Skip to content

Commit 12a7be7

Browse files
committed
[server] Apply BBOX inside And using filterRect
In case of a WFS GetFeature request, if BBOX is not a direct child of the Filter element, it is applyed through an intersects_bbox function in the QgsFeatureRequest filterExpression. This is not compiled by providers like PostgreSQL, causing the whole filter to be interpreted on QGIS side. When interpreted on QGIS side, the srsname given in the request is not handled properly as geom_from_gml return a geometry object, projection agnostic. This result in a very long request returning no results. This is a workaround for this performance and srs issue in the case the BBOX is direct child of an And operator, itself at first level in Filter element. This is a bug fix and huge optimisation for the case we have a And with a BBOX and another condition.
1 parent e6c9498 commit 12a7be7

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

src/server/services/wfs/qgswfsutils.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,47 @@ namespace QgsWfs
153153
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
154154
return request;
155155
}
156+
// Apply BBOX through filterRect even inside an And to use spatial index
157+
else if ( filterElem.firstChildElement().tagName() == QLatin1String( "And" ) &&
158+
!filterElem.firstChildElement().firstChildElement( QLatin1String( "BBOX" ) ).isNull() )
159+
{
160+
QDomElement childElem = filterElem.firstChildElement().firstChildElement();
161+
while ( !childElem.isNull() )
162+
{
163+
QDomElement childFilterElement = filterElem.ownerDocument().createElement( QLatin1String( "Filter" ) );
164+
childFilterElement.appendChild( childElem.cloneNode( true ) );
165+
QgsFeatureRequest childRequest = parseFilterElement( typeName, childFilterElement );
166+
if ( childElem.tagName() == QLatin1String( "BBOX" ) )
167+
{
168+
if ( request.filterRect().isEmpty() )
169+
{
170+
request.setFilterRect( childRequest.filterRect() );
171+
}
172+
else
173+
{
174+
request.setFilterRect( request.filterRect().intersect( &childRequest.filterRect() ) );
175+
}
176+
}
177+
else
178+
{
179+
if ( !request.filterExpression() )
180+
{
181+
request.setFilterExpression( childRequest.filterExpression()->expression() );
182+
}
183+
else
184+
{
185+
QgsExpressionNode *opLeft = request.filterExpression()->rootNode()->clone();
186+
QgsExpressionNode *opRight = childRequest.filterExpression()->rootNode()->clone();
187+
std::unique_ptr<QgsExpressionNodeBinaryOperator> node = qgis::make_unique<QgsExpressionNodeBinaryOperator>( QgsExpressionNodeBinaryOperator::boAnd, opLeft, opRight );
188+
QgsExpression expr( node->dump() );
189+
request.setFilterExpression( expr );
190+
}
191+
}
192+
childElem = childElem.nextSiblingElement();
193+
}
194+
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
195+
return request;
196+
}
156197
else
157198
{
158199
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );

tests/src/python/test_qgsserver_wfs.py

+27
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,33 @@ def test_getfeature_post(self):
252252
"""
253253
tests.append(('sortby_post', sortTemplate.format("")))
254254

255+
andBboxTemplate = """<?xml version="1.0" encoding="UTF-8"?>
256+
<wfs:GetFeature service="WFS" version="1.0.0" {} xmlns:wfs="http://www.opengis.net/wfs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
257+
<wfs:Query typeName="testlayer" srsName="EPSG:3857" xmlns:feature="http://www.qgis.org/gml">
258+
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
259+
<ogc:And>
260+
<ogc:BBOX>
261+
<ogc:PropertyName>geometry</ogc:PropertyName>
262+
<gml:Envelope xmlns:gml="http://www.opengis.net/gml">
263+
<gml:lowerCorner>890555.92634619 5465442.18332275</gml:lowerCorner>
264+
<gml:upperCorner>1001875.41713946 5621521.48619207</gml:upperCorner>
265+
</gml:Envelope>
266+
</ogc:BBOX>
267+
<ogc:PropertyIsGreaterThan>
268+
<ogc:PropertyName>id</ogc:PropertyName>
269+
<ogc:Literal>1</ogc:Literal>
270+
</ogc:PropertyIsGreaterThan>
271+
<ogc:PropertyIsLessThan>
272+
<ogc:PropertyName>id</ogc:PropertyName>
273+
<ogc:Literal>3</ogc:Literal>
274+
</ogc:PropertyIsLessThan>
275+
</ogc:And>
276+
</ogc:Filter>
277+
</wfs:Query>
278+
</wfs:GetFeature>
279+
"""
280+
tests.append(('bbox_inside_and_post', andBboxTemplate.format("")))
281+
255282
for id, req in tests:
256283
self.wfs_getfeature_post_compare(id, req)
257284

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Content-Type: text/xml; subtype=gml/2.1.2; charset=utf-8
2+
3+
<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml ?MAP=/home/dhont/3liz_dev/QGIS/qgis_rldhont/tests/testdata/qgis_server/test_project_wfs.qgs&amp;SRSNAME=EPSG:3857&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=testlayer&amp;OUTPUTFORMAT=XMLSCHEMA">
4+
<gml:boundedBy>
5+
<gml:Box srsName="EPSG:4326">
6+
<gml:coordinates cs="," ts=" ">8,44 9,45</gml:coordinates>
7+
</gml:Box>
8+
</gml:boundedBy>
9+
<gml:featureMember>
10+
<qgs:testlayer fid="testlayer.1">
11+
<gml:boundedBy>
12+
<gml:Box srsName="EPSG:3857">
13+
<gml:coordinates cs="," ts=" ">913214.67407005,5606017.87425818 913214.67407005,5606017.87425818</gml:coordinates>
14+
</gml:Box>
15+
</gml:boundedBy>
16+
<qgs:geometry>
17+
<Point xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
18+
<coordinates xmlns="http://www.opengis.net/gml" cs="," ts=" ">913214.67407005,5606017.87425818</coordinates>
19+
</Point>
20+
</qgs:geometry>
21+
<qgs:id>2</qgs:id>
22+
<qgs:name>two</qgs:name>
23+
<qgs:utf8nameè>two àò</qgs:utf8nameè>
24+
</qgs:testlayer>
25+
</gml:featureMember>
26+
</wfs:FeatureCollection>

0 commit comments

Comments
 (0)