From 916af48cff66e0acbeb6da39997498ce3b9626ce Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 17 Feb 2015 14:29:09 +0100 Subject: [PATCH] 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 --- src/sql/drivers/psql/qsql_psql.cpp | 42 ++++++++++++------- .../sql/kernel/qsqlquery/tst_qsqlquery.cpp | 36 ++++++++++++++++ 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index c83c633fd0f..3aa2455ff05 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -1248,6 +1248,23 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const return info; } +template +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 { Q_D(const QPSQLDriver); @@ -1255,7 +1272,7 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const if (field.isNull()) { r = QLatin1String("NULL"); } else { - switch (field.type()) { + switch (int(field.type())) { case QVariant::DateTime: #ifndef QT_NO_DATESTRING if (field.value().toDateTime().isValid()) { @@ -1305,21 +1322,16 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const qPQfreemem(data); break; } - case QVariant::Double: { - double val = field.value().toDouble(); - if (isnan(val)) - r = QLatin1String("'NaN'"); - else { - int res = isinf(val); - if (res == 1) - r = QLatin1String("'Infinity'"); - else if (res == -1) - r = QLatin1String("'-Infinity'"); - else - r = QSqlDriver::formatValue(field, trimStrings); - } + case QMetaType::Float: + assignSpecialPsqlFloatValue(field.value().toFloat(), &r); + if (r.isEmpty()) + r = QSqlDriver::formatValue(field, trimStrings); + break; + case QVariant::Double: + assignSpecialPsqlFloatValue(field.value().toDouble(), &r); + if (r.isEmpty()) + r = QSqlDriver::formatValue(field, trimStrings); break; - } default: r = QSqlDriver::formatValue(field, trimStrings); break; diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index 9502343bd7f..d2b4474dd49 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include "../qsqldatabase/tst_databases.h" const QString qtest(qTableName("qtest", __FILE__, QSqlDatabase())); @@ -159,6 +161,8 @@ private slots: void bindBool(); void psql_bindWithDoubleColonCastOperator_data() { generic_data("QPSQL"); } void psql_bindWithDoubleColonCastOperator(); + void psql_specialFloatValues_data() { generic_data("QPSQL"); } + void psql_specialFloatValues(); void queryOnInvalidDatabase_data() { generic_data(); } void queryOnInvalidDatabase(); 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" ) ); } +void tst_QSqlQuery::psql_specialFloatValues() +{ + if (!std::numeric_limits::has_quiet_NaN) + QSKIP("Platform does not have quiet_NaN"); + if (!std::numeric_limits::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::quiet_NaN()) + << QVariant(std::numeric_limits::infinity()) + << QVariant(float(42.42)) + << QVariant(std::numeric_limits::quiet_NaN()) + << QVariant(std::numeric_limits::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 does not set the last error of the query. This test function will output some warnings, that's ok.