Skip to content

Commit 1f02fd4

Browse files
committed
Implement provider side FilterFids iterators for OGR provider
Makes some operations with OGR sources magnitudes faster, ie zoom to 20 selected features in a 4 million point dataset: before: 14 seconds of blocked gui after: instant Win!
1 parent 00a8fea commit 1f02fd4

File tree

3 files changed

+64
-13
lines changed

3 files changed

+64
-13
lines changed

src/providers/ogr/qgsogrfeatureiterator.cpp

+38-11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
4343
, mSubsetStringSet( false )
4444
, mFetchGeometry( false )
4545
, mExpressionCompiled( false )
46+
, mFilterFids( mRequest.filterFids() )
47+
, mFilterFidsIt( mFilterFids.constBegin() )
4648
{
4749
mConn = QgsOgrConnPool::instance()->acquireConnection( mSource->mProvider->dataSourceUri() );
4850
if ( !mConn->ds )
@@ -166,6 +168,22 @@ bool QgsOgrFeatureIterator::nextFeatureFilterExpression( QgsFeature& f )
166168
return fetchFeature( f );
167169
}
168170

171+
bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature& feature ) const
172+
{
173+
feature.setValid( false );
174+
OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( id ) );
175+
if ( !fet )
176+
{
177+
return false;
178+
}
179+
180+
if ( readFeature( fet, feature ) )
181+
OGR_F_Destroy( fet );
182+
183+
feature.setValid( true );
184+
return true;
185+
}
186+
169187
bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
170188
{
171189
feature.setValid( false );
@@ -175,19 +193,26 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
175193

176194
if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
177195
{
178-
OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( mRequest.filterFid() ) );
179-
if ( !fet )
196+
bool result = fetchFeatureWithId( mRequest.filterFid(), feature );
197+
close(); // the feature has been read or was not found: we have finished here
198+
return result;
199+
}
200+
else if ( mRequest.filterType() == QgsFeatureRequest::FilterFids )
201+
{
202+
if ( mFilterFidsIt == mFilterFids.constEnd() )
180203
{
181204
close();
182205
return false;
183206
}
184-
185-
if ( readFeature( fet, feature ) )
186-
OGR_F_Destroy( fet );
187-
188-
feature.setValid( true );
189-
close(); // the feature has been read: we have finished here
190-
return true;
207+
else
208+
{
209+
QgsFeatureId nextId = *mFilterFidsIt;
210+
mFilterFidsIt++;
211+
bool result = fetchFeatureWithId( nextId, feature );
212+
if ( !result )
213+
close();
214+
return result;
215+
}
191216
}
192217

193218
OGRFeatureH fet;
@@ -220,6 +245,8 @@ bool QgsOgrFeatureIterator::rewind()
220245

221246
OGR_L_ResetReading( ogrLayer );
222247

248+
mFilterFidsIt = mFilterFids.constBegin();
249+
223250
return true;
224251
}
225252

@@ -246,7 +273,7 @@ bool QgsOgrFeatureIterator::close()
246273
}
247274

248275

249-
void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex )
276+
void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) const
250277
{
251278
if ( mSource->mFirstFieldIsFid && attindex == 0 )
252279
{
@@ -264,7 +291,7 @@ void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature
264291
}
265292

266293

267-
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )
294+
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) const
268295
{
269296
feature.setFeatureId( OGR_F_GetFID( fet ) );
270297
feature.initAttributes( mSource->mFields.count() );

src/providers/ogr/qgsogrfeatureiterator.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
6969
//! fetch next feature filter expression
7070
bool nextFeatureFilterExpression( QgsFeature& f ) override;
7171

72-
bool readFeature( OGRFeatureH fet, QgsFeature& feature );
72+
bool readFeature( OGRFeatureH fet, QgsFeature& feature ) const;
7373

7474
//! Get an attribute associated with a feature
75-
void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex );
75+
void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) const;
7676

7777
bool mFeatureFetched;
7878

@@ -86,6 +86,10 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
8686

8787
private:
8888
bool mExpressionCompiled;
89+
QgsFeatureIds mFilterFids;
90+
QgsFeatureIds::const_iterator mFilterFidsIt;
91+
92+
bool fetchFeatureWithId( QgsFeatureId id, QgsFeature& feature ) const;
8993
};
9094

9195
#endif // QGSOGRFEATUREITERATOR_H

tests/src/python/providertestbase.py

+20
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,26 @@ def testGetFeaturesFidsTests(self):
387387
expected = set([])
388388
assert result == expected, 'Expected {} and got {} when testing for feature IDs filter'.format(expected, result)
389389

390+
# Rewind mid-way
391+
request = QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]])
392+
feature_it = self.provider.getFeatures(request)
393+
feature = QgsFeature()
394+
feature.setValid(True)
395+
self.assertTrue(feature_it.nextFeature(feature))
396+
self.assertEqual(feature.id(), fids[1])
397+
self.assertTrue(feature.isValid())
398+
# rewind
399+
self.assertTrue(feature_it.rewind())
400+
self.assertTrue(feature_it.nextFeature(feature))
401+
self.assertEqual(feature.id(), fids[1])
402+
self.assertTrue(feature.isValid())
403+
# grab all features
404+
self.assertTrue(feature_it.nextFeature(feature))
405+
self.assertTrue(feature_it.nextFeature(feature))
406+
# none left
407+
self.assertFalse(feature_it.nextFeature(feature))
408+
self.assertFalse(feature.isValid())
409+
390410
def testGetFeaturesFilterRectTests(self):
391411
extent = QgsRectangle(-70, 67, -60, 80)
392412
request = QgsFeatureRequest().setFilterRect(extent)

0 commit comments

Comments
 (0)