From 5b15595885293a39d6729ae5301101fa37217e57 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 5 Mar 2025 11:32:53 +0100 Subject: [PATCH] WFS: fix crash with GetFeatureCount() and client-side filters Fixes #11920 --- autotest/ogr/ogr_wfs.py | 81 +++++++++++++++++++++++++++++ ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp | 13 +++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/autotest/ogr/ogr_wfs.py b/autotest/ogr/ogr_wfs.py index 8bf514f18ac0..9fb2381fab48 100755 --- a/autotest/ogr/ogr_wfs.py +++ b/autotest/ogr/ogr_wfs.py @@ -5204,3 +5204,84 @@ def test_ogr_wfs_vsimem_wfs200_supported_crs(): f = lyr.GetNextFeature() assert f is not None assert f.GetGeometryRef().ExportToWkt() == "POINT (2 49)" + + +############################################################################### +# Test GetFeatureCount() with client-side only filter + + +def test_ogr_wfs_get_feature_count_issue_11920(): + + getfeatures_response = """ + + + foo + 49 2 + + +""" + + with gdaltest.tempfile( + "/vsimem/test_ogr_wfs_get_feature_count_issue_11920?SERVICE=WFS&REQUEST=GetCapabilities", + """ + + + + results + hits + + + + + + foo:lyr + urn:ogc:def:crs:EPSG::4326 + + -10 40 + 15 50 + + + + +""", + ), gdaltest.tempfile( + "/vsimem/test_ogr_wfs_get_feature_count_issue_11920?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAME=foo:lyr", + """ + + + + + + + + + + + + + +""", + ), gdaltest.tempfile( + "/vsimem/test_ogr_wfs_get_feature_count_issue_11920?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=foo:lyr&COUNT=1", + getfeatures_response, + ), gdaltest.tempfile( + "/vsimem/test_ogr_wfs_get_feature_count_issue_11920?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=foo:lyr", + getfeatures_response, + ): + ds = ogr.Open("WFS:/vsimem/test_ogr_wfs_get_feature_count_issue_11920") + lyr = ds.GetLayer(0) + + # Use client-side filters + lyr.SetAttributeFilter("FID >= 0") + assert lyr.GetFeatureCount() == 1 + + lyr.SetAttributeFilter("FID < 0") + assert lyr.GetFeatureCount() == 0 diff --git a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp index 8c6bd9e25791..859b3a691912 100644 --- a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp +++ b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp @@ -1339,6 +1339,7 @@ OGRFeature *OGRWFSLayer::GetNextFeature() if (bGotApproximateLayerDefn) { poNewFeature->SetFrom(poSrcFeature); + poNewFeature->SetFID(poSrcFeature->GetFID()); /* Client-side attribute filtering. */ if (m_poAttrQuery != nullptr && osWFSWhere.empty() && @@ -1351,6 +1352,7 @@ OGRFeature *OGRWFSLayer::GetNextFeature() } else { + poNewFeature->SetFID(poSrcFeature->GetFID()); for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++) { @@ -1360,7 +1362,6 @@ OGRFeature *OGRWFSLayer::GetNextFeature() poNewFeature->SetStyleString(poSrcFeature->GetStyleString()); poNewFeature->SetGeometryDirectly(poSrcFeature->StealGeometry()); } - poNewFeature->SetFID(poSrcFeature->GetFID()); poGeom = poNewFeature->GetGeometryRef(); /* FIXME? I don't really know what we should do with WFS 1.1.0 */ @@ -1724,7 +1725,7 @@ GIntBig OGRWFSLayer::GetFeatureCount(int bForce) if (nFeatures >= 0) return nFeatures; - if (TestCapability(OLCFastFeatureCount)) + if (poBaseLayer && TestCapability(OLCFastFeatureCount)) return poBaseLayer->GetFeatureCount(bForce); if ((m_poAttrQuery == nullptr || !osWFSWhere.empty()) && @@ -1739,14 +1740,18 @@ GIntBig OGRWFSLayer::GetFeatureCount(int bForce) /* feature, and then query again OLCFastFeatureCount on the */ /* base layer. In case the WFS response would contain the */ /* number of features */ - if (poBaseLayer == nullptr) + if (poBaseLayer == nullptr && + (m_poAttrQuery == nullptr || !osWFSWhere.empty())) { ResetReading(); OGRFeature *poFeature = GetNextFeature(); delete poFeature; ResetReading(); - if (TestCapability(OLCFastFeatureCount)) + if (nFeatures >= 0) + return nFeatures; + + if (poBaseLayer && TestCapability(OLCFastFeatureCount)) return poBaseLayer->GetFeatureCount(bForce); }