Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Handle arrays comparison in QgsExpression
  • Loading branch information
arnaud-morvan committed Mar 22, 2017
1 parent eeb1283 commit 8385cd9
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
74 changes: 74 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -175,6 +175,11 @@ inline bool isNull( const QVariant &v )
return v.isNull();
}

inline bool isList( const QVariant &v )
{
return v.type() == QVariant::List;
}

///////////////////////////////////////////////
// evaluation error macros

Expand Down Expand Up @@ -4813,6 +4818,75 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression *parent, const Q
{
return TVL_Unknown;
}
else if ( isList( vL ) || isList( vR ) )
{
// verify that we have two lists
if ( !isList( vL ) || !isList( vR ) )
return TVL_Unknown;

// and search for not equal respective items
QVariantList lL = vL.toList();
QVariantList lR = vR.toList();
for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
{
if ( isNull( lL.at( i ) ) && isNull( lR.at( i ) ) )
continue; // same behavior as PostgreSQL

if ( isNull( lL.at( i ) ) || isNull( lR.at( i ) ) )
{
switch ( mOp )
{
case boEQ:
return false;
case boNE:
return true;
case boLT:
case boLE:
return isNull( lR.at( i ) );
case boGT:
case boGE:
return isNull( lL.at( i ) );
default:
Q_ASSERT( false );
return TVL_Unknown;
}
}

QgsExpression::NodeLiteral nL( lL.at( i ) );
QgsExpression::NodeLiteral nR( lR.at( i ) );
QgsExpression::NodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
QVariant eq = eqNode.eval( parent, context );
ENSURE_NO_EVAL_ERROR;
if ( eq == TVL_False )
{
// return the two items comparison
QgsExpression::NodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
QVariant v = node.eval( parent, context );
ENSURE_NO_EVAL_ERROR;
return v;
}
}

// default to length comparison
switch ( mOp )
{
case boEQ:
return lL.length() == lR.length();
case boNE:
return lL.length() != lR.length();
case boLT:
return lL.length() < lR.length();
case boGT:
return lL.length() > lR.length();
case boLE:
return lL.length() <= lR.length();
case boGE:
return lL.length() >= lR.length();
default:
Q_ASSERT( false );
return TVL_Unknown;
}
}
else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
{
Expand Down
42 changes: 42 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -2443,6 +2443,48 @@ class TestQgsExpression: public QObject
QCOMPARE( badArray.evalErrorString(), QString( "Cannot convert 'not an array' to array" ) );
}

void compare_arrays()
{
QCOMPARE( QgsExpression( "array() = array()" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(NULL) = array(NULL)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array() = array(NULL)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array(1, NULL) = array(NULL, 1)" ).evaluate(), QVariant( false ) );

QCOMPARE( QgsExpression( "array('hello') = array('hello')" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array('hello') = array('hello2')" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') = array('h', 'e', 'l', 'l', 'o')" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') = array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );

QCOMPARE( QgsExpression( "array('1') = array(1)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array('1.2') = array(1.2)" ).evaluate(), QVariant( true ) );

QCOMPARE( QgsExpression( "array() != array()" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array(NULL) != array(NULL)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array() != array(NULL)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array('hello') != array('hello')" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('hello') != array('hello2')" ).evaluate(), QVariant( true ) );

QCOMPARE( QgsExpression( "array() < array(1)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1) < array(NULL)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1) < array(1)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array(1) < array(2)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(2) < array(1)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array(1) < array(1, 2)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1, 2) < array(1)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') < array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') > array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( true ) );

QCOMPARE( QgsExpression( "array() <= array(1)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1) <= array(NULL)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1) <= array(1)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1) <= array(2)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(2) <= array(1)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array(1) <= array(1, 2)" ).evaluate(), QVariant( true ) );
QCOMPARE( QgsExpression( "array(1, 2) <= array(1)" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') <= array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( false ) );
QCOMPARE( QgsExpression( "array('h', 'e', 'l', 'l', 'o') >= array('h', 'e', 'l', 'l')" ).evaluate(), QVariant( true ) );
}

void eval_map()
{
QgsFeature f( 100 );
Expand Down

0 comments on commit 8385cd9

Please sign in to comment.