Always assume utf8 for the client connection with the mysql server

The code was already trying to set the client charset to utf8. Enforce
this further and issue a warning if it fails.

Remove the text codec dependencies and directly use to/fromUtf8().

Change-Id: Ib75e46aaf0d1a274f6832b19eb38623a5cae5eb3
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
bb10
Lars Knoll 2020-04-28 22:18:27 +02:00
parent 52053a8994
commit 8ab3b54fb7
1 changed files with 22 additions and 74 deletions

View File

@ -79,45 +79,11 @@ class QMYSQLDriverPrivate : public QSqlDriverPrivate
public:
QMYSQLDriverPrivate() : QSqlDriverPrivate(QSqlDriver::MySqlServer)
#if QT_CONFIG(textcodec)
, tc(QTextCodec::codecForLocale())
#endif
{}
MYSQL *mysql = nullptr;
QTextCodec *tc = nullptr;
bool preparedQuerysEnabled = false;
};
static inline QString toUnicode(QTextCodec *tc, const char *str)
{
#if !QT_CONFIG(textcodec)
Q_UNUSED(tc);
return QString::fromLatin1(str);
#else
return tc->toUnicode(str);
#endif
}
static inline QString toUnicode(QTextCodec *tc, const char *str, int length)
{
#if !QT_CONFIG(textcodec)
Q_UNUSED(tc);
return QString::fromLatin1(str, length);
#else
return tc->toUnicode(str, length);
#endif
}
static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str)
{
#if !QT_CONFIG(textcodec)
Q_UNUSED(tc);
return str.toLatin1();
#else
return tc->fromUnicode(str);
#endif
}
static inline QVariant qDateFromString(const QString &val)
{
#if !QT_CONFIG(datestring)
@ -228,22 +194,12 @@ public:
bool preparedQuery = false;
};
#if QT_CONFIG(textcodec)
static QTextCodec* codec(MYSQL* mysql)
{
QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql));
if (heuristicCodec)
return heuristicCodec;
return QTextCodec::codecForLocale();
}
#endif // textcodec
static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
const QMYSQLDriverPrivate* p)
{
const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
return QSqlError(QLatin1String("QMYSQL: ") + err,
p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
QString::fromUtf8(cerr),
type, QString::number(mysql_errno(p->mysql)));
}
@ -306,11 +262,11 @@ static QMetaType::Type qDecodeMYSQLType(int mysqltype, uint flags)
return type;
}
static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
static QSqlField qToField(MYSQL_FIELD *field)
{
QSqlField f(toUnicode(tc, field->name),
QSqlField f(QString::fromUtf8(field->name),
QVariant::Type(qDecodeMYSQLType(int(field->type), field->flags)),
toUnicode(tc, field->table));
QString::fromUtf8(field->table));
f.setRequired(IS_NOT_NULL(field->flags));
f.setLength(field->length);
f.setPrecision(field->decimals);
@ -609,7 +565,7 @@ QVariant QMYSQLResult::data(int field)
}
if (f.type != QMetaType::QByteArray)
val = toUnicode(d->drv_d_func()->tc, f.outField, f.bufLength);
val = QString::fromUtf8(f.outField, f.bufLength);
} else {
if (d->row[field] == NULL) {
// NULL value
@ -619,7 +575,7 @@ QVariant QMYSQLResult::data(int field)
fieldLength = mysql_fetch_lengths(d->result)[field];
if (f.type != QMetaType::QByteArray)
val = toUnicode(d->drv_d_func()->tc, d->row[field], fieldLength);
val = QString::fromUtf8(d->row[field], fieldLength);
}
switch (static_cast<int>(f.type)) {
@ -703,7 +659,7 @@ bool QMYSQLResult::reset (const QString& query)
cleanup();
const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
const QByteArray encQuery = query.toUtf8();
if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.length())) {
setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"),
QSqlError::StatementError, d->drv_d_func()));
@ -790,7 +746,7 @@ QSqlRecord QMYSQLResult::record() const
mysql_field_seek(res, 0);
MYSQL_FIELD* field = mysql_fetch_field(res);
while(field) {
info.append(qToField(field, d->drv_d_func()->tc));
info.append(qToField(field));
field = mysql_fetch_field(res);
}
}
@ -899,7 +855,7 @@ bool QMYSQLResult::prepare(const QString& query)
return false;
}
const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query));
const QByteArray encQuery = query.toUtf8();
r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length());
if (r != 0) {
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
@ -1017,7 +973,7 @@ bool QMYSQLResult::exec()
break;
case QMetaType::QString:
default: {
QByteArray ba = fromUnicode(d->drv_d_func()->tc, val.toString());
QByteArray ba = val.toString().toUtf8();
stringVector.append(ba);
currBind->buffer_type = MYSQL_TYPE_STRING;
currBind->buffer = const_cast<char *>(ba.constData());
@ -1142,9 +1098,6 @@ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent)
init();
if (con) {
d->mysql = (MYSQL *) con;
#if QT_CONFIG(textcodec)
d->tc = codec(con);
#endif
setOpen(true);
setOpenError(false);
if (qMySqlConnectionCount == 1)
@ -1334,6 +1287,11 @@ bool QMYSQLDriver::open(const QString& db,
: unixSocket.toLocal8Bit().constData(),
optionFlags);
// try utf8 with non BMP first, utf8 (BMP only) if that fails
if (mysql_set_character_set(d->mysql, "utf8mb4"))
if (mysql_set_character_set(d->mysql, "utf8"))
qWarning() << "MySQL: Unable to set the client character set to utf8.";
if (mysql == d->mysql) {
if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
@ -1354,22 +1312,12 @@ bool QMYSQLDriver::open(const QString& db,
return false;
}
#if MYSQL_VERSION_ID >= 50007
if (mysql_get_client_version() >= 50503 && mysql_get_server_version(d->mysql) >= 50503) {
// force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
mysql_set_character_set(d->mysql, "utf8mb4");
#if QT_CONFIG(textcodec)
d->tc = QTextCodec::codecForName("UTF-8");
#endif
} else
{
// force the communication to be utf8
mysql_set_character_set(d->mysql, "utf8");
#if QT_CONFIG(textcodec)
d->tc = codec(d->mysql);
#endif
// force the communication to be utf8mb4 (only utf8mb4 supports 4-byte characters)
if (mysql_set_character_set(d->mysql, "utf8mb4")) {
// this failed, try forcing it to utf (BMP only)
if (mysql_set_character_set(d->mysql, "utf8"))
qWarning() << "MySQL: Unable to set the client character set to utf8.";
}
#endif // MYSQL_VERSION_ID >= 50007
d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
&& mysql_get_server_version(d->mysql) >= 40100;
@ -1462,7 +1410,7 @@ QSqlRecord QMYSQLDriver::record(const QString& tablename) const
MYSQL_FIELD* field;
while ((field = mysql_fetch_field(r)))
info.append(qToField(field, d->tc));
info.append(qToField(field));
mysql_free_result(r);
return info;
}
@ -1551,7 +1499,7 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
ba.data(), ba.size()));
r.reserve(escapedSize + 3);
r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\''));
r.append(QLatin1Char('\'')).append(QString::fromUtf8(buffer)).append(QLatin1Char('\''));
delete[] buffer;
break;
} else {