Skip to content

Commit cf9b384

Browse files
author
stoeckerb
committed
init v6.2
1 parent 8bc2d92 commit cf9b384

File tree

2 files changed

+91
-66
lines changed

2 files changed

+91
-66
lines changed

mysql/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
qt_internal_add_plugin(QMYSQLDriverPlugin
88
OUTPUT_NAME qsqlmysql
9-
TYPE sqldrivers
9+
PLUGIN_TYPE sqldrivers
1010
SOURCES
1111
main.cpp
1212
qsql_mysql.cpp qsql_mysql_p.h
@@ -22,3 +22,5 @@ qt_internal_add_plugin(QMYSQLDriverPlugin
2222

2323
#### Keys ignored in scope 1:.:.:mysql.pro:<TRUE>:
2424
# OTHER_FILES = "mysql.json"
25+
26+
qt_internal_force_macos_intel_arch(QMYSQLDriverPlugin)

mysql/qsql_mysql.cpp

Lines changed: 88 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ static inline QVariant qDateTimeFromString(QString &val)
121121
#endif
122122
}
123123

124+
// check if this client and server version of MySQL/MariaDB support prepared statements
125+
static inline bool checkPreparedQueries(MYSQL *mysql)
126+
{
127+
std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
128+
if (!stmt)
129+
return false;
130+
131+
static const char dummyQuery[] = "SELECT ? + ?";
132+
if (mysql_stmt_prepare(stmt.get(), dummyQuery, sizeof(dummyQuery) - 1))
133+
return false;
134+
135+
return mysql_stmt_param_count(stmt.get()) == 2;
136+
}
137+
124138
class QMYSQLResultPrivate;
125139

126140
class QMYSQLResult : public QSqlResult
@@ -172,7 +186,7 @@ class QMYSQLResultPrivate: public QSqlResultPrivate
172186
struct QMyField
173187
{
174188
char *outField = nullptr;
175-
MYSQL_FIELD *myField = nullptr;
189+
const MYSQL_FIELD *myField = nullptr;
176190
QMetaType type = QMetaType();
177191
my_bool nullIndicator = false;
178192
ulong bufLength = 0ul;
@@ -299,14 +313,10 @@ static bool qIsInteger(int t)
299313

300314
void QMYSQLResultPrivate::bindBlobs()
301315
{
302-
int i;
303-
MYSQL_FIELD *fieldInfo;
304-
MYSQL_BIND *bind;
305-
306-
for(i = 0; i < fields.count(); ++i) {
307-
fieldInfo = fields.at(i).myField;
316+
for (int i = 0; i < fields.count(); ++i) {
317+
const MYSQL_FIELD *fieldInfo = fields.at(i).myField;
308318
if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
309-
bind = &inBinds[i];
319+
MYSQL_BIND *bind = &inBinds[i];
310320
bind->buffer_length = fieldInfo->max_length;
311321
delete[] static_cast<char*>(bind->buffer);
312322
bind->buffer = new char[fieldInfo->max_length];
@@ -322,43 +332,40 @@ bool QMYSQLResultPrivate::bindInValues()
322332
if (!meta)
323333
return false;
324334

325-
MYSQL_BIND *bind;
326-
char *field;
327-
int i = 0;
328335
fields.resize(mysql_num_fields(meta));
329336

330337
inBinds = new MYSQL_BIND[fields.size()];
331338
memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND));
332339

333-
MYSQL_FIELD *fieldInfo;
340+
const MYSQL_FIELD *fieldInfo;
334341

342+
int i = 0;
335343
while((fieldInfo = mysql_fetch_field(meta))) {
344+
MYSQL_BIND *bind = &inBinds[i];
345+
336346
QMyField &f = fields[i];
337347
f.myField = fieldInfo;
338-
348+
bind->buffer_length = f.bufLength = fieldInfo->length + 1;
349+
bind->buffer_type = fieldInfo->type;
339350
f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags);
340351
if (qIsBlob(fieldInfo->type)) {
341352
// the size of a blob-field is available as soon as we call
342353
// mysql_stmt_store_result()
343354
// after mysql_stmt_exec() in QMYSQLResult::exec()
344-
fieldInfo->length = 0;
355+
bind->buffer_length = f.bufLength = 0;
345356
hasBlobs = true;
346357
} else if (qIsInteger(f.type.id())) {
347-
fieldInfo->length = 8;
358+
bind->buffer_length = f.bufLength = 8;
348359
} else {
349-
fieldInfo->type = MYSQL_TYPE_STRING;
360+
bind->buffer_type = MYSQL_TYPE_STRING;
350361
}
351-
bind = &inBinds[i];
352-
field = new char[fieldInfo->length + 1];
353-
memset(field, 0, fieldInfo->length + 1);
354362

355-
bind->buffer_type = fieldInfo->type;
356-
bind->buffer = field;
357-
bind->buffer_length = f.bufLength = fieldInfo->length + 1;
358363
bind->is_null = &f.nullIndicator;
359364
bind->length = &f.bufLength;
360365
bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0;
361-
f.outField=field;
366+
367+
char *field = new char[bind->buffer_length + 1]{};
368+
bind->buffer = f.outField = field;
362369

363370
++i;
364371
}
@@ -425,8 +432,8 @@ void QMYSQLResult::cleanup()
425432

426433
d->hasBlobs = false;
427434
d->fields.clear();
428-
d->result = NULL;
429-
d->row = NULL;
435+
d->result = nullptr;
436+
d->row = nullptr;
430437
setAt(-1);
431438
setActive(false);
432439
}
@@ -535,7 +542,7 @@ QVariant QMYSQLResult::data(int field)
535542
if (!driver())
536543
return QVariant();
537544

538-
int fieldLength = 0;
545+
my_ulonglong fieldLength = 0;
539546
const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
540547
QString val;
541548
if (d->preparedQuery) {
@@ -555,7 +562,7 @@ QVariant QMYSQLResult::data(int field)
555562
if (f.type.id() != QMetaType::QByteArray)
556563
val = QString::fromUtf8(f.outField, f.bufLength);
557564
} else {
558-
if (d->row[field] == NULL) {
565+
if (d->row[field] == nullptr) {
559566
// NULL value
560567
return QVariant(f.type);
561568
}
@@ -634,7 +641,7 @@ bool QMYSQLResult::isNull(int field)
634641
if (d->preparedQuery)
635642
return d->fields.at(field).nullIndicator;
636643
else
637-
return d->row[field] == NULL;
644+
return d->row[field] == nullptr;
638645
}
639646

640647
bool QMYSQLResult::reset (const QString& query)
@@ -1076,7 +1083,7 @@ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent)
10761083
Q_D(QMYSQLDriver);
10771084
init();
10781085
if (con) {
1079-
d->mysql = (MYSQL *) con;
1086+
d->mysql = con;
10801087
setOpen(true);
10811088
setOpenError(false);
10821089
if (qMySqlConnectionCount == 1)
@@ -1219,26 +1226,39 @@ bool QMYSQLDriver::open(const QString& db,
12191226
}
12201227
}
12211228

1222-
if (!(d->mysql = mysql_init((MYSQL*) 0))) {
1229+
if (!(d->mysql = mysql_init(nullptr))) {
12231230
setLastError(qMakeError(tr("Unable to allocate a MYSQL object"),
12241231
QSqlError::ConnectionError, d));
12251232
setOpenError(true);
12261233
return false;
12271234
}
12281235

1236+
// try utf8 with non BMP first, utf8 (BMP only) if that fails
1237+
static const char wanted_charsets[][8] = { "utf8mb4", "utf8" };
1238+
#ifdef MARIADB_VERSION_ID
1239+
MARIADB_CHARSET_INFO *cs = nullptr;
1240+
for (const char *p : wanted_charsets) {
1241+
cs = mariadb_get_charset_by_name(p);
1242+
if (cs) {
1243+
d->mysql->charset = cs;
1244+
break;
1245+
}
1246+
}
1247+
#else
1248+
// dummy
1249+
struct {
1250+
const char *csname;
1251+
} *cs = nullptr;
1252+
#endif
1253+
12291254
if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() ||
12301255
!sslCAPath.isNull() || !sslCipher.isNull()) {
12311256
mysql_ssl_set(d->mysql,
1232-
sslKey.isNull() ? static_cast<const char *>(0)
1233-
: QFile::encodeName(sslKey).constData(),
1234-
sslCert.isNull() ? static_cast<const char *>(0)
1235-
: QFile::encodeName(sslCert).constData(),
1236-
sslCA.isNull() ? static_cast<const char *>(0)
1237-
: QFile::encodeName(sslCA).constData(),
1238-
sslCAPath.isNull() ? static_cast<const char *>(0)
1239-
: QFile::encodeName(sslCAPath).constData(),
1240-
sslCipher.isNull() ? static_cast<const char *>(0)
1241-
: sslCipher.toLocal8Bit().constData());
1257+
sslKey.isNull() ? nullptr : sslKey.toUtf8().constData(),
1258+
sslCert.isNull() ? nullptr : sslCert.toUtf8().constData(),
1259+
sslCA.isNull() ? nullptr : sslCA.toUtf8().constData(),
1260+
sslCAPath.isNull() ? nullptr : sslCAPath.toUtf8().constData(),
1261+
sslCipher.isNull() ? nullptr : sslCipher.toUtf8().constData());
12421262
}
12431263

