Skip to content

Commit

Permalink
Merge pull request #45841 from 3nids/fix-rel-mismatch-type
Browse files Browse the repository at this point in the history
improve success of compiled expressions running on backend with mismatching types in relation field pairs
  • Loading branch information
3nids committed Nov 9, 2021
2 parents c1dfea5 + 295a2e9 commit ac63c6e
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 6 deletions.
3 changes: 2 additions & 1 deletion python/core/auto_generated/expression/qgsexpression.sip.in
Expand Up @@ -673,13 +673,14 @@ length, and presents text representations of non numeric/text types (e.g., geome
.. versionadded:: 2.14
%End

static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value );
static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType = QVariant::Type::Invalid );
%Docstring
Create an expression allowing to evaluate if a field is equal to a
value. The value may be null.

:param fieldName: the name of the field
:param value: the value of the field
:param fieldType: the type of the field on the left side used to quote the value. If not given, the value type is used instead

:return: the expression to evaluate field equality

Expand Down
6 changes: 4 additions & 2 deletions src/core/expression/qgsexpression.cpp
Expand Up @@ -1112,14 +1112,16 @@ QString QgsExpression::formatPreviewString( const QVariant &value, const bool ht
}
}

QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value )
QString QgsExpression::createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType )
{
QString expr;

if ( value.isNull() )
expr = QStringLiteral( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
else
else if ( fieldType == QVariant::Type::Invalid )
expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
else
expr = QStringLiteral( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value, fieldType ) );

return expr;
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/expression/qgsexpression.h
Expand Up @@ -659,10 +659,11 @@ class CORE_EXPORT QgsExpression
* value. The value may be null.
* \param fieldName the name of the field
* \param value the value of the field
* \param fieldType the type of the field on the left side used to quote the value. If not given, the value type is used instead
* \returns the expression to evaluate field equality
* \since QGIS 3.0
*/
static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value );
static QString createFieldEqualityExpression( const QString &fieldName, const QVariant &value, QVariant::Type fieldType = QVariant::Type::Invalid );

/**
* Returns TRUE if the given \a expression is a simple "field=value" type expression.
Expand Down
22 changes: 20 additions & 2 deletions src/core/qgsrelation.cpp
Expand Up @@ -221,7 +221,16 @@ QString QgsRelation::getRelatedFeaturesFilter( const QgsFeature &feature ) const
for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
{
QVariant val( feature.attribute( pair.referencedField() ) );
conditions << QgsExpression::createFieldEqualityExpression( pair.referencingField(), val );
int referencingIdx = referencingLayer()->fields().lookupField( pair.referencingField() );
if ( referencingIdx >= 0 )
{
QVariant::Type fieldType = referencingLayer()->fields().at( referencingIdx ).type();
conditions << QgsExpression::createFieldEqualityExpression( pair.referencingField(), val, fieldType );
}
else
{
conditions << QgsExpression::createFieldEqualityExpression( pair.referencingField(), val );
}
}

return conditions.join( QLatin1String( " AND " ) );
Expand All @@ -233,8 +242,17 @@ QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes

for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
{
int referencedIdx = referencedLayer()->fields().lookupField( pair.referencedField() );
int referencingIdx = referencingLayer()->fields().lookupField( pair.referencingField() );
conditions << QgsExpression::createFieldEqualityExpression( pair.referencedField(), attributes.at( referencingIdx ) );
if ( referencedIdx >= 0 )
{
QVariant::Type fieldType = referencedLayer()->fields().at( referencedIdx ).type();
conditions << QgsExpression::createFieldEqualityExpression( pair.referencedField(), attributes.at( referencingIdx ), fieldType );
}
else
{
conditions << QgsExpression::createFieldEqualityExpression( pair.referencedField(), attributes.at( referencingIdx ) );
}
}

QgsFeatureRequest myRequest;
Expand Down
14 changes: 14 additions & 0 deletions tests/src/python/test_qgsexpression.py
Expand Up @@ -271,6 +271,20 @@ def testCreateFieldEqualityExpression(self):
res = '"my\'field" = TRUE'
self.assertEqual(e.createFieldEqualityExpression(field, value), res)

# test with field type
field = "myfield"
value = 1
type = QVariant.String
res = '"myfield" = \'1\''
self.assertEqual(e.createFieldEqualityExpression(field, value, type), res)

# test with field type
field = "myfield"
value = "1"
type = QVariant.Int
res = '"myfield" = 1'
self.assertEqual(e.createFieldEqualityExpression(field, value, type), res)

def testReferencedAttributeIndexesNonExistingField(self):
e = QgsExpression()
e.setExpression("foo = 1")
Expand Down

0 comments on commit ac63c6e

Please sign in to comment.