Skip to content

Commit fcf3361

Browse files
committed
Merge branch 'bugfix_relationquote' of https://github.com/pblottiere/QGIS into pblottiere-bugfix_relationquote
2 parents 603168e + e306cb4 commit fcf3361

File tree

7 files changed

+89
-44
lines changed

7 files changed

+89
-44
lines changed

python/core/expression/qgsexpression.sip

+11
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,17 @@ return index of the function in Functions array
495495
:rtype: str
496496
%End
497497

498+
static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value );
499+
%Docstring
500+
Create an expression allowing to evaluate if a field is equal to a
501+
value. The value may be null.
502+
\param fieldName the name of the field
503+
\param value the value of the field
504+
:return: the expression to evaluate field equality
505+
.. versionadded:: 3.0
506+
:rtype: str
507+
%End
508+
498509
};
499510

500511

src/core/expression/qgsexpression.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,18 @@ QString QgsExpression::formatPreviewString( const QVariant &value )
836836
}
837837
}
838838

839+
QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value )
840+
{
841+
QString expr;
842+
843+
if ( value.isNull() )
844+
expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
845+
else
846+
expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
847+
848+
return expr;
849+
}
850+
839851
const QgsExpressionNode *QgsExpression::rootNode() const
840852
{
841853
return d->mRootNode;

src/core/expression/qgsexpression.h

+9
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,15 @@ class CORE_EXPORT QgsExpression
449449
*/
450450
static QString formatPreviewString( const QVariant &value );
451451

452+
/** Create an expression allowing to evaluate if a field is equal to a
453+
* value. The value may be null.
454+
* \param fieldName the name of the field
455+
* \param value the value of the field
456+
* \returns the expression to evaluate field equality
457+
* \since QGIS 3.0
458+
*/
459+
static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value );
460+
452461
private:
453462
void initGeomCalculator();
454463

src/core/qgsrelation.cpp

+2-26
Original file line numberDiff line numberDiff line change
@@ -170,23 +170,8 @@ QString QgsRelation::getRelatedFeaturesFilter( const QgsFeature &feature ) const
170170
{
171171
int referencingIdx = referencingLayer()->fields().indexFromName( fieldPair.referencingField() );
172172
QgsField referencingField = referencingLayer()->fields().at( referencingIdx );
173-
174173
QVariant val( feature.attribute( fieldPair.referencedField() ) );
175-
176-
if ( val.isNull() )
177-
{
178-
conditions << QStringLiteral( "\"%1\" IS NULL" ).arg( fieldPair.referencingField() );
179-
}
180-
else if ( referencingField.type() == QVariant::String )
181-
{
182-
// Use quotes
183-
conditions << QStringLiteral( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), val.toString() );
184-
}
185-
else
186-
{
187-
// No quotes
188-
conditions << QStringLiteral( "\"%1\" = %2" ).arg( fieldPair.referencingField(), val.toString() );
189-
}
174+
conditions << QgsExpression::createFieldEqualityExpression( fieldPair.referencingField(), val );
190175
}
191176

192177
return conditions.join( QStringLiteral( " AND " ) );
@@ -203,16 +188,7 @@ QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes
203188

204189
QgsField referencedField = referencedLayer()->fields().at( referencedIdx );
205190

206-
if ( referencedField.type() == QVariant::String )
207-
{
208-
// Use quotes
209-
conditions << QStringLiteral( "\"%1\" = '%2'" ).arg( fieldPair.referencedField(), attributes.at( referencingIdx ).toString() );
210-
}
211-
else
212-
{
213-
// No quotes
214-
conditions << QStringLiteral( "\"%1\" = %2" ).arg( fieldPair.referencedField(), attributes.at( referencingIdx ).toString() );
215-
}
191+
conditions << QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( fieldPair.referencedField() ), QgsExpression::quotedValue( attributes.at( referencingIdx ) ) );
216192
}
217193

218194
QgsFeatureRequest myRequest;

src/gui/editorwidgets/qgsrelationreferencewidget.cpp

