21#include <QtSql/private/qsqldriver_p.h>
22#include <QtSql/private/qsqlresult_p.h>
27# define Q_NO_MYSQL_EMBEDDED
35#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID < 50709
36#define MYSQL_TYPE_JSON 245
41using my_bool =
decltype(mysql_stmt_bind_result(
nullptr,
nullptr));
58using namespace
Qt::StringLiterals;
67 MYSQL *mysql =
nullptr;
69 bool preparedQuerysEnabled =
false;
74#if !QT_CONFIG(datestring)
86#if !QT_CONFIG(datestring)
98#if !QT_CONFIG(datestring)
108 if (
val.size() == 14)
109 val.insert(4, u
'-').insert(7, u
'-').insert(10, u
'T').insert(13, u
':').insert(16, u
':');
111 if (!
val.endsWith(u
'Z'))
120 std::unique_ptr<MYSQL_STMT,
decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
124 static const char dummyQuery[] =
"SELECT ? + ?";
125 if (mysql_stmt_prepare(stmt.get(), dummyQuery,
sizeof(dummyQuery) - 1))
128 return mysql_stmt_param_count(stmt.get()) == 2;
134 std::unique_ptr<MYSQL_STMT,
decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
138 static const char query[] =
"SET time_zone = '+00:00'";
139 if (mysql_stmt_prepare(stmt.get(),
query,
sizeof(
query) - 1))
140 mysql_stmt_execute(stmt.get());
157 bool fetch(
int i) override;
162 bool isNull(
int field) override;
173 bool exec() override;
193 char *outField =
nullptr;
194 const MYSQL_FIELD *myField =
nullptr;
202 MYSQL_STMT *stmt =
nullptr;
203 MYSQL_RES *meta =
nullptr;
205 MYSQL_BIND *inBinds =
nullptr;
206 MYSQL_BIND *outBinds =
nullptr;
208 int rowsAffected = 0;
209 bool hasBlobs =
false;
210 bool preparedQuery =
false;
216 const char *cerr =
p->mysql ? mysql_error(
p->mysql) :
nullptr;
227 case MYSQL_TYPE_TINY:
228 type = (
flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char;
230 case MYSQL_TYPE_SHORT:
231 type = (
flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short;
233 case MYSQL_TYPE_LONG:
234 case MYSQL_TYPE_INT24:
235 type = (
flags & UNSIGNED_FLAG) ? QMetaType::UInt : QMetaType::Int;
237 case MYSQL_TYPE_YEAR:
238 type = QMetaType::Int;
241 case MYSQL_TYPE_LONGLONG:
242 type = (
flags & UNSIGNED_FLAG) ? QMetaType::ULongLong : QMetaType::LongLong;
244 case MYSQL_TYPE_FLOAT:
245 case MYSQL_TYPE_DOUBLE:
246 case MYSQL_TYPE_DECIMAL:
247 case MYSQL_TYPE_NEWDECIMAL:
248 type = QMetaType::Double;
250 case MYSQL_TYPE_DATE:
251 type = QMetaType::QDate;
253 case MYSQL_TYPE_TIME:
256 type = QMetaType::QString;
258 case MYSQL_TYPE_DATETIME:
259 case MYSQL_TYPE_TIMESTAMP:
260 type = QMetaType::QDateTime;
262 case MYSQL_TYPE_STRING:
263 case MYSQL_TYPE_VAR_STRING:
264 case MYSQL_TYPE_BLOB:
265 case MYSQL_TYPE_TINY_BLOB:
266 case MYSQL_TYPE_MEDIUM_BLOB:
267 case MYSQL_TYPE_LONG_BLOB:
268 case MYSQL_TYPE_GEOMETRY:
269 case MYSQL_TYPE_JSON:
270 type = (
flags & BINARY_FLAG) ? QMetaType::QByteArray : QMetaType::QString;
272 case MYSQL_TYPE_ENUM:
274 type = QMetaType::QString;
277 type = QMetaType::QString;
288 f.setRequired(IS_NOT_NULL(field->flags));
289 f.setLength(field->length);
290 f.setPrecision(field->decimals);
291 f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
298 const char *cerr = mysql_stmt_error(stmt);
306 return t == MYSQL_TYPE_TINY_BLOB
307 ||
t == MYSQL_TYPE_BLOB
308 ||
t == MYSQL_TYPE_MEDIUM_BLOB
309 ||
t == MYSQL_TYPE_LONG_BLOB
310 ||
t == MYSQL_TYPE_JSON;
317 return t == MYSQL_TYPE_DATE ||
t == MYSQL_TYPE_DATETIME ||
t == MYSQL_TYPE_TIMESTAMP;
322 return t == QMetaType::Char ||
t == QMetaType::UChar
323 ||
t == QMetaType::Short ||
t == QMetaType::UShort
324 ||
t == QMetaType::Int ||
t == QMetaType::UInt
325 ||
t == QMetaType::LongLong ||
t == QMetaType::ULongLong;
330 return type == MYSQL_TYPE_BIT;
335 for (
int i = 0;
i < fields.size(); ++
i) {
336 const MYSQL_FIELD *fieldInfo = fields.at(
i).myField;
337 if (
qIsBlob(inBinds[
i].buffer_type) && meta && fieldInfo) {
338 MYSQL_BIND *
bind = &inBinds[
i];
339 bind->buffer_length = fieldInfo->max_length;
340 delete[]
static_cast<char*
>(
bind->buffer);
341 bind->buffer =
new char[fieldInfo->max_length];
342 fields[
i].outField =
static_cast<char*
>(
bind->buffer);
350 meta = mysql_stmt_result_metadata(stmt);
354 fields.resize(mysql_num_fields(meta));
356 inBinds =
new MYSQL_BIND[fields.size()];
357 memset(inBinds, 0, fields.size() *
sizeof(MYSQL_BIND));
359 const MYSQL_FIELD *fieldInfo;
362 while((fieldInfo = mysql_fetch_field(meta))) {
363 MYSQL_BIND *
bind = &inBinds[
i];
367 bind->buffer_length =
f.bufLength = fieldInfo->length + 1;
368 bind->buffer_type = fieldInfo->type;
370 if (
qIsBlob(fieldInfo->type)) {
374 bind->buffer_length =
f.bufLength = 0;
379 bind->buffer_length =
f.bufLength = 8;
381 bind->buffer_type = MYSQL_TYPE_STRING;
384 bind->is_null = &
f.nullIndicator;
385 bind->length = &
f.bufLength;
386 bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0;
388 char *field =
bind->buffer_length ?
new char[
bind->buffer_length + 1]{} :
nullptr;
389 bind->buffer =
f.outField = field;
409 if (
d->preparedQuery)
419 mysql_free_result(
d->result);
423 while (
driver() &&
d->drv_d_func()->mysql && mysql_next_result(
d->drv_d_func()->mysql) == 0) {
424 MYSQL_RES *
res = mysql_store_result(
d->drv_d_func()->mysql);
426 mysql_free_result(
res);
430 if (mysql_stmt_close(
d->stmt))
431 qCWarning(lcMysql,
"QMYSQLResult::cleanup: unable to free statement handle");
436 mysql_free_result(
d->meta);
444 delete[]
d->outBinds;
477 if (
d->preparedQuery) {
478 mysql_stmt_data_seek(
d->stmt,
i);
480 int nRC = mysql_stmt_fetch(
d->stmt);
482 if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
488 mysql_data_seek(
d->result,
i);
489 d->row = mysql_fetch_row(
d->result);
503 if (
d->preparedQuery) {
504 int nRC = mysql_stmt_fetch(
d->stmt);
506 if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
512 d->row = mysql_fetch_row(
d->result);
531 my_ulonglong numRows =
d->preparedQuery ? mysql_stmt_num_rows(
d->stmt) : mysql_num_rows(
d->result);
532 if (
at() ==
int(numRows))
536 return fetch(numRows - 1);
549static inline uint64_t
553 const auto numBytes = (
f.myField->length + 7) / 8;
555 for (
unsigned long i = 0;
i < numBytes && outField; ++
i) {
556 uint64_t tmp =
static_cast<uint8_t
>(outField[
i]);
566 if (!
isSelect() || field >=
d->fields.size()) {
567 qCWarning(lcMysql,
"QMYSQLResult::data: column %d out of range", field);
574 my_ulonglong fieldLength = 0;
577 if (
d->preparedQuery) {
585 if (
f.type.id() == QMetaType::UChar)
587 else if (
f.type.id() == QMetaType::Char)
594 if (
f.type.id() != QMetaType::QTime)
596 if (
f.type.id() != QMetaType::QDate)
597 time =
QTime(
t->hour,
t->minute,
t->second,
t->second_part / 1000);
598 if (
f.type.id() == QMetaType::QDateTime)
600 else if (
f.type.id() == QMetaType::QDate)
606 if (
f.type.id() != QMetaType::QByteArray)
609 if (
d->row[field] ==
nullptr) {
617 fieldLength = mysql_fetch_lengths(
d->result)[field];
619 if (
f.type.id() != QMetaType::QByteArray)
623 switch (
f.type.id()) {
624 case QMetaType::LongLong:
626 case QMetaType::ULongLong:
628 case QMetaType::Char:
629 case QMetaType::Short:
632 case QMetaType::UChar:
633 case QMetaType::UShort:
634 case QMetaType::UInt:
636 case QMetaType::Double: {
660 case QMetaType::QDate:
662 case QMetaType::QTime:
664 case QMetaType::QDateTime:
666 case QMetaType::QByteArray: {
669 if (
d->preparedQuery) {
676 case QMetaType::QString:
686 if (field < 0 || field >=
d->fields.size())
688 if (
d->preparedQuery)
689 return d->fields.at(field).nullIndicator;
691 return d->row[field] ==
nullptr;
700 d->preparedQuery =
false;
705 if (mysql_real_query(
d->drv_d_func()->mysql, encQuery.data(), encQuery.size())) {
710 d->result = mysql_store_result(
d->drv_d_func()->mysql);
711 if (!
d->result && mysql_field_count(
d->drv_d_func()->mysql) > 0) {
716 int numFields = mysql_field_count(
d->drv_d_func()->mysql);
718 d->fields.resize(numFields);
719 d->rowsAffected = mysql_affected_rows(
d->drv_d_func()->mysql);
722 for(
int i = 0;
i < numFields;
i++) {
723 MYSQL_FIELD* field = mysql_fetch_field_direct(
d->result,
i);
725 d->fields[
i].myField = field;
737 if (
d->preparedQuery)
738 return mysql_stmt_num_rows(
d->stmt);
740 return int(mysql_num_rows(
d->result));
748 return d->rowsAffected;
755 if (
d->preparedQuery) {
756 mysql_stmt_free_result(
d->stmt);
766 if (
d->preparedQuery) {
767 quint64 id = mysql_stmt_insert_id(
d->stmt);
771 quint64 id = mysql_insert_id(
d->drv_d_func()->mysql);
786 res =
d->preparedQuery ?
d->meta :
d->result;
788 if (!mysql_errno(
d->drv_d_func()->mysql)) {
789 mysql_field_seek(
res, 0);
790 MYSQL_FIELD* field = mysql_fetch_field(
res);
793 field = mysql_fetch_field(
res);
796 mysql_field_seek(
res, 0);
810 mysql_free_result(
d->result);
818 int status = mysql_next_result(
d->drv_d_func()->mysql);
823 }
else if (status == -1) {
827 d->result = mysql_store_result(
d->drv_d_func()->mysql);
828 unsigned int numFields = mysql_field_count(
d->drv_d_func()->mysql);
829 if (!
d->result && numFields > 0) {
836 d->fields.resize(numFields);
837 d->rowsAffected = mysql_affected_rows(
d->drv_d_func()->mysql);
840 for (
unsigned int i = 0;
i < numFields;
i++) {
841 MYSQL_FIELD *field = mysql_fetch_field_direct(
d->result,
i);
843 d->fields[
i].myField = field;
863 if (!
d->drv_d_func()->preparedQuerysEnabled)
872 d->stmt = mysql_stmt_init(
d->drv_d_func()->mysql);
880 r = mysql_stmt_prepare(
d->stmt, encQuery.constData(), encQuery.size());
888 const auto paramCount = mysql_stmt_param_count(
d->stmt);
890 d->outBinds =
new MYSQL_BIND[paramCount]();
893 d->preparedQuery =
true;
902 if (!
d->preparedQuery)
908 QList<QT_MYSQL_TIME *> timeVector;
909 QList<QByteArray> stringVector;
910 QList<my_bool> nullVector;
914 r = mysql_stmt_reset(
d->stmt);
921 const unsigned long paramCount = mysql_stmt_param_count(
d->stmt);
922 if (paramCount > 0 && paramCount ==
static_cast<size_t>(
values.size())) {
923 nullVector.resize(
values.size());
926 void *
data =
const_cast<void *
>(
val.constData());
928 MYSQL_BIND* currBind = &
d->outBinds[
i];
931 currBind->is_null = &nullVector[
i];
932 currBind->length = 0;
933 currBind->is_unsigned = 0;
935 switch (
val.userType()) {
936 case QMetaType::QByteArray:
937 currBind->buffer_type = MYSQL_TYPE_BLOB;
938 currBind->buffer =
const_cast<char *
>(
val.toByteArray().constData());
942 case QMetaType::QTime:
943 case QMetaType::QDate:
944 case QMetaType::QDateTime: {
946 timeVector.append(myTime);
947 currBind->buffer = myTime;
952 if (
type == QMetaType::QTime) {
954 currBind->buffer_type = MYSQL_TYPE_TIME;
955 myTime->time_type = MYSQL_TIMESTAMP_TIME;
956 }
else if (
type == QMetaType::QDate) {
958 currBind->buffer_type = MYSQL_TYPE_DATE;
959 myTime->time_type = MYSQL_TIMESTAMP_DATE;
964 currBind->buffer_type = MYSQL_TYPE_DATETIME;
965 myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
968 if (
type == QMetaType::QTime ||
type == QMetaType::QDateTime) {
972 myTime->second_part =
time.
msec() * 1000;
974 if (
type == QMetaType::QDate ||
type == QMetaType::QDateTime) {
980 currBind->length = 0;
982 case QMetaType::UInt:
984 currBind->buffer_type = MYSQL_TYPE_LONG;
985 currBind->buffer =
data;
986 currBind->buffer_length =
sizeof(int);
987 currBind->is_unsigned = (
val.userType() != QMetaType::Int);
989 case QMetaType::Bool:
990 currBind->buffer_type = MYSQL_TYPE_TINY;
991 currBind->buffer =
data;
992 currBind->buffer_length =
sizeof(bool);
993 currBind->is_unsigned =
false;
995 case QMetaType::Double:
996 currBind->buffer_type = MYSQL_TYPE_DOUBLE;
997 currBind->buffer =
data;
998 currBind->buffer_length =
sizeof(double);
1000 case QMetaType::LongLong:
1001 case QMetaType::ULongLong:
1002 currBind->buffer_type = MYSQL_TYPE_LONGLONG;
1003 currBind->buffer =
data;
1004 currBind->buffer_length =
sizeof(
qint64);
1005 currBind->is_unsigned = (
val.userType() == QMetaType::ULongLong);
1007 case QMetaType::QString:
1011 currBind->buffer_type = MYSQL_TYPE_STRING;
1012 currBind->buffer =
const_cast<char *
>(
ba.
constData());
1013 currBind->buffer_length =
ba.
size();
1018#if defined(MARIADB_VERSION_ID) || MYSQL_VERSION_ID < 80300
1019 r = mysql_stmt_bind_param(
d->stmt,
d->outBinds);
1021 r = mysql_stmt_bind_named_param(
d->stmt,
d->outBinds, paramCount,
nullptr);
1030 r = mysql_stmt_execute(
d->stmt);
1042 d->rowsAffected = mysql_stmt_affected_rows(
d->stmt);
1045 my_bool update_max_length =
true;
1047 r = mysql_stmt_bind_result(
d->stmt,
d->inBinds);
1054 mysql_stmt_attr_set(
d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length);
1056 r = mysql_stmt_store_result(
d->stmt);
1068 r = mysql_stmt_bind_result(
d->stmt,
d->inBinds);
1088#ifndef Q_NO_MYSQL_EMBEDDED
1092 if (mysql_library_init(0, 0, 0)) {
1093 qCWarning(lcMysql,
"QMYSQLDriver::qServerInit: unable to start server.");
1097#if defined(MARIADB_BASE_VERSION) || defined(MARIADB_VERSION_ID)
1104#if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID)
1105# if !defined(Q_NO_MYSQL_EMBEDDED)
1106 mysql_library_end();
1139void QMYSQLDriver::init()
1159 if ((
d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS)
1178 return d->preparedQuerysEnabled;
1187 if (
opt ==
"CLIENT_COMPRESS"_L1)
1188 optionFlags |= CLIENT_COMPRESS;
1189 else if (
opt ==
"CLIENT_FOUND_ROWS"_L1)
1190 optionFlags |= CLIENT_FOUND_ROWS;
1191 else if (
opt ==
"CLIENT_IGNORE_SPACE"_L1)
1192 optionFlags |= CLIENT_IGNORE_SPACE;
1193 else if (
opt ==
"CLIENT_INTERACTIVE"_L1)
1194 optionFlags |= CLIENT_INTERACTIVE;
1195 else if (
opt ==
"CLIENT_NO_SCHEMA"_L1)
1196 optionFlags |= CLIENT_NO_SCHEMA;
1197 else if (
opt ==
"CLIENT_ODBC"_L1)
1198 optionFlags |= CLIENT_ODBC;
1199 else if (
opt ==
"CLIENT_SSL"_L1)
1200 qCWarning(lcMysql,
"QMYSQLDriver: MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT "
1201 "and MYSQL_OPT_SSL_CA should be used instead of CLIENT_SSL.");
1203 qCWarning(lcMysql,
"QMYSQLDriver::open: Unknown connect option '%ls'",
1209 return mysql_options(mysql,
option,
v.toUtf8().constData()) == 0;
1215 const auto val =
v.toInt(&bOk);
1216 return bOk ? mysql_options(mysql,
option, &
val) == 0 :
false;
1221 bool val = (
v.isEmpty() ||
v ==
"TRUE"_L1 ||
v ==
"1"_L1);
1222 return mysql_options(mysql,
option, &
val) == 0;
1226#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
1229 mysql_ssl_mode sslMode = SSL_MODE_DISABLED;
1230 if (
v ==
"DISABLED"_L1 ||
v ==
"SSL_MODE_DISABLED"_L1)
1231 sslMode = SSL_MODE_DISABLED;
1232 else if (
v ==
"PREFERRED"_L1 ||
v ==
"SSL_MODE_PREFERRED"_L1)
1233 sslMode = SSL_MODE_PREFERRED;
1234 else if (
v ==
"REQUIRED"_L1 ||
v ==
"SSL_MODE_REQUIRED"_L1)
1235 sslMode = SSL_MODE_REQUIRED;
1236 else if (
v ==
"VERIFY_CA"_L1 ||
v ==
"SSL_MODE_VERIFY_CA"_L1)
1237 sslMode = SSL_MODE_VERIFY_CA;
1238 else if (
v ==
"VERIFY_IDENTITY"_L1 ||
v ==
"SSL_MODE_VERIFY_IDENTITY"_L1)
1239 sslMode = SSL_MODE_VERIFY_IDENTITY;
1241 qCWarning(lcMysql,
"Unknown ssl mode '%ls' - using SSL_MODE_DISABLED",
1243 return mysql_options(mysql,
option, &sslMode) == 0;
1249 mysql_protocol_type proto = MYSQL_PROTOCOL_DEFAULT;
1250 if (
v ==
"TCP"_L1 ||
v ==
"MYSQL_PROTOCOL_TCP"_L1)
1251 proto = MYSQL_PROTOCOL_TCP;
1252 else if (
v ==
"SOCKET"_L1 ||
v ==
"MYSQL_PROTOCOL_SOCKET"_L1)
1253 proto = MYSQL_PROTOCOL_SOCKET;
1254 else if (
v ==
"PIPE"_L1 ||
v ==
"MYSQL_PROTOCOL_PIPE"_L1)
1255 proto = MYSQL_PROTOCOL_PIPE;
1256 else if (
v ==
"MEMORY"_L1 ||
v ==
"MYSQL_PROTOCOL_MEMORY"_L1)
1257 proto = MYSQL_PROTOCOL_MEMORY;
1258 else if (
v ==
"DEFAULT"_L1 ||
v ==
"MYSQL_PROTOCOL_DEFAULT"_L1)
1259 proto = MYSQL_PROTOCOL_DEFAULT;
1261 qCWarning(lcMysql,
"Unknown protocol '%ls' - using MYSQL_PROTOCOL_DEFAULT",
1263 return mysql_options(mysql,
option, &proto) == 0;
1277 if (!(
d->mysql = mysql_init(
nullptr))) {
1284 typedef bool (*SetOptionFunc)(MYSQL*, mysql_option,
QStringView);
1285 struct mysqloptions {
1290 const mysqloptions options[] = {
1303#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50710
1306#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
1307 {
"MYSQL_OPT_SSL_MODE"_L1, MYSQL_OPT_SSL_MODE, setOptionSslMode},
1309 {
"MYSQL_OPT_CONNECT_TIMEOUT"_L1, MYSQL_OPT_CONNECT_TIMEOUT,
setOptionInt},
1310 {
"MYSQL_OPT_READ_TIMEOUT"_L1, MYSQL_OPT_READ_TIMEOUT,
setOptionInt},
1311 {
"MYSQL_OPT_WRITE_TIMEOUT"_L1, MYSQL_OPT_WRITE_TIMEOUT,
setOptionInt},
1312 {
"MYSQL_OPT_RECONNECT"_L1, MYSQL_OPT_RECONNECT,
setOptionBool},
1313 {
"MYSQL_OPT_LOCAL_INFILE"_L1, MYSQL_OPT_LOCAL_INFILE,
setOptionInt},
1315 {
"MYSQL_SHARED_MEMORY_BASE_NAME"_L1, MYSQL_SHARED_MEMORY_BASE_NAME,
setOptionString},
1318 for (
const mysqloptions &
opt : options) {
1321 qCWarning(lcMysql,
"QMYSQLDriver::open: Could not set connect option value "
1336 unsigned int optionFlags = CLIENT_MULTI_STATEMENTS;
1341 for (
const auto &
option : opts) {
1344 if ((idx = sv.
indexOf(u
'=')) != -1) {
1347 if (trySetOption(
key,
val))
1349 else if (
key ==
"UNIX_SOCKET"_L1)
1350 unixSocket =
val.toString();
1351 else if (
val ==
"TRUE"_L1 ||
val ==
"1"_L1)
1354 qCWarning(lcMysql,
"QMYSQLDriver::open: Illegal connect option value '%ls'",
1362 static const char wanted_charsets[][8] = {
"utf8mb4",
"utf8" };
1363#ifdef MARIADB_VERSION_ID
1364 MARIADB_CHARSET_INFO *cs =
nullptr;
1365 for (
const char *
p : wanted_charsets) {
1366 cs = mariadb_get_charset_by_name(
p);
1368 d->mysql->charset = cs;
1379 MYSQL *mysql = mysql_real_connect(
d->mysql,
1388 if (mysql !=
d->mysql) {
1391 mysql_close(
d->mysql);
1398 if (!cs || mysql_set_character_set(
d->mysql, cs->csname) != 0) {
1400 for (
const char *
p : wanted_charsets) {
1401 if (mysql_set_character_set(
d->mysql,
p) == 0) {
1407 qCWarning(lcMysql,
"MySQL: Unable to set the client character set to utf8 (\"%s\"). "
1408 "Using '%s' instead.",
1409 mysql_error(
d->mysql),
1410 mysql_character_set_name(
d->mysql));
1413 if (!
db.isEmpty() && mysql_select_db(
d->mysql,
db.toUtf8().constData())) {
1415 mysql_close(
d->mysql);
1423 if (
d->preparedQuerysEnabled)
1426#if QT_CONFIG(thread)
1427 mysql_thread_init();
1439#if QT_CONFIG(thread)
1442 mysql_close(
d->mysql);
1461 QString sql =
"select table_name from information_schema.tables where table_schema = '"_L1 +
d->dbName +
"' and table_type = 'BASE TABLE'"_L1;
1465 tl.append(
q.value(0).toString());
1468 QString sql =
"select table_name from information_schema.tables where table_schema = '"_L1 +
d->dbName +
"' and table_type = 'VIEW'"_L1;
1472 tl.append(
q.value(0).toString());
1484 QString stmt(
"show index from %1;"_L1);
1487 while (
i.isActive() &&
i.next()) {
1488 if (
i.value(2).toString() ==
"PRIMARY"_L1) {
1489 idx.
append(fil.field(
i.value(4).toString()));
1491 idx.
setName(
i.value(2).toString());
1504 QString stmt(
"SELECT * FROM %1 LIMIT 0"_L1);
1506 auto r =
i.record();
1511 stmt =
"SELECT column_name, column_default FROM information_schema.columns WHERE table_name = '%1'"_L1;
1512 const auto baTableName = tablename.
toUtf8();
1513 QVarLengthArray<char> tableNameQuoted(baTableName.size() * 2 + 1);
1514#if defined(MARIADB_VERSION_ID)
1515 const auto len = mysql_real_escape_string(
d->mysql, tableNameQuoted.data(),
1516 baTableName.data(), baTableName.size());
1518 const auto len = mysql_real_escape_string_quote(
d->mysql, tableNameQuoted.data(),
1519 baTableName.data(), baTableName.size(),
'\'');
1523 const auto colName =
i.value(0).toString();
1524 const auto recordIdx =
r.indexOf(colName);
1525 if (recordIdx >= 0) {
1526 auto field =
r.field(recordIdx);
1527 field.setDefaultValue(
i.value(1));
1528 r.replace(recordIdx, field);
1545 qCWarning(lcMysql,
"QMYSQLDriver::beginTransaction: Database not open");
1548 if (mysql_query(
d->mysql,
"BEGIN WORK")) {
1560 qCWarning(lcMysql,
"QMYSQLDriver::commitTransaction: Database not open");
1563 if (mysql_query(
d->mysql,
"COMMIT")) {
1575 qCWarning(lcMysql,
"QMYSQLDriver::rollbackTransaction: Database not open");
1578 if (mysql_query(
d->mysql,
"ROLLBACK")) {
1594 case QMetaType::Double:
1597 case QMetaType::QString:
1600 r.replace(
"\\"_L1,
"\\\\"_L1);
1602 case QMetaType::QByteArray:
1607 auto escapedSize = mysql_real_escape_string(
d->mysql,
buffer.data(),
ba.
data(),
ba.
size());
1608 r.reserve(escapedSize + 3);
1612 qCWarning(lcMysql,
"QMYSQLDriver::formatValue: Database not open");
1615 case QMetaType::QDateTime:
1648 return identifier.
size() > 2
1655#include "moc_qsql_mysql_p.cpp"
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore\reentrant
QDateTime toUTC() const
Returns a copy of this datetime converted to UTC.
\inmodule QtCore \reentrant
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int day() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
const_reference at(qsizetype i) const noexcept
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts) override
Derived classes must reimplement this pure virtual function to open a database connection on database...
QSqlIndex primaryIndex(const QString &tablename) const override
Returns the primary index for table tableName.
void close() override
Derived classes must reimplement this pure virtual function in order to close the database connection...
QString escapeIdentifier(const QString &identifier, IdentifierType type) const override
Returns the identifier escaped according to the database rules.
QStringList tables(QSql::TableType) const override
Returns a list of the names of the tables in the database.
QString formatValue(const QSqlField &field, bool trimStrings) const override
Returns a string representation of the field value for the database.
QMYSQLDriver(QObject *parent=nullptr)
bool commitTransaction() override
This function is called to commit a transaction.
QVariant handle() const override
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
bool beginTransaction() override
This function is called to begin a transaction.
bool rollbackTransaction() override
This function is called to rollback a transaction.
bool hasFeature(DriverFeature f) const override
Returns true if the driver supports feature feature; otherwise returns false.
QSqlResult * createResult() const override
Creates an empty SQL result on the database.
bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override
Returns whether identifier is escaped according to the database rules.
QSqlRecord record(const QString &tablename) const override
Returns a QSqlRecord populated with the names of the fields in table tableName.
QMYSQLResult(const QMYSQLDriver *db)
QSqlRecord record() const override
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
bool exec() override
Executes the query, returning true if successful; otherwise returns false.
bool isNull(int field) override
Returns true if the field at position index in the current row is null; otherwise returns false.
int numRowsAffected() override
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
bool fetchNext() override
Positions the result to the next available record (row) in the result.
bool fetchFirst() override
Positions the result to the first record (row 0) in the result.
QVariant lastInsertId() const override
Returns the object ID of the most recent inserted row if the database supports it.
int size() override
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
bool reset(const QString &query) override
Sets the result to use the SQL statement query for subsequent data retrieval.
void virtual_hook(int id, void *data) override
QVariant data(int field) override
Returns the data for field index in the current row as a QVariant.
bool fetch(int i) override
Positions the result to an arbitrary (zero-based) row index.
QVariant handle() const override
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
bool fetchLast() override
Positions the result to the last record (last row) in the result.
bool prepare(const QString &stmt) override
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
void detachFromResultSet() override
bool nextResult() override
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
virtual QString formatValue(const QSqlField &field, bool trimStrings=false) const
Returns a string representation of the field value for the database.
IdentifierType
This enum contains a list of SQL identifier types.
DriverFeature
This enum contains a list of features a driver might support.
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database.
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
virtual void setOpen(bool o)
This function sets the open state of the database to open.
The QSqlError class provides SQL database error information.
ErrorType
This enum type describes the context in which the error occurred, e.g., a connection error,...
The QSqlField class manipulates the fields in SQL database tables and views.
bool isNull() const
Returns true if the field's value is NULL; otherwise returns false.
The QSqlIndex class provides functions to manipulate and describe database indexes.
void setName(const QString &name)
Sets \l name to name.
void setCursorName(const QString &cursorName)
Sets \l cursorName to cursorName.
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
The QSqlRecord class encapsulates a database record.
static bool isVariantNull(const QVariant &variant)
QSqlResultPrivate(QSqlResult *q, const QSqlDriver *drv)
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases.
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false.
virtual void virtual_hook(int id, void *data)
int at() const
Returns the current (zero-based) row position of the result.
virtual bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
virtual bool exec()
Executes the query, returning true if successful; otherwise returns false.
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index.
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active.
QVariantList & boundValues(QT6_DECL_NEW_OVERLOAD)
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
const QSqlDriver * driver() const
Returns the driver associated with the result.
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
constexpr QStringView left(qsizetype n) const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
QStringView trimmed() const noexcept
Strips leading and trailing whitespace and returns the result.
qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
bool isNull() const
Returns true if this string is null; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
\inmodule QtCore \reentrant
int hour() const
Returns the hour part (0 to 23) of the time.
int minute() const
Returns the minute part (0 to 59) of the time.
int msec() const
Returns the millisecond part (0 to 999) of the time.
int second() const
Returns the second part (0 to 59) of the time.
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has userType() \l QMetaType::QDateTime,...
double toDouble(bool *ok=nullptr) const
Returns the variant as a double if the variant has userType() \l QMetaType::Double,...
qlonglong toLongLong(bool *ok=nullptr) const
Returns the variant as a long long int if the variant has userType() \l QMetaType::LongLong,...
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
uint toUInt(bool *ok=nullptr) const
Returns the variant as an unsigned int if the variant has userType() \l QMetaType::UInt,...
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has userType() \l QMetaType::QByteArray or \l QMet...
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
void qAddPostRoutine(QtCleanUpFunction p)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLdouble GLdouble GLdouble GLdouble q
static void split(QT_FT_Vector *b)
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QDB2DriverPrivate *p)
static bool setOptionString(MYSQL *mysql, mysql_option option, QStringView v)
static bool qMySqlInitHandledByUser
static QVariant qTimeFromString(const QString &val)
static bool qIsTimeOrDate(enum_field_types t)
static void setOptionFlag(uint &optionFlags, QStringView opt)
static bool setOptionInt(MYSQL *mysql, mysql_option option, QStringView v)
static QVariant qDateTimeFromString(QString &val)
static bool setOptionBool(MYSQL *mysql, mysql_option option, QStringView v)
static bool checkPreparedQueries(MYSQL *mysql)
static bool qIsBlob(enum_field_types t)
static uint64_t qDecodeBitfield(const QMYSQLResultPrivate::QMyField &f, const char *outField)
static void setUtcTimeZone(MYSQL *mysql)
static bool qIsInteger(int t)
static void qLibraryInit()
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QMYSQLDriverPrivate *p)
static QVariant qDateFromString(const QString &val)
static bool qIsBitfield(enum_field_types type)
static int qMySqlConnectionCount
static QSqlError qMakeStmtError(const QString &err, QSqlError::ErrorType type, MYSQL_STMT *stmt)
static void qLibraryEnd()
static QSqlField qToField(MYSQL_FIELD *field)
static bool setOptionProtocol(MYSQL *mysql, mysql_option option, QStringView v)
static QMetaType qDecodeMYSQLType(enum_field_types mysqltype, uint flags)
decltype(mysql_stmt_bind_result(nullptr, nullptr)) my_bool
#define Q_DECLARE_SQLDRIVER_PRIVATE(Class)
#define qUtf16Printable(string)
#define QStringLiteral(str)
unsigned long long quint64
socketLayer bind(QHostAddress::Any, 4000)
const MYSQL_FIELD * myField
unsigned long second_part
enum enum_mysql_timestamp_type time_type