12441264
if (connectTimeout != 0)
@@ -1247,27 +1267,33 @@ bool QMYSQLDriver::open(const QString& db,
12471267
mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout);
12481268
if (writeTimeout != 0)
12491269
mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout);
1270+
12501271
MYSQL *mysql = mysql_real_connect(d->mysql,
1251-
host.isNull() ? static_cast<const char *>(0)
1252-
: host.toLocal8Bit().constData(),
1253-
user.isNull() ? static_cast<const char *>(0)
1254-
: user.toLocal8Bit().constData(),
1255-
password.isNull() ? static_cast<const char *>(0)
1256-
: password.toLocal8Bit().constData(),
1257-
db.isNull() ? static_cast<const char *>(0)
1258-
: db.toLocal8Bit().constData(),
1272+
host.isNull() ? nullptr : host.toUtf8().constData(),
1273+
user.isNull() ? nullptr : user.toUtf8().constData(),
1274+
password.isNull() ? nullptr : password.toUtf8().constData(),
1275+
db.isNull() ? nullptr : db.toUtf8().constData(),
12591276
(port > -1) ? port : 0,
1260-
unixSocket.isNull() ? static_cast<const char *>(0)
1261-
: unixSocket.toLocal8Bit().constData(),
1277+
unixSocket.isNull() ? nullptr : unixSocket.toUtf8().constData(),
12621278
optionFlags);
12631279

