Skip to content

Commit

Permalink
Fix storing string representations of doubles in a longlong field
Browse files Browse the repository at this point in the history
results in NULL rather than converting value to longlong
with C++ test added
  • Loading branch information
rldhont committed Jun 27, 2019
1 parent 1321c08 commit 91d9220
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 6 deletions.
28 changes: 28 additions & 0 deletions src/core/qgsfield.cpp
Expand Up @@ -378,6 +378,34 @@ bool QgsField::convertCompatible( QVariant &v ) const
return true;
}

//String representations of doubles in QVariant will return false to convert( QVariant::LongLong )
//work around this by first converting to double, and then checking whether the double is convertible to longlong
if ( d->type == QVariant::LongLong && v.canConvert( QVariant::Double ) )
{
//firstly test the conversion to longlong because conversion to double will rounded the value
QVariant tmp( v );
if ( !tmp.convert( d->type ) )
{
bool ok = false;
double dbl = v.toDouble( &ok );
if ( !ok )
{
//couldn't convert to number
v = QVariant( d->type );
return false;
}

double round = std::round( dbl );
if ( round > std::numeric_limits<long long>::max() || round < -std::numeric_limits<long long>::max() )
{
//double too large to fit in longlong
v = QVariant( d->type );
return false;
}
v = QVariant( static_cast< long long >( std::round( dbl ) ) );
return true;
}
}

if ( !v.convert( d->type ) )
{
Expand Down
37 changes: 31 additions & 6 deletions tests/src/core/testqgsfield.cpp
Expand Up @@ -524,12 +524,6 @@ void TestQgsField::convertCompatible()
QVERIFY( intField.convertCompatible( smallLonglong ) );
QCOMPARE( smallLonglong.type(), QVariant::Int );
QCOMPARE( smallLonglong, QVariant( 99 ) );
//conversion of longlong to longlong field
QgsField longlongField( QStringLiteral( "long" ), QVariant::LongLong, QStringLiteral( "longlong" ) );
longlong = QVariant( 99999999999999999LL );
QVERIFY( longlongField.convertCompatible( longlong ) );
QCOMPARE( longlong.type(), QVariant::LongLong );
QCOMPARE( longlong, QVariant( 99999999999999999LL ) );

//string representation of an int
QVariant stringInt( "123456" );
Expand All @@ -542,6 +536,13 @@ void TestQgsField::convertCompatible()
QCOMPARE( stringInt.type(), QVariant::Int );
QCOMPARE( stringInt, QVariant( "123456" ) );

//conversion of longlong to longlong field
QgsField longlongField( QStringLiteral( "long" ), QVariant::LongLong, QStringLiteral( "longlong" ) );
longlong = QVariant( 99999999999999999LL );
QVERIFY( longlongField.convertCompatible( longlong ) );
QCOMPARE( longlong.type(), QVariant::LongLong );
QCOMPARE( longlong, QVariant( 99999999999999999LL ) );

//string representation of a longlong
QVariant stringLong( "99999999999999999" );
QVERIFY( longlongField.convertCompatible( stringLong ) );
Expand All @@ -553,6 +554,30 @@ void TestQgsField::convertCompatible()
QCOMPARE( stringLong.type(), QVariant::LongLong );
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );

//conversion of string double value to longlong
notNumberString = QVariant( "notanumber" );
QVERIFY( !longlongField.convertCompatible( notNumberString ) );
QCOMPARE( notNumberString.type(), QVariant::LongLong );
QVERIFY( notNumberString.isNull() );
//small double, should be rounded
smallDoubleString = QVariant( "45.7" );
QVERIFY( longlongField.convertCompatible( smallDoubleString ) );
QCOMPARE( smallDoubleString.type(), QVariant::LongLong );
QCOMPARE( smallDoubleString, QVariant( 46 ) );
negativeSmallDoubleString = QVariant( "-9345.754534525235235" );
QVERIFY( longlongField.convertCompatible( negativeSmallDoubleString ) );
QCOMPARE( negativeSmallDoubleString.type(), QVariant::LongLong );
QCOMPARE( negativeSmallDoubleString, QVariant( -9346 ) );
//large double, can be converted
largeDoubleString = QVariant( "9999999999.99" );
QVERIFY( longlongField.convertCompatible( largeDoubleString ) );
QCOMPARE( largeDoubleString.type(), QVariant::LongLong );
QCOMPARE( largeDoubleString, QVariant( 10000000000LL ) );
//extra large double, cannot be converted
largeDoubleString = QVariant( "999999999999999999999.99" );
QVERIFY( !longlongField.convertCompatible( largeDoubleString ) );
QCOMPARE( largeDoubleString.type(), QVariant::LongLong );
QVERIFY( largeDoubleString.isNull() );

//string representation of a double
QVariant stringDouble( "123456.012345" );
Expand Down

0 comments on commit 91d9220

Please sign in to comment.