diff options
-rw-r--r-- | src/plugins/sqldrivers/psql/qsql_psql.cpp | 51 | ||||
-rw-r--r-- | tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp | 42 |
2 files changed, 55 insertions, 38 deletions
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index f67c78b2bb..b4eb69e6cf 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -57,29 +57,7 @@ #include <libpq-fe.h> #include <pg_config.h> -#include <stdlib.h> -#include <math.h> -// below code taken from an example at http://www.gnu.org/software/hello/manual/autoconf/Function-Portability.html -#ifndef isnan - # define isnan(x) \ - (sizeof (x) == sizeof (long double) ? isnan_ld (x) \ - : sizeof (x) == sizeof (double) ? isnan_d (x) \ - : isnan_f (x)) - static inline int isnan_f (float x) { return x != x; } - static inline int isnan_d (double x) { return x != x; } - static inline int isnan_ld (long double x) { return x != x; } -#endif - -#ifndef isinf - # define isinf(x) \ - (sizeof (x) == sizeof (long double) ? isinf_ld (x) \ - : sizeof (x) == sizeof (double) ? isinf_d (x) \ - : isinf_f (x)) - static inline int isinf_f (float x) { return isnan (x - x); } - static inline int isinf_d (double x) { return isnan (x - x); } - static inline int isinf_ld (long double x) { return isnan (x - x); } -#endif - +#include <cmath> // workaround for postgres defining their OIDs in a private header file #define QBOOLOID 16 @@ -135,7 +113,7 @@ static const StatementId InvalidStatementId = 0; class QPSQLResultPrivate; -class QPSQLResult: public QSqlResult +class QPSQLResult final : public QSqlResult { Q_DECLARE_PRIVATE(QPSQLResult) @@ -164,7 +142,7 @@ protected: bool exec() override; }; -class QPSQLDriverPrivate : public QSqlDriverPrivate +class QPSQLDriverPrivate final : public QSqlDriverPrivate { Q_DECLARE_PUBLIC(QPSQLDriver) public: @@ -671,7 +649,7 @@ QVariant QPSQLResult::data(int i) return QString::fromLatin1(val).toULongLong(); case QVariant::Int: return atoi(val); - case QVariant::Double: + case QVariant::Double: { if (ptype == QNUMERICOID) { if (numericalPrecisionPolicy() != QSql::HighPrecision) { QVariant retval; @@ -689,7 +667,12 @@ QVariant QPSQLResult::data(int i) } return QString::fromLatin1(val); } + if (qstricmp(val, "Infinity") == 0) + return qInf(); + if (qstricmp(val, "-Infinity") == 0) + return -qInf(); return QString::fromLatin1(val).toDouble(); + } case QVariant::Date: if (val[0] == '\0') { return QVariant(QDate()); @@ -1497,18 +1480,10 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const 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; - } - } + if (qIsNaN(val)) + *target = QStringLiteral("'NaN'"); + else if (qIsInf(val)) + *target = (val < 0) ? QStringLiteral("'-Infinity'") : QStringLiteral("'Infinity'"); } QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const diff --git a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp index 427bc092a5..89978319a0 100644 --- a/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/sql/kernel/qsqldatabase/tst_qsqldatabase.cpp @@ -126,6 +126,8 @@ private slots: void formatValueTrimStrings(); void precisionPolicy_data() { generic_data(); } void precisionPolicy(); + void infinityAndNan_data() { generic_data(); } + void infinityAndNan(); void multipleThreads_data() { generic_data(); } void multipleThreads(); @@ -1467,6 +1469,46 @@ void tst_QSqlDatabase::precisionPolicy() db.setNumericalPrecisionPolicy(oldPrecision); } +void tst_QSqlDatabase::infinityAndNan() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + if (tst_Databases::getDatabaseType(db) != QSqlDriver::PostgreSQL) + QSKIP("checking for infinity/nan currently only works for PostgreSQL"); + + QSqlQuery q(db); + const QString tableName(qTableName("infititytest", __FILE__, db)); + tst_Databases::safeDropTables(db, {tableName}); + QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id smallint, val double precision)").arg(tableName))); + + QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?)").arg(tableName))); + + q.bindValue(0, 1); + q.bindValue(1, qQNaN()); + QVERIFY_SQL(q, exec()); + q.bindValue(0, 2); + q.bindValue(1, qInf()); + QVERIFY_SQL(q, exec()); + q.bindValue(0, 3); + q.bindValue(1, -qInf()); + QVERIFY_SQL(q, exec()); + + QVERIFY_SQL(q, exec(QString("SELECT val FROM %1 ORDER BY id").arg(tableName))); + + QVERIFY_SQL(q, next()); + QVERIFY(qIsNaN(q.value(0).toDouble())); + + QVERIFY_SQL(q, next()); + QVERIFY(qIsInf(q.value(0).toDouble())); + QVERIFY(q.value(0).toDouble() > 0); + + QVERIFY_SQL(q, next()); + QVERIFY(qIsInf(q.value(0).toDouble())); + QVERIFY(q.value(0).toDouble() < 0); +} + // This test needs a ODBC data source containing MYSQL in it's name void tst_QSqlDatabase::mysqlOdbc_unsignedIntegers() { |