diff options
Diffstat (limited to 'src/plugins/sqldrivers/ibase/qsql_ibase.cpp')
-rw-r--r-- | src/plugins/sqldrivers/ibase/qsql_ibase.cpp | 140 |
1 files changed, 90 insertions, 50 deletions
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index f6eed5e227..6df7aa9507 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp +++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp @@ -3,11 +3,13 @@ #include "qsql_ibase_p.h" #include <QtCore/qcoreapplication.h> +#include <QtCore/qendian.h> #include <QtCore/qdatetime.h> #include <QtCore/qtimezone.h> #include <QtCore/qdeadlinetimer.h> #include <QtCore/qdebug.h> #include <QtCore/qlist.h> +#include <QtCore/private/qlocale_tools_p.h> #include <QtCore/qloggingcategory.h> #include <QtCore/qmap.h> #include <QtCore/qmutex.h> @@ -41,6 +43,10 @@ using namespace Qt::StringLiterals; #define blr_boolean_dtype blr_bool #endif +#if (defined(QT_SUPPORTS_INT128) || defined(Q_CC_MSVC)) && (FB_API_VER >= 40) +#define IBASE_INT128_SUPPORTED +#endif + constexpr qsizetype QIBaseChunkSize = SHRT_MAX / 2; #if (FB_API_VER >= 40) @@ -100,6 +106,9 @@ static void initDA(XSQLDA *sqlda) case SQL_TIMESTAMP: #if (FB_API_VER >= 40) case SQL_TIMESTAMP_TZ: +#ifdef IBASE_INT128_SUPPORTED + case SQL_INT128: +#endif #endif case SQL_TYPE_TIME: case SQL_TYPE_DATE: @@ -347,21 +356,14 @@ public: QSqlQuery qry(q->createResult()); qry.setForwardOnly(true); qry.exec(QString("select * from RDB$TIME_ZONES"_L1)); - if (qry.lastError().type()) { - q->setLastError(QSqlError( - QCoreApplication::translate("QIBaseDriver", - "failed to query time zone mapping from system table"), - qry.lastError().databaseText(), - QSqlError::StatementError, - qry.lastError().nativeErrorCode())); - + if (qry.lastError().isValid()) { + qCInfo(lcIbase) << "Table 'RDB$TIME_ZONES' not found - not timezone support available"; return; } while (qry.next()) { - auto record = qry.record(); - quint16 fbTzId = record.value(0).value<quint16>(); - QByteArray ianaId = record.value(1).toByteArray().simplified(); + quint16 fbTzId = qry.value(0).value<quint16>(); + QByteArray ianaId = qry.value(1).toByteArray().simplified(); qFbTzIdToIanaIdMap()->insert(fbTzId, ianaId); qIanaIdToFbTzIdMap()->insert(ianaId, fbTzId); } @@ -408,6 +410,32 @@ protected: QSqlRecord record() const override; template<typename T> + static QString numberToHighPrecision(T val, int scale) + { + const bool negative = val < 0; + QString number; +#ifdef IBASE_INT128_SUPPORTED + if constexpr (std::is_same_v<qinternalint128, T>) { + number = negative ? qint128toBasicLatin(val * -1) + : qint128toBasicLatin(val); + } else +#endif + number = negative ? QString::number(qAbs(val)) + : QString::number(val); + auto len = number.size(); + scale *= -1; + if (scale >= len) { + number = QString(scale - len + 1, u'0') + number; + len = number.size(); + } + const auto sepPos = len - scale; + number = number.left(sepPos) + u'.' + number.mid(sepPos); + if (negative) + number = u'-' + number; + return number; + } + + template<typename T> QVariant applyScale(T val, int scale) const { if (scale >= 0) @@ -420,28 +448,36 @@ protected: return QVariant(qint64(val * pow(10.0, scale))); case QSql::LowPrecisionDouble: return QVariant(double(val * pow(10.0, scale))); - case QSql::HighPrecision: { - const bool negative = val < 0; - QString number; - if constexpr (std::is_signed_v<T> || negative) - number = QString::number(qAbs(val)); - else - number = QString::number(val); - auto len = number.size(); - scale *= -1; - if (scale >= len) { - number = QString(scale - len + 1, u'0') + number; - len = number.size(); - } - const auto sepPos = len - scale; - number = number.left(sepPos) + u'.' + number.mid(sepPos); - if (negative) - number = u'-' + number; - return QVariant(number); - } + case QSql::HighPrecision: + return QVariant(numberToHighPrecision(val, scale)); } return QVariant(val); } + + template<typename T> + void setWithScale(const QVariant &val, int scale, char *data) + { + auto ptr = reinterpret_cast<T *>(data); + if (scale < 0) { + double d = floor(0.5 + val.toDouble() * pow(10.0, scale * -1)); +#ifdef IBASE_INT128_SUPPORTED + if constexpr (std::is_same_v<qinternalint128, T>) { + quint64 lower = quint64(d); + quint64 tmp = quint64(std::numeric_limits<quint32>::max()) + 1; + d /= tmp; + d /= tmp; + quint64 higher = quint64(d); + qinternalint128 result = higher; + result <<= 64; + result += lower; + *ptr = static_cast<T>(result); + } else +#endif + *ptr = static_cast<T>(d); + } + else + *ptr = val.value<T>(); + } }; class QIBaseResultPrivate: public QSqlCachedResultPrivate @@ -1102,32 +1138,25 @@ bool QIBaseResult::exec() } switch(d->inda->sqlvar[para].sqltype & ~1) { case SQL_INT64: - if (d->inda->sqlvar[para].sqlscale < 0) - *((qint64*)d->inda->sqlvar[para].sqldata) = - (qint64)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1)); - else - *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong(); + setWithScale<qint64>(val, d->inda->sqlvar[para].sqlscale, d->inda->sqlvar[para].sqldata); break; +#ifdef IBASE_INT128_SUPPORTED + case SQL_INT128: + setWithScale<qinternalint128>(val, d->inda->sqlvar[para].sqlscale, + d->inda->sqlvar[para].sqldata); + break; +#endif case SQL_LONG: - if (d->inda->sqlvar[para].sqllen == 4) { - if (d->inda->sqlvar[para].sqlscale < 0) - *((qint32*)d->inda->sqlvar[para].sqldata) = - (qint32)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1)); - else - *((qint32*)d->inda->sqlvar[para].sqldata) = (qint32)val.toInt(); - } else { - *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong(); - } + if (d->inda->sqlvar[para].sqllen == 4) + setWithScale<qint32>(val, d->inda->sqlvar[para].sqlscale, d->inda->sqlvar[para].sqldata); + else + setWithScale<qint64>(val, 0, d->inda->sqlvar[para].sqldata); break; case SQL_SHORT: - if (d->inda->sqlvar[para].sqlscale < 0) - *((short*)d->inda->sqlvar[para].sqldata) = - (short)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1)); - else - *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt(); + setWithScale<qint16>(val, d->inda->sqlvar[para].sqlscale, d->inda->sqlvar[para].sqldata); break; case SQL_FLOAT: - *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble(); + *((float*)d->inda->sqlvar[para].sqldata) = val.toFloat(); break; case SQL_DOUBLE: *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble(); @@ -1282,6 +1311,17 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx) row[idx] = applyScale(val, scale); break; } +#ifdef IBASE_INT128_SUPPORTED + case SQL_INT128: { + Q_ASSERT(d->sqlda->sqlvar[i].sqllen == sizeof(qinternalint128)); + const qinternalint128 val128 = qFromUnaligned<qinternalint128>(buf); + const auto scale = d->sqlda->sqlvar[i].sqlscale; + row[idx] = numberToHighPrecision(val128, scale); + if (numericalPrecisionPolicy() != QSql::HighPrecision) + row[idx] = applyScale(row[idx].toDouble(), 0); + break; + } +#endif case SQL_LONG: if (d->sqlda->sqlvar[i].sqllen == 4) { const auto val = *(qint32 *)buf; |