Skip to content

Commit 485cd80

Browse files
authored
Merge pull request #5695 from pblottiere/bugfix_virtuallayer_218
[backport][bugfix] Fixes #16798 FilterFid feature requests with virtual layers
2 parents 193ead7 + 4693f1a commit 485cd80

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
3737
QString tableName = mSource->provider()->mTableName;
3838

3939
QStringList wheres;
40+
QString offset;
4041
QString subset = mSource->provider()->mSubset;
4142
if ( !subset.isNull() )
4243
{
@@ -76,6 +77,17 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
7677
values += ")";
7778
wheres << values;
7879
}
80+
else if ( mDefinition.uid().isNull() && request.filterType() == QgsFeatureRequest::FilterFid )
81+
{
82+
if ( request.filterFid() >= 0 )
83+
{
84+
offset = QString( " LIMIT 1 OFFSET %1" ).arg( request.filterFid() );
85+
}
86+
else // never return a feature if the id is negative
87+
{
88+
offset = QString( " LIMIT 0" );
89+
}
90+
}
7991

8092
mFields = mSource->provider()->fields();
8193
if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
@@ -111,7 +123,15 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
111123
}
112124
else
113125
{
114-
columns = "0";
126+
columns = QString( "0" );
127+
if ( request.filterType() == QgsFeatureRequest::FilterFid )
128+
{
129+
columns = QString::number( request.filterFid() );
130+
}
131+
else
132+
{
133+
columns = QString( "0" );
134+
}
115135
}
116136
Q_FOREACH ( int i, mAttributes )
117137
{
@@ -134,6 +154,11 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
134154
mSqlQuery += " WHERE " + wheres.join( " AND " );
135155
}
136156

157+
if ( !offset.isEmpty() )
158+
{
159+
mSqlQuery += offset;
160+
}
161+
137162
mQuery.reset( new Sqlite::Query( mSqlite, mSqlQuery ) );
138163

139164
mFid = 0;
@@ -191,7 +216,8 @@ bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature& feature )
191216

192217
feature.setFields( mFields, /* init */ true );
193218

194-
if ( mDefinition.uid().isNull() )
219+
if ( mDefinition.uid().isNull() &&
220+
mRequest.filterType() != QgsFeatureRequest::FilterFid )
195221
{
196222
// no id column => autoincrement
197223
feature.setFeatureId( mFid++ );

tests/src/python/test_provider_virtual.py

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

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

0 commit comments

Comments
 (0)