Handle arrays comparison in QgsExpression

This commit is contained in:
arnaud.morvan@camptocamp.com 2017-03-17 17:49:54 +01:00
parent eeb1283018
commit 8385cd9f4c
2 changed files with 116 additions and 0 deletions

View File

@ -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
@ -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 ) )
{

View File

@ -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 );