SQL/MySQL: retrieve default column value for QSqlDatabase::record()

Retrieve the default value (if set) of a column during
QSqlDatabase::record() but not for QSqlQuery::record() as it's done for
the other drivers which support retrieving the default column value.

Fixes: QTBUG-122723
Change-Id: I92e052bfa6d88e019c0151fbcbc1483a65770c55
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Christian Ehrlicher 2024-02-26 14:35:07 +01:00
parent 453e66c61b
commit e2e818483f
3 changed files with 39 additions and 3 deletions

View File

@ -1475,12 +1475,39 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString &tablename) const
QSqlRecord QMYSQLDriver::record(const QString &tablename) const QSqlRecord QMYSQLDriver::record(const QString &tablename) const
{ {
Q_D(const QMYSQLDriver);
if (!isOpen()) if (!isOpen())
return {}; return {};
QSqlQuery i(createResult()); QSqlQuery i(createResult());
QString stmt("SELECT * FROM %1 LIMIT 0"_L1); QString stmt("SELECT * FROM %1 LIMIT 0"_L1);
i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName))); i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName)));
return i.record(); auto r = i.record();
if (r.isEmpty())
return r;
// no binding of WHERE possible with MySQL
// escaping on WHERE clause does not work, so use mysql_real_escape_string()
stmt = "SELECT column_name, column_default FROM information_schema.columns WHERE table_name = '%1'"_L1;
const auto baTableName = tablename.toUtf8();
QVarLengthArray<char> tableNameQuoted(baTableName.size() * 2 + 1);
#if defined(MARIADB_VERSION_ID)
const auto len = mysql_real_escape_string(d->mysql, tableNameQuoted.data(),
baTableName.data(), baTableName.size());
#else
const auto len = mysql_real_escape_string_quote(d->mysql, tableNameQuoted.data(),
baTableName.data(), baTableName.size(), '\'');
#endif
if (i.exec(stmt.arg(QString::fromUtf8(tableNameQuoted.data(), len)))) {
while (i.next()) {
const auto colName = i.value(0).toString();
const auto recordIdx = r.indexOf(colName);
if (recordIdx >= 0) {
auto field = r.field(recordIdx);
field.setDefaultValue(i.value(1));
r.replace(recordIdx, field);
}
}
}
return r;
} }
QVariant QMYSQLDriver::handle() const QVariant QMYSQLDriver::handle() const

View File

@ -208,6 +208,8 @@ void QSqlField::setPrecision(int precision)
\since 6.8 \since 6.8
This property holds the default value for this field. This property holds the default value for this field.
Only some database drivers supports this property. Currently
those are SQLite, PostgreSQL, Oracle and MySQL/MariaDB.
*/ */
/*! /*!

View File

@ -35,6 +35,7 @@ static bool driverSupportsDefaultValues(QSqlDriver::DbmsType dbType)
case QSqlDriver::SQLite: case QSqlDriver::SQLite:
case QSqlDriver::PostgreSQL: case QSqlDriver::PostgreSQL:
case QSqlDriver::Oracle: case QSqlDriver::Oracle:
case QSqlDriver::MySqlServer:
return true; return true;
default: default:
break; break;
@ -132,8 +133,14 @@ void tst_QSqlDriver::record()
for (int i = 0; i < fields.size(); ++i) for (int i = 0; i < fields.size(); ++i)
QCOMPARE(rec.fieldName(i), fields[i]); QCOMPARE(rec.fieldName(i), fields[i]);
if (driverSupportsDefaultValues(dbType)) if (driverSupportsDefaultValues(dbType)) {
QCOMPARE(rec.field(QStringLiteral("name")).defaultValue().toString(), QStringLiteral("defaultVal")); auto defVal = rec.field(QStringLiteral("name")).defaultValue().toString();
if (dbType == QSqlDriver::MySqlServer && defVal.startsWith('\'') && defVal.endsWith('\'')) {
qDebug() << "MariaDB 10.6 default string value is escaped:" << defVal;
defVal = defVal.mid(1, defVal.size() - 2);
}
QCOMPARE(defVal, QStringLiteral("defaultVal"));
}
if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2) if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::DB2)
tablename = tablename.toUpper(); tablename = tablename.toUpper();