Skip to content

Commit

Permalink
Default integers to QLongLong in expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Feb 24, 2017
1 parent beca8d7 commit 50347b3
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 40 deletions.
81 changes: 48 additions & 33 deletions src/core/qgsexpression.cpp
Expand Up @@ -220,11 +220,11 @@ static double getDoubleValue( const QVariant& value, QgsExpression* parent )
return x;
}

static int getIntValue( const QVariant& value, QgsExpression* parent )
static qlonglong getIntValue( const QVariant& value, QgsExpression* parent )
{
bool ok;
qint64 x = value.toLongLong( &ok );
if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
qlonglong x = value.toLongLong( &ok );
if ( ok )
{
return x;
}
Expand All @@ -235,6 +235,21 @@ static int getIntValue( const QVariant& value, QgsExpression* parent )
}
}

static int getNativeIntValue( const QVariant& value, QgsExpression* parent )
{
bool ok;
qlonglong x = value.toLongLong( &ok );
if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
{
return x;
}
else
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
return 0;
}
}

static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
{
QDateTime d = value.toDateTime();
Expand Down Expand Up @@ -532,13 +547,13 @@ static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*
}
static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
int min = getIntValue( values.at( 0 ), parent );
int max = getIntValue( values.at( 1 ), parent );
qlonglong min = getIntValue( values.at( 0 ), parent );
qlonglong max = getIntValue( values.at( 1 ), parent );
if ( max < min )
return QVariant();

// Return a random integer in the range [min, max] (inclusive)
return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
return QVariant( min + ( qrand() % static_cast< qlonglong >( max - min + 1 ) ) );
}

static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
Expand Down Expand Up @@ -1148,7 +1163,7 @@ static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionConte

static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QChar character = QChar( getIntValue( values.at( 0 ), parent ) );
QChar character = QChar( getNativeIntValue( values.at( 0 ), parent ) );
return QVariant( QString( character ) );
}

Expand All @@ -1157,7 +1172,7 @@ static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionCont
if ( values.length() == 2 || values.length() == 3 )
{
QString str = getStringValue( values.at( 0 ), parent );
int wrap = getIntValue( values.at( 1 ), parent );
qlonglong wrap = getIntValue( values.at( 1 ), parent );

if ( !str.isEmpty() && wrap != 0 )
{
Expand Down Expand Up @@ -1406,9 +1421,9 @@ static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContex
return QVariant();

QString str = getStringValue( values.at( 0 ), parent );
int from = getIntValue( values.at( 1 ), parent );
qlonglong from = getIntValue( values.at( 1 ), parent );

int len = 0;
qlonglong len = 0;
if ( values.at( 2 ).isValid() )
len = getIntValue( values.at( 2 ), parent );
else
Expand Down Expand Up @@ -1536,29 +1551,29 @@ static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContex
static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
QString string = getStringValue( values.at( 0 ), parent );
int pos = getIntValue( values.at( 1 ), parent );
qlonglong pos = getIntValue( values.at( 1 ), parent );
return string.right( pos );
}

static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
QString string = getStringValue( values.at( 0 ), parent );
int pos = getIntValue( values.at( 1 ), parent );
qlonglong pos = getIntValue( values.at( 1 ), parent );
return string.left( pos );
}

static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
QString string = getStringValue( values.at( 0 ), parent );
int length = getIntValue( values.at( 1 ), parent );
qlonglong length = getIntValue( values.at( 1 ), parent );
QString fill = getStringValue( values.at( 2 ), parent );
return string.leftJustified( length, fill.at( 0 ), true );
}

static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
{
QString string = getStringValue( values.at( 0 ), parent );
int length = getIntValue( values.at( 1 ), parent );
qlonglong length = getIntValue( values.at( 1 ), parent );
QString fill = getStringValue( values.at( 2 ), parent );
return string.rightJustified( length, fill.at( 0 ), true );
}
Expand Down Expand Up @@ -1847,7 +1862,7 @@ static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContex
return QVariant();

//idx is 1 based
int idx = getIntValue( values.at( 1 ), parent ) - 1;
qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;

