SQL/MySQL: Add support for Bit-Value Type - BIT

Add support for MYSQL_TYPE_BIT. Since the bitfield can be max 64bits,
store it in a uint64_t. Writing such a value as MYSQL_TYPE_LONGLONG
works as expected but receiving it needs a special handling.

[ChangeLog][SQL][MySQL] Added handling for Bit-Value Type - BIT.

Fixes: QTBUG-21326
Change-Id: Id20e3316caf6703b3bec8a828144494a20693fd8
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Christian Ehrlicher 2023-03-10 22:24:18 +01:00
parent 18bd15a9ea
commit 30de1f74de
2 changed files with 35 additions and 2 deletions

View File

@ -215,6 +215,7 @@ static QMetaType qDecodeMYSQLType(enum_field_types mysqltype, uint flags)
case MYSQL_TYPE_YEAR:
type = QMetaType::Int;
break;
case MYSQL_TYPE_BIT:
case MYSQL_TYPE_LONGLONG:
type = (flags & UNSIGNED_FLAG) ? QMetaType::ULongLong : QMetaType::LongLong;
break;
@ -303,6 +304,11 @@ static bool qIsInteger(int t)
|| t == QMetaType::LongLong || t == QMetaType::ULongLong;
}
static inline bool qIsBitfield(enum_field_types type)
{
return type == MYSQL_TYPE_BIT;
}
void QMYSQLResultPrivate::bindBlobs()
{
for (int i = 0; i < fields.size(); ++i) {
@ -519,6 +525,20 @@ bool QMYSQLResult::fetchFirst()
return fetch(0);
}
static inline uint64_t
qDecodeBitfield(const QMYSQLResultPrivate::QMyField &f, const char *outField)
{
// byte-aligned length
const auto numBytes = (f.myField->length + 7) / 8;
uint64_t val = 0;
for (unsigned long i = 0; i < numBytes && outField; ++i) {
uint64_t tmp = static_cast<uint8_t>(outField[i]);
val <<= 8;
val |= tmp;
}
return val;
}
QVariant QMYSQLResult::data(int field)
{
Q_D(QMYSQLResult);
@ -536,8 +556,9 @@ QVariant QMYSQLResult::data(int field)
if (d->preparedQuery) {
if (f.nullIndicator)
return QVariant(f.type);
if (qIsInteger(f.type.id())) {
if (qIsBitfield(f.myField->type)) {
return QVariant::fromValue(qDecodeBitfield(f, f.outField));
} else if (qIsInteger(f.type.id())) {
QVariant variant(f.type, f.outField);
// we never want to return char variants here, see QTBUG-53397
if (f.type.id() == QMetaType::UChar)
@ -569,6 +590,9 @@ QVariant QMYSQLResult::data(int field)
return QVariant(f.type);
}
if (qIsBitfield(f.myField->type))
return QVariant::fromValue(qDecodeBitfield(f, d->row[field]));
fieldLength = mysql_fetch_lengths(d->result)[field];
if (f.type.id() != QMetaType::QByteArray)
@ -677,6 +701,7 @@ bool QMYSQLResult::reset (const QString& query)
for(int i = 0; i < numFields; i++) {
MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
d->fields[i].myField = field;
}
setAt(QSql::BeforeFirstRow);
}
@ -794,6 +819,7 @@ bool QMYSQLResult::nextResult()
for (unsigned int i = 0; i < numFields; i++) {
MYSQL_FIELD *field = mysql_fetch_field_direct(d->result, i);
d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
d->fields[i].myField = field;
}
}

View File

@ -4629,6 +4629,13 @@ void tst_QSqlQuery::integralTypesMysql()
runIntegralTypesMysqlTest<qint64>(db, "bigIntTest", "BIGINT", withPreparedStatement);
runIntegralTypesMysqlTest<quint64>(db, "unsignedBigIntTest", "BIGINT UNSIGNED",
withPreparedStatement);
runIntegralTypesMysqlTest<quint64>(db, "bitmask_7", "BIT(7)", withPreparedStatement, 0,
(1LL << 7) - 1);
runIntegralTypesMysqlTest<quint64>(db, "bitmask_31", "BIT(31)", withPreparedStatement, 0,
(1LL << 31) - 1);
runIntegralTypesMysqlTest<quint64>(db, "bitmask_33", "BIT(33)", withPreparedStatement, 0,
(1LL << 33) - 1);
runIntegralTypesMysqlTest<quint64>(db, "bitmask_64", "BIT(64)", withPreparedStatement);
}
}