Skip to content

Commit bf3e96c

Browse files
committedNov 1, 2018
[BUGFIX] [OGR provider] Make filter by id(s) requests work again on OSM datasets (fixes #20308)
1 parent 0d73805 commit bf3e96c

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed
 

‎src/providers/ogr/qgsogrfeatureiterator.cpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,16 @@
4141

4242
QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
4343
: QgsAbstractFeatureIteratorFromSource<QgsOgrFeatureSource>( source, ownSource, request )
44-
, mFilterFids( mRequest.filterFids() )
45-
, mFilterFidsIt( mFilterFids.constBegin() )
4644
, mSharedDS( source->mSharedDS )
4745
, mFirstFieldIsFid( source->mFirstFieldIsFid )
4846
, mFieldsWithoutFid( source->mFieldsWithoutFid )
4947
{
48+
for ( const auto &id : mRequest.filterFids() )
49+
{
50+
mFilterFids.insert( id );
51+
}
52+
mFilterFidsIt = mFilterFids.begin();
53+
5054
// Since connection timeout for OGR connections is problematic and can lead to crashes, disable for now.
5155
mRequest.setTimeout( -1 );
5256
if ( mSharedDS )
@@ -235,7 +239,47 @@ bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature &fea
235239
{
236240
feature.setValid( false );
237241
gdal::ogr_feature_unique_ptr fet;
238-
fet.reset( OGR_L_GetFeature( mOgrLayer, FID_TO_NUMBER( id ) ) );
242+
243+
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,2,0)
244+
if ( !QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mSource->mDriverName ) )
245+
{
246+
OGRLayerH nextFeatureBelongingLayer;
247+
bool found = false;
248+
// First pass: try to read from the last feature, in the hope the dataset
249+
// returns them in increasing feature id number (and as we use a std::set
250+
// for mFilterFids, we get them in increasing number by the iterator)
251+
// Second pass: reset before reading
252+
for ( int passNumber = 0; passNumber < 2; passNumber++ )
253+
{
254+
while ( fet.reset( GDALDatasetGetNextFeature(
255+
mConn->ds, &nextFeatureBelongingLayer, nullptr, nullptr, nullptr ) ), fet )
256+
{
257+
if ( nextFeatureBelongingLayer == mOgrLayer )
258+
{
259+
if ( OGR_F_GetFID( fet.get() ) == FID_TO_NUMBER( id ) )
260+
{
261+
found = true;
262+
break;
263+
}
264+
}
265+
}
266+
if ( found || passNumber == 1 )
267+
{
268+
break;
269+
}
270+
GDALDatasetResetReading( mConn->ds );
271+
}
272+
273+
if ( !found )
274+
{
275+
return false;
276+
}
277+
}
278+
else
279+
#endif
280+
{
281+
fet.reset( OGR_L_GetFeature( mOgrLayer, FID_TO_NUMBER( id ) ) );
282+
}
239283

240284
if ( !fet )
241285
{
@@ -281,10 +325,10 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature &feature )
281325
}
282326
else if ( mRequest.filterType() == QgsFeatureRequest::FilterFids )
283327
{
284-
while ( mFilterFidsIt != mFilterFids.constEnd() )
328+
while ( mFilterFidsIt != mFilterFids.end() )
285329
{
286330
QgsFeatureId nextId = *mFilterFidsIt;
287-
mFilterFidsIt++;
331+
++mFilterFidsIt;
288332

289333
if ( fetchFeatureWithId( nextId, feature ) )
290334
return true;
@@ -351,7 +395,7 @@ bool QgsOgrFeatureIterator::rewind()
351395

352396
resetReading();
353397

354-
mFilterFidsIt = mFilterFids.constBegin();
398+
mFilterFidsIt = mFilterFids.begin();
355399

356400
return true;
357401
}

‎src/providers/ogr/qgsogrfeatureiterator.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <ogr_api.h>
2323

2424
#include <memory>
25+
#include <set>
2526

2627
class QgsOgrFeatureIterator;
2728
class QgsOgrProvider;
@@ -86,8 +87,9 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
8687
bool mFetchGeometry = false;
8788

8889
bool mExpressionCompiled = false;
89-
QgsFeatureIds mFilterFids;
90-
QgsFeatureIds::const_iterator mFilterFidsIt;
90+
// use std::set to get sorted ids (needed for efficient QgsFeatureRequest::FilterFids requests on OSM datasource)
91+
std::set<QgsFeatureId> mFilterFids;
92+
std::set<QgsFeatureId>::iterator mFilterFidsIt;
9193

9294
QgsRectangle mFilterRect;
9395
QgsCoordinateTransform mTransform;

‎tests/src/python/test_provider_ogr.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,32 @@ def testOSM(self):
463463
iter_multipolygons = vl_multipolygons.getFeatures(QgsFeatureRequest())
464464
self.assertTrue(iter_multipolygons.nextFeature(f))
465465

466+
# Test filter by id (#20308)
467+
f = next(vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFid(8)))
468+
self.assertTrue(f.isValid())
469+
self.assertEqual(f.id(), 8)
470+
471+
f = next(vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFid(1)))
472+
self.assertTrue(f.isValid())
473+
self.assertEqual(f.id(), 1)
474+
475+
f = next(vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFid(5)))
476+
self.assertTrue(f.isValid())
477+
self.assertEqual(f.id(), 5)
478+
479+
# 6 doesn't exist
480+
it = vl_multipolygons.getFeatures(QgsFeatureRequest().setFilterFids([1, 5, 6, 8]))
481+
f = next(it)
482+
self.assertTrue(f.isValid())
483+
self.assertEqual(f.id(), 1)
484+
f = next(it)
485+
self.assertTrue(f.isValid())
486+
self.assertEqual(f.id(), 5)
487+
f = next(it)
488+
self.assertTrue(f.isValid())
489+
self.assertEqual(f.id(), 8)
490+
del it
491+
466492

467493
if __name__ == '__main__':
468494
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.