Skip to content

Commit b07c334

Browse files
committedJun 5, 2018
[server] Proper convertion of literals in Filters
Convert OGC Filter's literals accordings to field type. This can have a huge impact on performance in some cases. For example for a filter like "num_char" = '+2' converted to "num_char" = 2, this result with PostgreSQL provider in a fallback to client side evaluation for the whole filter, including the bbox if present.
1 parent facf7a2 commit b07c334

14 files changed

+126
-62
lines changed
 

‎python/core/auto_generated/qgsogcutils.sip.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ Exports the rectangle to GML3 Envelope
128128
Parse XML with OGC fill into QColor
129129
%End
130130

131-
static QgsExpression *expressionFromOgcFilter( const QDomElement &element ) /Factory/;
131+
static QgsExpression *expressionFromOgcFilter( const QDomElement &element, QgsVectorLayer *layer = 0 ) /Factory/;
132132
%Docstring
133133
Parse XML with OGC filter into QGIS expression
134134
%End

‎src/core/qgsogcutils.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ QColor QgsOgcUtils::colorFromOgcFill( const QDomElement &fillElement )
15981598
}
15991599

16001600

1601-
QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element )
1601+
QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element, QgsVectorLayer *layer )
16021602
{
16031603
if ( element.isNull() || !element.hasChildNodes() )
16041604
return nullptr;
@@ -1619,7 +1619,7 @@ QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element
16191619
while ( !childElem.isNull() )
16201620
{
16211621
QString errorMsg;
1622-
QgsExpressionNode *node = nodeFromOgcFilter( childElem, errorMsg );
1622+
QgsExpressionNode *node = nodeFromOgcFilter( childElem, errorMsg, layer );
16231623
if ( !node )
16241624
{
16251625
// invalid expression, parser error
@@ -1702,15 +1702,15 @@ static bool isSpatialOperator( const QString &tagName )
17021702

17031703

17041704

1705-
QgsExpressionNode *QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString &errorMessage )
1705+
QgsExpressionNode *QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
17061706
{
17071707
if ( element.isNull() )
17081708
return nullptr;
17091709

17101710
// check for binary operators
17111711
if ( isBinaryOperator( element.tagName() ) )
17121712
{
1713-
return nodeBinaryOperatorFromOgcFilter( element, errorMessage );
1713+
return nodeBinaryOperatorFromOgcFilter( element, errorMessage, layer );
17141714
}
17151715

17161716
// check for spatial operators
@@ -1731,7 +1731,7 @@ QgsExpressionNode *QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString
17311731
}
17321732
else if ( element.tagName() == QLatin1String( "Literal" ) )
17331733
{
1734-
return nodeLiteralFromOgcFilter( element, errorMessage );
1734+
return nodeLiteralFromOgcFilter( element, errorMessage, layer );
17351735
}
17361736
else if ( element.tagName() == QLatin1String( "Function" ) )
17371737
{
@@ -1752,7 +1752,7 @@ QgsExpressionNode *QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString
17521752

17531753

17541754

1755-
QgsExpressionNodeBinaryOperator *QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage )
1755+
QgsExpressionNodeBinaryOperator *QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
17561756
{
17571757
if ( element.isNull() )
17581758
return nullptr;
@@ -1771,7 +1771,7 @@ QgsExpressionNodeBinaryOperator *QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( Q
17711771
}
17721772

17731773
QDomElement operandElem = element.firstChildElement();
1774-
QgsExpressionNode *expr = nodeFromOgcFilter( operandElem, errorMessage ), *leftOp = expr;
1774+
QgsExpressionNode *expr = nodeFromOgcFilter( operandElem, errorMessage, layer ), *leftOp = expr;
17751775
if ( !expr )
17761776
{
17771777
if ( errorMessage.isEmpty() )
@@ -1781,7 +1781,7 @@ QgsExpressionNodeBinaryOperator *QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( Q
17811781

17821782
for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
17831783
{
1784-
QgsExpressionNode *opRight = nodeFromOgcFilter( operandElem, errorMessage );
1784+
QgsExpressionNode *opRight = nodeFromOgcFilter( operandElem, errorMessage, layer );
17851785
if ( !opRight )
17861786
{
17871787
if ( errorMessage.isEmpty() )
@@ -1960,7 +1960,7 @@ QgsExpressionNodeFunction *QgsOgcUtils::nodeFunctionFromOgcFilter( QDomElement &
19601960

19611961

19621962

1963-
QgsExpressionNode *QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage )
1963+
QgsExpressionNode *QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
19641964
{
19651965
if ( element.isNull() || element.tagName() != QLatin1String( "Literal" ) )
19661966
{
@@ -1980,7 +1980,7 @@ QgsExpressionNode *QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element,
19801980
{
19811981
// found a element node (e.g. PropertyName), convert it
19821982
QDomElement operandElem = childNode.toElement();
1983-
operand = nodeFromOgcFilter( operandElem, errorMessage );
1983+
operand = nodeFromOgcFilter( operandElem, errorMessage, layer );
19841984
if ( !operand )
19851985
{
19861986
delete root;
@@ -1994,12 +1994,36 @@ QgsExpressionNode *QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element,
19941994
// probably a text/CDATA node
19951995
QVariant value = childNode.nodeValue();
19961996

1997-
// try to convert the node content to number if possible,
1998-
// otherwise let's use it as string
1999-
bool ok;
2000-
double d = value.toDouble( &ok );
2001-
if ( ok )
2002-
value = d;
1997+
bool converted = false;
1998+
1999+
// try to convert the node content to corresponding field type if possible
2000+
if ( layer != nullptr )
2001+
{
2002+
QDomElement propertyNameElement = element.previousSiblingElement( QLatin1String( "PropertyName" ) );
2003+
if ( propertyNameElement.isNull() || propertyNameElement.tagName() != QLatin1String( "PropertyName" ) )
2004+
{
2005+
propertyNameElement = element.nextSiblingElement( QLatin1String( "PropertyName" ) );
2006+
}
2007+
if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == QLatin1String( "PropertyName" ) )
2008+
{
2009+
int fieldIndex = layer->fields().indexOf( propertyNameElement.firstChild().nodeValue() );
2010+
if ( fieldIndex != -1 )
2011+
{
2012+
QgsField field = layer->fields().field( propertyNameElement.firstChild().nodeValue() );
2013+
field.convertCompatible( value );
2014+
converted = true;
2015+
}
2016+
}
2017+
}
2018+
if ( !converted )
2019+
{
2020+
// try to convert the node content to number if possible,
2021+
// otherwise let's use it as string
2022+
bool ok;
2023+
double d = value.toDouble( &ok );
2024+
if ( ok )
2025+
value = d;
2026+
}
20032027

20042028
operand = new QgsExpressionNodeLiteral( value );
20052029
if ( !operand )

‎src/core/qgsogcutils.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class QgsRectangle;
3737
#include "qgsexpressionnode.h"
3838
#include "qgsexpressionnodeimpl.h"
3939
#include "qgssqlstatement.h"
40+
#include "qgsvectorlayer.h"
4041

4142
/**
4243
* \ingroup core
@@ -140,7 +141,7 @@ class CORE_EXPORT QgsOgcUtils
140141
static QColor colorFromOgcFill( const QDomElement &fillElement );
141142

142143
//! Parse XML with OGC filter into QGIS expression
143-
static QgsExpression *expressionFromOgcFilter( const QDomElement &element ) SIP_FACTORY;
144+
static QgsExpression *expressionFromOgcFilter( const QDomElement &element, QgsVectorLayer *layer = nullptr ) SIP_FACTORY;
144145

145146
/**
146147
* Creates OGC filter XML element. Supports minimum standard filter
@@ -298,17 +299,17 @@ class CORE_EXPORT QgsOgcUtils
298299
static QDomElement createGMLPositions( const QgsPolylineXY &points, QDomDocument &doc );
299300

300301
//! handle a generic sub-expression
301-
static QgsExpressionNode *nodeFromOgcFilter( QDomElement &element, QString &errorMessage );
302+
static QgsExpressionNode *nodeFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer = nullptr );
302303
//! handle a generic binary operator
303-
static QgsExpressionNodeBinaryOperator *nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage );
304+
static QgsExpressionNodeBinaryOperator *nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer = nullptr );
304305
//! handles various spatial operation tags (\verbatim <Intersects> \endverbatim, \verbatim <Touches> \endverbatim etc.)
305306
static QgsExpressionNodeFunction *nodeSpatialOperatorFromOgcFilter( QDomElement &element, QString &errorMessage );
306307
//! handle \verbatim <Not> \endverbatim tag
307308
static QgsExpressionNodeUnaryOperator *nodeNotFromOgcFilter( QDomElement &element, QString &errorMessage );
308309
//! handles \verbatim <Function> \endverbatim tag
309310
static QgsExpressionNodeFunction *nodeFunctionFromOgcFilter( QDomElement &element, QString &errorMessage );
310311
//! handles \verbatim <Literal> \endverbatim tag
311-
static QgsExpressionNode *nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage );
312+
static QgsExpressionNode *nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer = nullptr );
312313
//! handles \verbatim <PropertyName> \endverbatim tag
313314
static QgsExpressionNodeColumnRef *nodeColumnRefFromOgcFilter( QDomElement &element, QString &errorMessage );
314315
//! handles \verbatim <PropertyIsBetween> \endverbatim tag

‎src/server/qgsserverprojectutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "qgis_server.h"
2222
#include "qgsproject.h"
23+
#include "qgsvectorlayer.h"
2324

2425
#ifdef SIP_RUN
2526
% ModuleHeaderCode

‎src/server/services/wfs/qgswfsdescribefeaturetype.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,7 @@ namespace QgsWfs
139139
continue;
140140
}
141141

142-
QString name = layer->name();
143-
if ( !layer->shortName().isEmpty() )
144-
name = layer->shortName();
145-
name = name.replace( ' ', '_' );
142+
QString name = layerTypeName( layer );
146143

147144
if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) )
148145
{
@@ -180,10 +177,7 @@ namespace QgsWfs
180177
return;
181178
}
182179

183-
QString typeName = layer->name();
184-
if ( !layer->shortName().isEmpty() )
185-
typeName = layer->shortName();
186-
typeName = typeName.replace( ' ', '_' );
180+
QString typeName = layerTypeName( layer );
187181

188182
//xsd:element
189183
QDomElement elementElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );

‎src/server/services/wfs/qgswfsgetcapabilities.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,11 +438,7 @@ namespace QgsWfs
438438

439439
//create Name
440440
QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) );
441-
QString typeName = layer->name();
442-
if ( !layer->shortName().isEmpty() )
443-
typeName = layer->shortName();
444-
typeName = typeName.replace( QLatin1String( " " ), QLatin1String( "_" ) );
445-
QDomText nameText = doc.createTextNode( typeName );
441+
QDomText nameText = doc.createTextNode( layerTypeName( layer ) );
446442
nameElem.appendChild( nameText );
447443
layerElem.appendChild( nameElem );
448444

‎src/server/services/wfs/qgswfsgetfeature.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ namespace QgsWfs
101101
if ( doc.setContent( mRequestParameters.value( QStringLiteral( "REQUEST_BODY" ) ), true, &errorMsg ) )
102102
{
103103
QDomElement docElem = doc.documentElement();
104-
aRequest = parseGetFeatureRequestBody( docElem );
104+
aRequest = parseGetFeatureRequestBody( docElem, project );
105105
}
106106
else
107107
{
108-
aRequest = parseGetFeatureParameters();
108+
aRequest = parseGetFeatureParameters( project );
109109
}
110110

111111
// store typeName
@@ -141,10 +141,7 @@ namespace QgsWfs
141141
continue;
142142
}
143143

144-
QString name = layer->name();
145-
if ( !layer->shortName().isEmpty() )
146-
name = layer->shortName();
147-
name = name.replace( ' ', '_' );
144+
QString name = layerTypeName( layer );
148145

149146
if ( typeNameList.contains( name ) )
150147
{
@@ -433,7 +430,7 @@ namespace QgsWfs
433430

434431
}
435432

436-
getFeatureRequest parseGetFeatureParameters()
433+
getFeatureRequest parseGetFeatureParameters( const QgsProject *project )
437434
{
438435
getFeatureRequest request;
439436
request.maxFeatures = mWfsParameters.maxFeaturesAsInt();;
@@ -767,7 +764,7 @@ namespace QgsWfs
767764
}
768765

769766
QDomElement filterElem = filter.firstChildElement();
770-
query.featureRequest = parseFilterElement( query.typeName, filterElem );
767+
query.featureRequest = parseFilterElement( query.typeName, filterElem, project );
771768

772769
if ( filterIt != filterList.constEnd() )
773770
{
@@ -821,7 +818,7 @@ namespace QgsWfs
821818
return request;
822819
}
823820

824-
getFeatureRequest parseGetFeatureRequestBody( QDomElement &docElem )
821+
getFeatureRequest parseGetFeatureRequestBody( QDomElement &docElem, const QgsProject *project )
825822
{
826823
getFeatureRequest request;
827824
request.maxFeatures = mWfsParameters.maxFeaturesAsInt();;
@@ -833,7 +830,7 @@ namespace QgsWfs
833830
for ( int i = 0; i < queryNodes.size(); i++ )
834831
{
835832
queryElem = queryNodes.at( i ).toElement();
836-
getFeatureQuery query = parseQueryElement( queryElem );
833+
getFeatureQuery query = parseQueryElement( queryElem, project );
837834
request.queries.append( query );
838835
}
839836
return request;
@@ -887,7 +884,7 @@ namespace QgsWfs
887884
}
888885
}
889886

890-
getFeatureQuery parseQueryElement( QDomElement &queryElem )
887+
getFeatureQuery parseQueryElement( QDomElement &queryElem, const QgsProject *project )
891888
{
892889
QString typeName = queryElem.attribute( QStringLiteral( "typeName" ), QLatin1String( "" ) );
893890
if ( typeName.contains( ':' ) )
@@ -923,7 +920,7 @@ namespace QgsWfs
923920
}
924921
else if ( queryChildElem.tagName() == QLatin1String( "Filter" ) )
925922
{
926-
featureRequest = parseFilterElement( typeName, queryChildElem );
923+
featureRequest = parseFilterElement( typeName, queryChildElem, project );
927924
}
928925
else if ( queryChildElem.tagName() == QLatin1String( "SortBy" ) )
929926
{

‎src/server/services/wfs/qgswfsgetfeature.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ namespace QgsWfs
5858
/**
5959
* Transform Query element to getFeatureQuery
6060
*/
61-
getFeatureQuery parseQueryElement( QDomElement &queryElem );
61+
getFeatureQuery parseQueryElement( QDomElement &queryElem, const QgsProject *project = nullptr );
6262

6363
/**
6464
* Transform RequestBody root element to getFeatureRequest
6565
*/
66-
getFeatureRequest parseGetFeatureRequestBody( QDomElement &docElem );
66+
getFeatureRequest parseGetFeatureRequestBody( QDomElement &docElem, const QgsProject *project = nullptr );
6767

6868
/**
6969
* Transform parameters to getFeatureRequest
7070
*/
71-
getFeatureRequest parseGetFeatureParameters();
71+
getFeatureRequest parseGetFeatureParameters( const QgsProject *project = nullptr );
7272

7373
/**
7474
* Output WFS GetFeature response

‎src/server/services/wfs/qgswfstransaction.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,7 @@ namespace QgsWfs
259259
continue;
260260
}
261261

262-
QString name = layer->name();
263-
if ( !layer->shortName().isEmpty() )
264-
name = layer->shortName();
265-
name = name.replace( ' ', '_' );
262+
QString name = layerTypeName( layer );
266263

267264
if ( !typeNameList.contains( name ) )
268265
{

‎src/server/services/wfs/qgswfstransaction_1_0_0.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,7 @@ namespace QgsWfs
242242
continue;
243243
}
244244

245-
QString name = layer->name();
246-
if ( !layer->shortName().isEmpty() )
247-
name = layer->shortName();
248-
name = name.replace( ' ', '_' );
245+
QString name = layerTypeName( layer );
249246

250247
if ( !typeNameList.contains( name ) )
251248
{

‎src/server/services/wfs/qgswfsutils.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,39 @@ namespace QgsWfs
5858
return href;
5959
}
6060

61-
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem )
61+
QString layerTypeName( const QgsMapLayer *layer )
62+
{
63+
QString name = layer->name();
64+
if ( !layer->shortName().isEmpty() )
65+
name = layer->shortName();
66+
name = name.replace( ' ', '_' );
67+
return name;
68+
}
69+
70+
QgsVectorLayer *layerByTypeName( const QgsProject *project, const QString &typeName )
71+
{
72+
QStringList layerIds = QgsServerProjectUtils::wfsLayerIds( *project );
73+
for ( const QString &layerId : layerIds )
74+
{
75+
QgsMapLayer *layer = project->mapLayer( layerId );
76+
if ( !layer )
77+
{
78+
continue;
79+
}
80+
if ( layer->type() != QgsMapLayer::LayerType::VectorLayer )
81+
{
82+
continue;
83+
}
84+
85+
if ( layerTypeName( layer ) == typeName )
86+
{
87+
return qobject_cast<QgsVectorLayer *>( layer );
88+
}
89+
}
90+
return nullptr;
91+
}
92+
93+
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem, const QgsProject *project )
6294
{
6395
QgsFeatureRequest request;
6496

@@ -196,7 +228,12 @@ namespace QgsWfs
196228
}
197229
else
198230
{
199-
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );
231+
QgsVectorLayer *layer = nullptr;
232+
if ( project != nullptr )
233+
{
234+
layer = layerByTypeName( project, typeName );
235+
}
236+
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem, layer ) );
200237
if ( filter )
201238
{
202239
if ( filter->hasParserError() )

‎src/server/services/wfs/qgswfsutils.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,20 @@ namespace QgsWfs
4747
*/
4848
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project );
4949

50+
/**
51+
* Returns typename from vector layer
52+
*/
53+
QString layerTypeName( const QgsMapLayer *layer );
54+
55+
/**
56+
* Retrieve a layer by typename
57+
*/
58+
QgsVectorLayer *layerByTypeName( const QgsProject *project, const QString &typeName );
59+
5060
/**
5161
* Transform a Filter element to a feature request
5262
*/
53-
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem );
63+
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem, const QgsProject *project = nullptr );
5464

5565
// Define namespaces used in WFS documents
5666
const QString WFS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wfs" );

‎src/server/services/wms/qgswmsrenderer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2798,7 +2798,7 @@ namespace QgsWms
27982798
QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, filter ) );
27992799
}
28002800
QDomElement filterElem = filterXml.firstChildElement();
2801-
QScopedPointer<QgsExpression> expression( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );
2801+
QScopedPointer<QgsExpression> expression( QgsOgcUtils::expressionFromOgcFilter( filterElem, filteredLayer ) );
28022802
mFeatureFilter.setFilter( filteredLayer, *expression );
28032803
}
28042804
else

‎tests/src/core/testqgsogcutils.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <qgsgeometry.h>
2222
#include <qgsogcutils.h>
2323
#include "qgsapplication.h"
24+
#include "qgsvectorlayer.h"
2425

2526
/**
2627
* \ingroup UnitTests
@@ -368,6 +369,13 @@ void TestQgsOgcUtils::testExpressionFromOgcFilter_data()
368369
"</Intersects>"
369370
"</Filter>" )
370371
<< QStringLiteral( "intersects($geometry, geom_from_gml('<Point><coordinates>123,456</coordinates></Point>'))" );
372+
373+
QTest::newRow( "Literal conversion" ) << QString(
374+
"<Filter><PropertyIsEqualTo>"
375+
"<PropertyName>LITERAL</PropertyName>"
376+
"<Literal>+2</Literal>"
377+
"</PropertyIsEqualTo></Filter>" )
378+
<< QStringLiteral( "LITERAL = '+2'" );
371379
}
372380

373381
void TestQgsOgcUtils::testExpressionFromOgcFilter()
@@ -379,7 +387,9 @@ void TestQgsOgcUtils::testExpressionFromOgcFilter()
379387
QVERIFY( doc.setContent( xmlText, true ) );
380388
QDomElement rootElem = doc.documentElement();
381389

382-
std::shared_ptr<QgsExpression> expr( QgsOgcUtils::expressionFromOgcFilter( rootElem ) );
390+
QgsVectorLayer layer( "Point?crs=epsg:4326&field=LITERAL:string(20)", "temp", "memory" );
391+
392+
std::shared_ptr<QgsExpression> expr( QgsOgcUtils::expressionFromOgcFilter( rootElem, &layer ) );
383393
QVERIFY( expr.get() );
384394

385395
qDebug( "OGC XML : %s", xmlText.toAscii().data() );

0 commit comments

Comments
 (0)
Please sign in to comment.