QgsVertexId vId;
if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
Expand Down Expand Up @@ -1968,7 +1983,7 @@ static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressio
return QVariant();

//idx is 1 based
int idx = getIntValue( values.at( 1 ), parent ) - 1;
qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;

if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
return QVariant();
Expand All @@ -1990,7 +2005,7 @@ static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionCon
return QVariant();

//idx is 1 based
int idx = getIntValue( values.at( 1 ), parent ) - 1;
qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;

if ( idx < 0 || idx >= collection->numGeometries() )
return QVariant();
Expand Down Expand Up @@ -2069,7 +2084,7 @@ static QVariant fcnSmooth( const QVariantList& values, const QgsExpressionContex
if ( geom.isNull() )
return QVariant();

int iterations = qMin( getIntValue( values.at( 1 ), parent ), 10 );
int iterations = qMin( getNativeIntValue( values.at( 1 ), parent ), 10 );
double offset = qBound( 0.0, getDoubleValue( values.at( 2 ), parent ), 0.5 );
double minLength = getDoubleValue( values.at( 3 ), parent );
double maxAngle = qBound( 0.0, getDoubleValue( values.at( 4 ), parent ), 180.0 );
Expand Down Expand Up @@ -2175,7 +2190,7 @@ static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionC
static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
{
FEAT_FROM_CONTEXT( context, f );
int idx = getIntValue( values.at( 0 ), parent );
qlonglong idx = getIntValue( values.at( 0 ), parent );
QgsGeometry g = f.geometry();
if ( g.isNull() )
return QVariant();
Expand Down Expand Up @@ -2523,7 +2538,7 @@ static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContex

QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
double dist = getDoubleValue( values.at( 1 ), parent );
int seg = 8;
qlonglong seg = 8;
if ( values.length() == 3 )
seg = getIntValue( values.at( 2 ), parent );

Expand All @@ -2536,7 +2551,7 @@ static QVariant fcnOffsetCurve( const QVariantList& values, const QgsExpressionC
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
double dist = getDoubleValue( values.at( 1 ), parent );
int segments = getIntValue( values.at( 2 ), parent );
qlonglong segments = getIntValue( values.at( 2 ), parent );
QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
return QVariant();
Expand All @@ -2551,7 +2566,7 @@ static QVariant fcnSingleSidedBuffer( const QVariantList& values, const QgsExpre
{
QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
double dist = getDoubleValue( values.at( 1 ), parent );
int segments = getIntValue( values.at( 2 ), parent );
qlonglong segments = getIntValue( values.at( 2 ), parent );
QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
return QVariant();
Expand Down Expand Up @@ -2687,7 +2702,7 @@ static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionCon
return QVariant();

QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
int prec = 8;
qlonglong prec = 8;
if ( values.length() == 2 )
prec = getIntValue( values.at( 1 ), parent );
QString wkt = fGeom.exportToWkt( prec );
Expand Down Expand Up @@ -2907,15 +2922,15 @@ static QVariant fcnLineInterpolateAngle( const QVariantList& values, const QgsEx
static QVariant fcnAngleAtVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
int vertex = getIntValue( values.at( 1 ), parent );
qlonglong vertex = getIntValue( values.at( 1 ), parent );

return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
}

static QVariant fcnDistanceToVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
QgsGeometry geom = getGeometry( values.at( 0 ), parent );
int vertex = getIntValue( values.at( 1 ), parent );
qlonglong vertex = getIntValue( values.at( 1 ), parent );

return geom.distanceToVertex( vertex );
}
Expand Down Expand Up @@ -3529,7 +3544,7 @@ static QVariant fcnArrayFind( const QVariantList& values, const QgsExpressionCon
static QVariant fcnArrayGet( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
{
const QVariantList list = getListValue( values.at( 0 ), parent );
const int pos = getIntValue( values.at( 1 ), parent );
const qlonglong pos = getIntValue( values.at( 1 ), parent );
if ( pos < 0 || pos >= list.length() ) return QVariant();
return list.at( pos );
}
Expand Down Expand Up @@ -4663,9 +4678,9 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, const Q
else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
{
// both are integers - let's use integer arithmetics
int iL = getIntValue( vL, parent );
qlonglong iL = getIntValue( vL, parent );
ENSURE_NO_EVAL_ERROR;
int iR = getIntValue( vR, parent );
qlonglong iR = getIntValue( vR, parent );
ENSURE_NO_EVAL_ERROR;

if ( mOp == boMod && iR == 0 )
Expand Down Expand Up @@ -4934,16 +4949,16 @@ bool QgsExpression::NodeBinaryOperator::compare( double diff )
}
}

int QgsExpression::NodeBinaryOperator::computeInt( int x, int y )
qlonglong QgsExpression::NodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
{
switch ( mOp )
{
case boPlus:
return x + y;
case boMinus:
return x -y;
return x - y;
case boMul:
return x*y;
return x * y;
case boDiv:
return x / y;
case boMod:
Expand Down Expand Up @@ -4975,9 +4990,9 @@ double QgsExpression::NodeBinaryOperator::computeDouble( double x, double y )
case boPlus:
return x + y;
case boMinus:
return x -y;
return x - y;
case boMul:
return x*y;
return x * y;
case boDiv:
return x / y;
case boMod:
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsexpression.h
Expand Up @@ -1045,7 +1045,7 @@ class CORE_EXPORT QgsExpression

protected:
bool compare( double diff );
int computeInt( int x, int y );
qlonglong computeInt( qlonglong x, qlonglong y );
double computeDouble( double x, double y );

/** Computes the result date time calculation from a start datetime and an interval
Expand Down
20 changes: 14 additions & 6 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -968,7 +968,7 @@ class TestQgsExpression: public QObject
QTest::newRow( "date - date" ) << "to_date('2013-03-04') - to_date('2013-03-01')" << false << QVariant( QgsInterval( 3*24*60*60 ) );
QTest::newRow( "datetime - datetime" ) << "to_datetime('2013-03-04 08:30:00') - to_datetime('2013-03-01 05:15:00')" << false << QVariant( QgsInterval( 3*24*60*60 + 3 * 60*60 + 15*60 ) );
QTest::newRow( "time - time" ) << "to_time('08:30:00') - to_time('05:15:00')" << false << QVariant( QgsInterval( 3 * 60*60 + 15*60 ) );
QTest::newRow( "epoch" ) << "epoch(to_date('2017-01-01'))" << false << QVariant(( qlonglong )1483203600000 );
QTest::newRow( "epoch" ) << "epoch(to_datetime('2017-01-01T00:00:01+00:00'))" << false << QVariant( 1483228801000LL );
QTest::newRow( "epoch invalid date" ) << "epoch('invalid')" << true << QVariant();

// Color functions
Expand Down Expand Up @@ -1103,13 +1103,21 @@ class TestQgsExpression: public QObject

Q_ASSERT( exp.prepare( &context ) );

QCOMPARE( result.type(), expected.type() );
switch ( result.type() )
QVariant::Type resultType = result.type();
QVariant::Type expectedType = expected.type();

if ( resultType == QVariant::Int )
resultType = QVariant::LongLong;
if ( expectedType == QVariant::Int )
expectedType = QVariant::LongLong;

QCOMPARE( resultType, expectedType );
switch ( resultType )
{
case QVariant::Invalid:
break; // nothing more to check
case QVariant::Int:
QCOMPARE( result.toInt(), expected.toInt() );
case QVariant::LongLong:
QCOMPARE( result.toLongLong(), expected.toLongLong() );
break;
case QVariant::Double:
QCOMPARE( result.toDouble(), expected.toDouble() );
Expand Down Expand Up @@ -1192,7 +1200,7 @@ class TestQgsExpression: public QObject
QCOMPARE( prepareRes, true );
QCOMPARE( exp.hasEvalError(), false );
QVariant res = exp.evaluate( &context );
QCOMPARE( res.type(), QVariant::Int );
QCOMPARE( res.type(), QVariant::LongLong );
QCOMPARE( res.toInt(), 21 );

// bad exp
Expand Down

0 comments on commit 50347b3

Please sign in to comment.