Never return char variants when reading prepared MySQL statements
This has undesired effects when converting a QSqlRecord to JSON. A char(0) e.g. has special semantics that are undesired when reading a Tinyint column. I don't think that returning bool for the special case of a Tinyint(1) is required. This also did not happen before, and is also not happening when not using a prepared statement. Instead, a plain int/uint QVariant is returned. This patch extends tst_QSqlQuery::integralTypesMysql to also cover reading and writing booleans from/to a MySQL table column of type Tinyint(1). Additionally, the reading is now also done with a prepared statement and we also check the raw variant value. The broken behavior fixed by this patch was introduced by me in commit 194403a3483b7317cc9511bc8b2ab307775643c5. Change-Id: I028a3abd83fdd2b42d98d478950d205e5b6bbeb5 Task-number: QTBUG-53397 Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
parent
3b8df0ea44
commit
3370ab9119
@ -596,8 +596,15 @@ QVariant QMYSQLResult::data(int field)
|
||||
if (f.nullIndicator)
|
||||
return QVariant(f.type);
|
||||
|
||||
if (qIsInteger(f.type))
|
||||
return QVariant(f.type, f.outField);
|
||||
if (qIsInteger(f.type)) {
|
||||
QVariant variant(f.type, f.outField);
|
||||
// we never want to return char variants here, see QTBUG-53397
|
||||
if (static_cast<int>(f.type) == QMetaType::UChar)
|
||||
return variant.toUInt();
|
||||
else if (static_cast<int>(f.type) == QMetaType::Char)
|
||||
return variant.toInt();
|
||||
return variant;
|
||||
}
|
||||
|
||||
if (f.type != QVariant::ByteArray)
|
||||
val = toUnicode(d->driver->d_func()->tc, f.outField, f.bufLength);
|
||||
|
@ -4007,12 +4007,14 @@ void runIntegralTypesMysqlTest(QSqlDatabase &db, const QString &tableName, const
|
||||
QVERIFY_SQL(q, exec("DROP TABLE IF EXISTS " + tableName));
|
||||
QVERIFY_SQL(q, exec("CREATE TABLE " + tableName + " (id " + type + ")"));
|
||||
|
||||
const int steps = 20;
|
||||
const T increment = max / steps - min / steps;
|
||||
const int steps = (max == min + 1) ? 2 : 20;
|
||||
const T increment = (max == min + 1) ? 1 : (max / steps - min / steps);
|
||||
|
||||
// insert some values
|
||||
QVector<T> values;
|
||||
QVector<QVariant> variantValues;
|
||||
values.resize(steps);
|
||||
variantValues.resize(steps);
|
||||
T v = min;
|
||||
if (withPreparedStatement) {
|
||||
QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " (id) VALUES (?)"));
|
||||
@ -4025,17 +4027,30 @@ void runIntegralTypesMysqlTest(QSqlDatabase &db, const QString &tableName, const
|
||||
QVERIFY_SQL(q, exec("INSERT INTO " + tableName + " (id) VALUES (" + QString::number(v) + ")"));
|
||||
}
|
||||
values[i] = v;
|
||||
variantValues[i] = QVariant::fromValue(v);
|
||||
v += increment;
|
||||
}
|
||||
|
||||
// ensure we can read them back properly
|
||||
QVERIFY_SQL(q, exec("SELECT id FROM " + tableName));
|
||||
if (withPreparedStatement) {
|
||||
QVERIFY_SQL(q, prepare("SELECT id FROM " + tableName));
|
||||
QVERIFY_SQL(q, exec());
|
||||
} else {
|
||||
QVERIFY_SQL(q, exec("SELECT id FROM " + tableName));
|
||||
}
|
||||
QVector<T> actualValues;
|
||||
QVector<QVariant> actualVariantValues;
|
||||
actualValues.reserve(values.size());
|
||||
while (q.next()) {
|
||||
actualValues << q.value(0).value<T>();
|
||||
QVariant value = q.value(0);
|
||||
actualVariantValues << value;
|
||||
actualValues << value.value<T>();
|
||||
QVERIFY(actualVariantValues.last().userType() != qMetaTypeId<char>());
|
||||
QVERIFY(actualVariantValues.last().userType() != qMetaTypeId<signed char>());
|
||||
QVERIFY(actualVariantValues.last().userType() != qMetaTypeId<unsigned char>());
|
||||
}
|
||||
QCOMPARE(actualValues, values);
|
||||
QCOMPARE(actualVariantValues, variantValues);
|
||||
}
|
||||
|
||||
void tst_QSqlQuery::integralTypesMysql()
|
||||
@ -4046,16 +4061,18 @@ void tst_QSqlQuery::integralTypesMysql()
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const bool withPreparedStatement = (i == 1);
|
||||
runIntegralTypesMysqlTest<char>(db, "tinyIntTest", "TINYINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<unsigned char>(db, "unsignedTinyIntTest", "TINYINT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<char>(db, "smallIntTest", "SMALLINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<unsigned char>(db, "unsignedSmallIntTest", "SMALLINT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<int>(db, "mediumIntTest", "MEDIUMINT", withPreparedStatement, -(1 << 23), (1 << 23) - 1);
|
||||
runIntegralTypesMysqlTest<unsigned int>(db, "unsignedMediumIntTest", "MEDIUMINT UNSIGNED", withPreparedStatement, 0, (1 << 24) - 1);
|
||||
runIntegralTypesMysqlTest<int>(db, "intTest", "INT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<unsigned int>(db, "unsignedIntTest", "INT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<long long>(db, "bigIntTest", "BIGINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<unsigned long long>(db, "unsignedBigIntTest", "BIGINT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<bool>(db, "tinyInt1Test", "TINYINT(1)", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<bool>(db, "unsignedTinyInt1Test", "TINYINT(1) UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<qint8>(db, "tinyIntTest", "TINYINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<quint8>(db, "unsignedTinyIntTest", "TINYINT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<qint16>(db, "smallIntTest", "SMALLINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<quint16>(db, "unsignedSmallIntTest", "SMALLINT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<qint32>(db, "mediumIntTest", "MEDIUMINT", withPreparedStatement, -(1 << 23), (1 << 23) - 1);
|
||||
runIntegralTypesMysqlTest<quint32>(db, "unsignedMediumIntTest", "MEDIUMINT UNSIGNED", withPreparedStatement, 0, (1 << 24) - 1);
|
||||
runIntegralTypesMysqlTest<qint32>(db, "intTest", "INT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<quint32>(db, "unsignedIntTest", "INT UNSIGNED", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<qint64>(db, "bigIntTest", "BIGINT", withPreparedStatement);
|
||||
runIntegralTypesMysqlTest<quint64>(db, "unsignedBigIntTest", "BIGINT UNSIGNED", withPreparedStatement);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user