Skip to content

Commit 9f0985f

Browse files
authored
Merge pull request #5554 from pblottiere/bugfix_virtuallayer
[bugfix] Fixes #16798 FilterFid feature requests with virtual layers
2 parents bd30e12 + b5317c5 commit 9f0985f

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
6363
QString tableName = mSource->mTableName;
6464

6565
QStringList wheres;
66+
QString offset;
6667
QString subset = mSource->mSubset;
6768
if ( !subset.isNull() )
6869
{
@@ -105,6 +106,16 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
105106
wheres << values;
106107
}
107108
}
109+
else
110+
{
111+
if ( request.filterType() == QgsFeatureRequest::FilterFid )
112+
{
113+
if ( request.filterFid() >= 0 )
114+
offset = QStringLiteral( " LIMIT 1 OFFSET %1" ).arg( request.filterFid() );
115+
else // never return a feature if the id is negative
116+
offset = QStringLiteral( " LIMIT 0" );
117+
}
118+
}
108119

109120
if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
110121
{
@@ -150,7 +161,14 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
150161
}
151162
else
152163
{
153-
columns = QStringLiteral( "0" );
164+
if ( request.filterType() == QgsFeatureRequest::FilterFid )
165+
{
166+
columns = QString::number( request.filterFid() );
167+
}
168+
else
169+
{
170+
columns = QStringLiteral( "0" );
171+
}
154172
}
155173
Q_FOREACH ( int i, mAttributes )
156174
{
@@ -173,6 +191,11 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
173191
mSqlQuery += " WHERE " + wheres.join( QStringLiteral( " AND " ) );
174192
}
175193

194+
if ( !offset.isEmpty() )
195+
{
196+
mSqlQuery += offset;
197+
}
198+
176199
mQuery.reset( new Sqlite::Query( mSource->mSqlite, mSqlQuery ) );
177200

178201
mFid = 0;
@@ -230,7 +253,8 @@ bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature &feature )
230253

231254
feature.setFields( mSource->mFields, /* init */ true );
232255

233-
if ( mSource->mDefinition.uid().isNull() )
256+
if ( mSource->mDefinition.uid().isNull() &&
257+
mRequest.filterType() != QgsFeatureRequest::FilterFid )
234258
{
235259
// no id column => autoincrement
236260
feature.setId( mFid++ );

tests/src/python/test_provider_virtual.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,46 @@ def tearDown(self):
8585
"""Run after each test."""
8686
pass
8787

88+
def test_filterfid_crossjoin(self):
89+
l0 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france_parts", "ogr")
90+
self.assertTrue(l0.isValid())
91+
QgsProject.instance().addMapLayer(l0)
92+
93+
l1 = QgsVectorLayer(os.path.join(self.testDataDir, "points.shp"), "points", "ogr")
94+
self.assertTrue(l1.isValid())
95+
QgsProject.instance().addMapLayer(l1)
96+
97+
# cross join
98+
query = toPercent("SELECT * FROM france_parts,points")
99+
vl = QgsVectorLayer("?query=%s" % query, "tt", "virtual")
100+
101+
self.assertEqual(vl.featureCount(), l0.featureCount() * l1.featureCount())
102+
103+
# test with FilterFid requests
104+
f = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(0)))
105+
idx = f.fields().indexOf('Class')
106+
self.assertEqual(f.id(), 0)
107+
self.assertEqual(f.attributes()[idx], 'Jet')
108+
109+
f = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(5)))
110+
self.assertEqual(f.id(), 5)
111+
self.assertEqual(f.attributes()[idx], 'Biplane')
112+
113+
# test with FilterFid requests
114+
fit = vl.getFeatures(QgsFeatureRequest().setFilterFids([0, 3, 5]))
115+
116+
f = next(fit)
117+
self.assertEqual(f.id(), 0)
118+
self.assertEqual(f.attributes()[idx], 'Jet')
119+
120+
f = next(fit)
121+
self.assertEqual(f.id(), 3)
122+
self.assertEqual(f.attributes()[idx], 'Jet')
123+
124+
f = next(fit)
125+
self.assertEqual(f.id(), 5)
126+
self.assertEqual(f.attributes()[idx], 'Biplane')
127+
88128
def test_CsvNoGeometry(self):
89129
l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", QgsVectorLayer.LayerOptions(False))
90130
self.assertEqual(l1.isValid(), True)

0 commit comments

Comments
 (0)