+1-16
Original file line numberDiff line numberDiff line change
@@ -861,22 +861,7 @@ void QgsRelationReferenceWidget::filterChanged()
861861
if ( cb->currentIndex() != 0 )
862862
{
863863
const QString fieldName = cb->property( "Field" ).toString();
864-
865-
if ( cb->currentText() == nullValue.toString() )
866-
{
867-
filters << QStringLiteral( "\"%1\" IS NULL" ).arg( fieldName );
868-
}
869-
else
870-
{
871-
if ( mReferencedLayer->fields().field( fieldName ).type() == QVariant::String )
872-
{
873-
filters << QStringLiteral( "\"%1\" = '%2'" ).arg( fieldName, cb->currentText() );
874-
}
875-
else
876-
{
877-
filters << QStringLiteral( "\"%1\" = %2" ).arg( fieldName, cb->currentText() );
878-
}
879-
}
864+
filters << QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
880865
attrs << mReferencedLayer->fields().lookupField( fieldName );
881866
}
882867
}

tests/src/python/test_qgsexpression.py

+34
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import qgis # NOQA
1616

17+
from qgis.PyQt.QtCore import QVariant
1718
from qgis.testing import unittest
1819
from qgis.utils import qgsfunction
1920
from qgis.core import QgsExpression, QgsFeatureRequest
@@ -196,6 +197,39 @@ def testValid(self):
196197
e.setExpression('1')
197198
self.assertTrue(e.isValid())
198199

200+
def testCreateFieldEqualityExpression(self):
201+
e = QgsExpression()
202+
203+
# test when value is null
204+
field = "myfield"
205+
value = QVariant()
206+
res = '"myfield" IS NULL'
207+
self.assertEqual(e.createFieldEqualityExpression(field, value), res)
208+
209+
# test when value is null and field name has a quote
210+
field = "my'field"
211+
value = QVariant()
212+
res = '"my\'field" IS NULL'
213+
self.assertEqual(e.createFieldEqualityExpression(field, value), res)
214+
215+
# test when field name has a quote and value is an int
216+
field = "my'field"
217+
value = 5
218+
res = '"my\'field" = 5'
219+
self.assertEqual(e.createFieldEqualityExpression(field, value), res)
220+
221+
# test when field name has a quote and value is a string
222+
field = "my'field"
223+
value = '5'
224+
res = '"my\'field" = \'5\''
225+
self.assertEqual(e.createFieldEqualityExpression(field, value), res)
226+
227+
# test when field name has a quote and value is a boolean
228+
field = "my'field"
229+
value = True
230+
res = '"my\'field" = TRUE'
231+
self.assertEqual(e.createFieldEqualityExpression(field, value), res)
232+
199233

200234
if __name__ == "__main__":
201235
unittest.main()

tests/src/python/test_qgsrelation.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ def createReferencingLayer():
3838
f2.setFields(layer.pendingFields())
3939
f2.setAttributes(["test2", 123])
4040
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(101, 201)))
41-
assert pr.addFeatures([f1, f2])
41+
f3 = QgsFeature()
42+
f3.setFields(layer.pendingFields())
43+
f3.setAttributes(["foobar'bar", 124])
44+
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(101, 201)))
45+
assert pr.addFeatures([f1, f2, f3])
4246
return layer
4347

4448

@@ -57,7 +61,7 @@ def createReferencedLayer():
5761
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(2, 2)))
5862
f3 = QgsFeature()
5963
f3.setFields(layer.pendingFields())
60-
f3.setAttributes(["foobar", 789, 554])
64+
f3.setAttributes(["foobar'bar", 789, 554])
6165
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(2, 3)))
6266
assert pr.addFeatures([f1, f2, f3])
6367
return layer
@@ -112,6 +116,20 @@ def test_getRelatedFeatures(self):
112116
it = rel.getRelatedFeatures(feat)
113117
assert [a.attributes() for a in it] == [['test1', 123], ['test2', 123]]
114118

119+
def test_getRelatedFeaturesWithQuote(self):
120+
rel = QgsRelation()
121+
122+
rel.setId('rel1')
123+
rel.setName('Relation Number One')
124+
rel.setReferencingLayer(self.referencingLayer.id())
125+
rel.setReferencedLayer(self.referencedLayer.id())
126+
rel.addFieldPair('fldtxt', 'x')
127+
128+
feat = self.referencedLayer.getFeature(3)
129+
130+
it = rel.getRelatedFeatures(feat)
131+
assert next(it).attributes() == ["foobar'bar", 124]
132+
115133
def test_getReferencedFeature(self):
116134
rel = QgsRelation()
117135
rel.setId('rel1')

0 commit comments

Comments
 (0)