diff options
author | Christian Ehrlicher <[email protected]> | 2024-04-20 20:51:50 +0200 |
---|---|---|
committer | Christian Ehrlicher <[email protected]> | 2024-05-25 22:25:12 +0200 |
commit | 373ae6cbd24cf0ddbed453e14b1f683e76c92bb5 (patch) | |
tree | 40823a326b5966ca94fb06af9fa704da5ff1a884 /src/plugins/sqldrivers/ibase/qsql_ibase.cpp | |
parent | e9c6adb992b4f209e3c206dc68cbd61f3f581716 (diff) |
SQL/IBase: add partial support for SQL_INT128 datatype
Implement partial support for SQL_INT128 datatype which is used for
DECIMAL/NUMERIC columns with a precision > 18. This support is only
available when QT_SUPPORTS_INT128 is defined and for MSVC.
Binding values to columns which need SQL_INT128 is supported but
numbers given as QString will be converted to doubles even if
QSql::HighPrecision is set.
[ChangeLog][SQL][IBASE] Added support for SQL_INT128 datatype.
Task-number: QTBUG-124575
Change-Id: If3fb1eb0f19dc60f000d163f3bf45da7acb08c87
Reviewed-by: Thiago Macieira <[email protected]>
Reviewed-by: Andreas Bacher <[email protected]>
Diffstat (limited to 'src/plugins/sqldrivers/ibase/qsql_ibase.cpp')
-rw-r--r-- | src/plugins/sqldrivers/ibase/qsql_ibase.cpp | 92 |
1 files changed, 71 insertions, 21 deletions
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index d2dc9f6a811..6df7aa95074 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: @@ -401,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) @@ -413,25 +448,8 @@ 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); } @@ -440,8 +458,23 @@ protected: void setWithScale(const QVariant &val, int scale, char *data) { auto ptr = reinterpret_cast<T *>(data); - if (scale < 0) - *ptr = static_cast<T>(floor(0.5 + val.toDouble() * pow(10.0, scale * -1))); + 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>(); } @@ -1107,6 +1140,12 @@ bool QIBaseResult::exec() case SQL_INT64: 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) setWithScale<qint32>(val, d->inda->sqlvar[para].sqlscale, d->inda->sqlvar[para].sqldata); @@ -1272,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; |