PostgreSQL: Fix special floating point handling for 'float' types.

Introduce a template function to determine the special values
via macro and use that for QVariant::Double and QMetaType::Float.

Task-number: QTBUG-44381
Change-Id: I379dd82b22d467b0aebaa42f4f0f5c52472a5c47
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
This commit is contained in:
Friedemann Kleint 2015-02-17 14:29:09 +01:00
parent 2f5c2ec12f
commit 916af48cff
2 changed files with 63 additions and 15 deletions

View File

@ -1248,6 +1248,23 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
return info; return info;
} }
template <class FloatType>
inline void assignSpecialPsqlFloatValue(FloatType val, QString *target)
{
if (isnan(val)) {
*target = QLatin1String("'NaN'");
} else {
switch (isinf(val)) {
case 1:
*target = QLatin1String("'Infinity'");
break;
case -1:
*target = QLatin1String("'-Infinity'");
break;
}
}
}
QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
{ {
Q_D(const QPSQLDriver); Q_D(const QPSQLDriver);
@ -1255,7 +1272,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
if (field.isNull()) { if (field.isNull()) {
r = QLatin1String("NULL"); r = QLatin1String("NULL");
} else { } else {
switch (field.type()) { switch (int(field.type())) {
case QVariant::DateTime: case QVariant::DateTime:
#ifndef QT_NO_DATESTRING #ifndef QT_NO_DATESTRING
if (field.value().toDateTime().isValid()) { if (field.value().toDateTime().isValid()) {
@ -1305,21 +1322,16 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
qPQfreemem(data); qPQfreemem(data);
break; break;
} }
case QVariant::Double: { case QMetaType::Float:
double val = field.value().toDouble(); assignSpecialPsqlFloatValue(field.value().toFloat(), &r);
if (isnan(val)) if (r.isEmpty())
r = QLatin1String("'NaN'"); r = QSqlDriver::formatValue(field, trimStrings);
else { break;
int res = isinf(val); case QVariant::Double:
if (res == 1) assignSpecialPsqlFloatValue(field.value().toDouble(), &r);
r = QLatin1String("'Infinity'"); if (r.isEmpty())
else if (res == -1) r = QSqlDriver::formatValue(field, trimStrings);
r = QLatin1String("'-Infinity'");
else
r = QSqlDriver::formatValue(field, trimStrings);
}
break; break;
}
default: default:
r = QSqlDriver::formatValue(field, trimStrings); r = QSqlDriver::formatValue(field, trimStrings);
break; break;

View File

@ -34,6 +34,8 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <QtSql/QtSql> #include <QtSql/QtSql>
#include <numeric>
#include "../qsqldatabase/tst_databases.h" #include "../qsqldatabase/tst_databases.h"
const QString qtest(qTableName("qtest", __FILE__, QSqlDatabase())); const QString qtest(qTableName("qtest", __FILE__, QSqlDatabase()));
@ -159,6 +161,8 @@ private slots:
void bindBool(); void bindBool();
void psql_bindWithDoubleColonCastOperator_data() { generic_data("QPSQL"); } void psql_bindWithDoubleColonCastOperator_data() { generic_data("QPSQL"); }
void psql_bindWithDoubleColonCastOperator(); void psql_bindWithDoubleColonCastOperator();
void psql_specialFloatValues_data() { generic_data("QPSQL"); }
void psql_specialFloatValues();
void queryOnInvalidDatabase_data() { generic_data(); } void queryOnInvalidDatabase_data() { generic_data(); }
void queryOnInvalidDatabase(); void queryOnInvalidDatabase();
void createQueryOnClosedDatabase_data() { generic_data(); } void createQueryOnClosedDatabase_data() { generic_data(); }
@ -2437,6 +2441,38 @@ void tst_QSqlQuery::psql_bindWithDoubleColonCastOperator()
QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3" ) ); QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3" ) );
} }
void tst_QSqlQuery::psql_specialFloatValues()
{
if (!std::numeric_limits<float>::has_quiet_NaN)
QSKIP("Platform does not have quiet_NaN");
if (!std::numeric_limits<float>::has_infinity)
QSKIP("Platform does not have infinity");
QFETCH( QString, dbName );
QSqlDatabase db = QSqlDatabase::database( dbName );
CHECK_DATABASE( db );
QSqlQuery query(db);
const QString tableName = qTableName("floattest", __FILE__, db);
QVERIFY_SQL( query, exec("create table " + tableName + " (value float)" ) );
QVERIFY_SQL(query, prepare("insert into " + tableName + " values(:value)") );
QVariantList data;
data << QVariant(double(42.42))
<< QVariant(std::numeric_limits<double>::quiet_NaN())
<< QVariant(std::numeric_limits<double>::infinity())
<< QVariant(float(42.42))
<< QVariant(std::numeric_limits<float>::quiet_NaN())
<< QVariant(std::numeric_limits<float>::infinity());
foreach (const QVariant &v, data) {
query.bindValue(":value", v);
QVERIFY_SQL( query, exec() );
}
QVERIFY_SQL( query, exec("drop table " + tableName) );
}
/* For task 157397: Using QSqlQuery with an invalid QSqlDatabase /* For task 157397: Using QSqlQuery with an invalid QSqlDatabase
does not set the last error of the query. does not set the last error of the query.
This test function will output some warnings, that's ok. This test function will output some warnings, that's ok.