1264-
// try utf8 with non BMP first, utf8 (BMP only) if that fails
1265-
if (mysql_set_character_set(d->mysql, "utf8mb4"))
1266-
if (mysql_set_character_set(d->mysql, "utf8"))
1267-
qWarning() << "MySQL: Unable to set the client character set to utf8.";
1280+
// now ask the server to match the charset we selected
1281+
if (!cs || mysql_set_character_set(d->mysql, cs->csname)) {
1282+
bool ok = false;
1283+
for (const char *p : wanted_charsets) {
1284+
if (mysql_set_character_set(d->mysql, p)) {
1285+
ok = true;
1286+
break;
1287+
}
1288+
}
1289+
if (!ok)
1290+
qWarning("MySQL: Unable to set the client character set to utf8 (\"%s\"). Using '%s' instead.",
1291+
mysql_error(d->mysql),
1292+
mysql_character_set_name(d->mysql));
1293+
}
12681294

12691295
if (mysql == d->mysql) {
1270-
if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
1296+
if (!db.isEmpty() && mysql_select_db(d->mysql, db.toUtf8().constData())) {
12711297
setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d));
12721298
mysql_close(d->mysql);
12731299
setOpenError(true);
@@ -1279,7 +1305,7 @@ bool QMYSQLDriver::open(const QString& db,
12791305
setLastError(qMakeError(tr("Unable to connect"),
12801306
QSqlError::ConnectionError, d));
12811307
mysql_close(d->mysql);
1282-
d->mysql = NULL;
1308+
d->mysql = nullptr;
12831309
setOpenError(true);
12841310
return false;
12851311
}
@@ -1291,8 +1317,7 @@ bool QMYSQLDriver::open(const QString& db,
12911317
qWarning() << "MySQL: Unable to set the client character set to utf8.";
12921318
}
12931319

1294-
d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
1295-
&& mysql_get_server_version(d->mysql) >= 40100;
1320+
d->preparedQuerysEnabled = checkPreparedQueries(d->mysql);
12961321

12971322
#if QT_CONFIG(thread)
12981323
mysql_thread_init();
@@ -1311,7 +1336,7 @@ void QMYSQLDriver::close()
13111336
mysql_thread_end();
13121337
#endif
13131338
mysql_close(d->mysql);
1314-
d->mysql = NULL;
1339+
d->mysql = nullptr;
13151340
setOpen(false);
13161341
setOpenError(false);
13171342
}
@@ -1375,7 +1400,7 @@ QSqlRecord QMYSQLDriver::record(const QString& tablename) const
13751400
QSqlRecord info;
13761401
if (!isOpen())
13771402
return info;
1378-
MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
1403+
MYSQL_RES* r = mysql_list_fields(d->mysql, table.toUtf8().constData(), 0);
13791404
if (!r) {
13801405
return info;
13811406
}
@@ -1458,12 +1483,10 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
14581483
if (isOpen()) {
14591484
const QByteArray ba = field.value().toByteArray();
14601485
// buffer has to be at least length*2+1 bytes
1461-
char* buffer = new char[ba.size() * 2 + 1];
1462-
int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
1463-
ba.data(), ba.size()));
1486+
QVarLengthArray<char, 512> buffer(ba.size() * 2 + 1);
1487+
auto escapedSize = mysql_real_escape_string(d->mysql, buffer.data(), ba.data(), ba.size());
14641488
r.reserve(escapedSize + 3);
1465-
r.append(QLatin1Char('\'')).append(QString::fromUtf8(buffer)).append(QLatin1Char('\''));
1466-
delete[] buffer;
1489+
r = QLatin1Char('\'') + QString::fromUtf8(buffer) + QLatin1Char('\'');
14671490
break;
14681491
} else {
14691492
qWarning("QMYSQLDriver::formatValue: Database not open");

0 commit comments

Comments
 (0)