diff options
Diffstat (limited to 'src/sql/drivers/mysql')
-rw-r--r-- | src/sql/drivers/mysql/qsql_mysql.cpp | 1665 | ||||
-rw-r--r-- | src/sql/drivers/mysql/qsql_mysql.pri | 16 | ||||
-rw-r--r-- | src/sql/drivers/mysql/qsql_mysql_p.h | 110 |
3 files changed, 0 insertions, 1791 deletions
diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp deleted file mode 100644 index 56caf52dcb..0000000000 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ /dev/null @@ -1,1665 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsql_mysql_p.h" - -#include <qcoreapplication.h> -#include <qvariant.h> -#include <qdatetime.h> -#include <qsqlerror.h> -#include <qsqlfield.h> -#include <qsqlindex.h> -#include <qsqlquery.h> -#include <qsqlrecord.h> -#include <qstringlist.h> -#include <qtextcodec.h> -#include <qvector.h> -#include <qfile.h> -#include <qdebug.h> -#include <QtSql/private/qsqldriver_p.h> -#include <QtSql/private/qsqlresult_p.h> - -#ifdef Q_OS_WIN32 -// comment the next line out if you want to use MySQL/embedded on Win32 systems. -// note that it will crash if you don't statically link to the mysql/e library! -# define Q_NO_MYSQL_EMBEDDED -#endif - -Q_DECLARE_METATYPE(MYSQL_RES*) -Q_DECLARE_METATYPE(MYSQL*) - -#if MYSQL_VERSION_ID >= 40108 -Q_DECLARE_METATYPE(MYSQL_STMT*) -#endif - -#if MYSQL_VERSION_ID >= 40100 -# define Q_CLIENT_MULTI_STATEMENTS CLIENT_MULTI_STATEMENTS -#else -# define Q_CLIENT_MULTI_STATEMENTS 0 -#endif - -QT_BEGIN_NAMESPACE - -class QMYSQLDriverPrivate : public QSqlDriverPrivate -{ - Q_DECLARE_PUBLIC(QMYSQLDriver) - -public: - QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0), -#ifndef QT_NO_TEXTCODEC - tc(QTextCodec::codecForLocale()), -#else - tc(0), -#endif - preparedQuerysEnabled(false) { dbmsType = QSqlDriver::MySqlServer; } - MYSQL *mysql; - QTextCodec *tc; - - bool preparedQuerysEnabled; -}; - -static inline QString toUnicode(QTextCodec *tc, const char *str) -{ -#ifdef QT_NO_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) -{ -#ifdef QT_NO_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) -{ -#ifdef QT_NO_TEXTCODEC - Q_UNUSED(tc); - return str.toLatin1(); -#else - return tc->fromUnicode(str); -#endif -} - -static inline QVariant qDateFromString(const QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QDate()); - return QVariant(QDate::fromString(val, Qt::ISODate)); -#endif -} - -static inline QVariant qTimeFromString(const QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QTime()); - return QVariant(QTime::fromString(val, Qt::ISODate)); -#endif -} - -static inline QVariant qDateTimeFromString(QString &val) -{ -#ifdef QT_NO_DATESTRING - Q_UNUSED(val); - return QVariant(val); -#else - if (val.isEmpty()) - return QVariant(QDateTime()); - if (val.length() == 14) - // TIMESTAMPS have the format yyyyMMddhhmmss - val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10, - QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':')); - return QVariant(QDateTime::fromString(val, Qt::ISODate)); -#endif -} - -class QMYSQLResultPrivate; - -class QMYSQLResult : public QSqlResult -{ - Q_DECLARE_PRIVATE(QMYSQLResult) - friend class QMYSQLDriver; - -public: - explicit QMYSQLResult(const QMYSQLDriver *db); - ~QMYSQLResult(); - - QVariant handle() const Q_DECL_OVERRIDE; -protected: - void cleanup(); - bool fetch(int i) Q_DECL_OVERRIDE; - bool fetchNext() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - QVariant data(int field) Q_DECL_OVERRIDE; - bool isNull(int field) Q_DECL_OVERRIDE; - bool reset (const QString& query) Q_DECL_OVERRIDE; - int size() Q_DECL_OVERRIDE; - int numRowsAffected() Q_DECL_OVERRIDE; - QVariant lastInsertId() const Q_DECL_OVERRIDE; - QSqlRecord record() const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - bool nextResult() Q_DECL_OVERRIDE; - -#if MYSQL_VERSION_ID >= 40108 - bool prepare(const QString &stmt) Q_DECL_OVERRIDE; - bool exec() Q_DECL_OVERRIDE; -#endif -}; - -class QMYSQLResultPrivate: public QSqlResultPrivate -{ - Q_DECLARE_PUBLIC(QMYSQLResult) - -public: - Q_DECLARE_SQLDRIVER_PRIVATE(QMYSQLDriver) - - QMYSQLResultPrivate(QMYSQLResult *q, const QMYSQLDriver *drv) - : QSqlResultPrivate(q, drv), - result(0), - rowsAffected(0), - hasBlobs(false) -#if MYSQL_VERSION_ID >= 40108 - , stmt(0), meta(0), inBinds(0), outBinds(0) -#endif - , preparedQuery(false) - { } - - MYSQL_RES *result; - MYSQL_ROW row; - - int rowsAffected; - - bool bindInValues(); - void bindBlobs(); - - bool hasBlobs; - struct QMyField - { - QMyField() - : outField(0), nullIndicator(false), bufLength(0ul), - myField(0), type(QVariant::Invalid) - {} - char *outField; - my_bool nullIndicator; - ulong bufLength; - MYSQL_FIELD *myField; - QVariant::Type type; - }; - - QVector<QMyField> fields; - -#if MYSQL_VERSION_ID >= 40108 - MYSQL_STMT* stmt; - MYSQL_RES* meta; - - MYSQL_BIND *inBinds; - MYSQL_BIND *outBinds; -#endif - - bool preparedQuery; -}; - -#ifndef QT_NO_TEXTCODEC -static QTextCodec* codec(MYSQL* mysql) -{ -#if MYSQL_VERSION_ID >= 32321 - QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql)); - if (heuristicCodec) - return heuristicCodec; -#endif - return QTextCodec::codecForLocale(); -} -#endif // QT_NO_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), - type, mysql_errno(p->mysql)); -} - - -static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags) -{ - QVariant::Type type; - switch (mysqltype) { - case FIELD_TYPE_TINY : - type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UChar : QMetaType::Char); - break; - case FIELD_TYPE_SHORT : - type = static_cast<QVariant::Type>((flags & UNSIGNED_FLAG) ? QMetaType::UShort : QMetaType::Short); - break; - case FIELD_TYPE_LONG : - case FIELD_TYPE_INT24 : - type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int; - break; - case FIELD_TYPE_YEAR : - type = QVariant::Int; - break; - case FIELD_TYPE_LONGLONG : - type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong; - break; - case FIELD_TYPE_FLOAT : - case FIELD_TYPE_DOUBLE : - case FIELD_TYPE_DECIMAL : -#if defined(FIELD_TYPE_NEWDECIMAL) - case FIELD_TYPE_NEWDECIMAL: -#endif - type = QVariant::Double; - break; - case FIELD_TYPE_DATE : - type = QVariant::Date; - break; - case FIELD_TYPE_TIME : - type = QVariant::Time; - break; - case FIELD_TYPE_DATETIME : - case FIELD_TYPE_TIMESTAMP : - type = QVariant::DateTime; - break; - case FIELD_TYPE_STRING : - case FIELD_TYPE_VAR_STRING : - case FIELD_TYPE_BLOB : - case FIELD_TYPE_TINY_BLOB : - case FIELD_TYPE_MEDIUM_BLOB : - case FIELD_TYPE_LONG_BLOB : - type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::String; - break; - default: - case FIELD_TYPE_ENUM : - case FIELD_TYPE_SET : - type = QVariant::String; - break; - } - return type; -} - -static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc) -{ - QSqlField f(toUnicode(tc, field->name), - qDecodeMYSQLType(int(field->type), field->flags)); - f.setRequired(IS_NOT_NULL(field->flags)); - f.setLength(field->length); - f.setPrecision(field->decimals); - f.setSqlType(field->type); - f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG); - return f; -} - -#if MYSQL_VERSION_ID >= 40108 - -static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type, - MYSQL_STMT* stmt) -{ - const char *cerr = mysql_stmt_error(stmt); - return QSqlError(QLatin1String("QMYSQL3: ") + err, - QString::fromLatin1(cerr), - type, mysql_stmt_errno(stmt)); -} - -static bool qIsBlob(int t) -{ - return t == MYSQL_TYPE_TINY_BLOB - || t == MYSQL_TYPE_BLOB - || t == MYSQL_TYPE_MEDIUM_BLOB - || t == MYSQL_TYPE_LONG_BLOB; -} - -static bool qIsInteger(int t) -{ - return t == QMetaType::Char || t == QMetaType::UChar - || t == QMetaType::Short || t == QMetaType::UShort - || t == QMetaType::Int || t == QMetaType::UInt - || t == QMetaType::LongLong || t == QMetaType::ULongLong; -} - -void QMYSQLResultPrivate::bindBlobs() -{ - int i; - MYSQL_FIELD *fieldInfo; - MYSQL_BIND *bind; - - for(i = 0; i < fields.count(); ++i) { - fieldInfo = fields.at(i).myField; - if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) { - bind = &inBinds[i]; - bind->buffer_length = fieldInfo->max_length; - delete[] static_cast<char*>(bind->buffer); - bind->buffer = new char[fieldInfo->max_length]; - fields[i].outField = static_cast<char*>(bind->buffer); - } - } -} - -bool QMYSQLResultPrivate::bindInValues() -{ - MYSQL_BIND *bind; - char *field; - int i = 0; - - if (!meta) - meta = mysql_stmt_result_metadata(stmt); - if (!meta) - return false; - - fields.resize(mysql_num_fields(meta)); - - inBinds = new MYSQL_BIND[fields.size()]; - memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND)); - - MYSQL_FIELD *fieldInfo; - - while((fieldInfo = mysql_fetch_field(meta))) { - QMyField &f = fields[i]; - f.myField = fieldInfo; - - f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags); - if (qIsBlob(fieldInfo->type)) { - // the size of a blob-field is available as soon as we call - // mysql_stmt_store_result() - // after mysql_stmt_exec() in QMYSQLResult::exec() - fieldInfo->length = 0; - hasBlobs = true; - } else if (qIsInteger(f.type)) { - fieldInfo->length = 8; - } else { - fieldInfo->type = MYSQL_TYPE_STRING; - } - bind = &inBinds[i]; - field = new char[fieldInfo->length + 1]; - memset(field, 0, fieldInfo->length + 1); - - bind->buffer_type = fieldInfo->type; - bind->buffer = field; - bind->buffer_length = f.bufLength = fieldInfo->length + 1; - bind->is_null = &f.nullIndicator; - bind->length = &f.bufLength; - f.outField=field; - - ++i; - } - return true; -} -#endif - -QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db) - : QSqlResult(*new QMYSQLResultPrivate(this, db)) -{ -} - -QMYSQLResult::~QMYSQLResult() -{ - cleanup(); -} - -QVariant QMYSQLResult::handle() const -{ - Q_D(const QMYSQLResult); -#if MYSQL_VERSION_ID >= 40108 - if(d->preparedQuery) - return d->meta ? QVariant::fromValue(d->meta) : QVariant::fromValue(d->stmt); - else -#endif - return QVariant::fromValue(d->result); -} - -void QMYSQLResult::cleanup() -{ - Q_D(QMYSQLResult); - if (d->result) - mysql_free_result(d->result); - -// must iterate trough leftover result sets from multi-selects or stored procedures -// if this isn't done subsequent queries will fail with "Commands out of sync" -#if MYSQL_VERSION_ID >= 40100 - while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) { - MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql); - if (res) - mysql_free_result(res); - } -#endif - -#if MYSQL_VERSION_ID >= 40108 - if (d->stmt) { - if (mysql_stmt_close(d->stmt)) - qWarning("QMYSQLResult::cleanup: unable to free statement handle"); - d->stmt = 0; - } - - if (d->meta) { - mysql_free_result(d->meta); - d->meta = 0; - } - - int i; - for (i = 0; i < d->fields.count(); ++i) - delete[] d->fields[i].outField; - - if (d->outBinds) { - delete[] d->outBinds; - d->outBinds = 0; - } - - if (d->inBinds) { - delete[] d->inBinds; - d->inBinds = 0; - } -#endif - - d->hasBlobs = false; - d->fields.clear(); - d->result = NULL; - d->row = NULL; - setAt(-1); - setActive(false); -} - -bool QMYSQLResult::fetch(int i) -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; - if (isForwardOnly()) { // fake a forward seek - if (at() < i) { - int x = i - at(); - while (--x && fetchNext()) {}; - return fetchNext(); - } else { - return false; - } - } - if (at() == i) - return true; - if (d->preparedQuery) { -#if MYSQL_VERSION_ID >= 40108 - mysql_stmt_data_seek(d->stmt, i); - - int nRC = mysql_stmt_fetch(d->stmt); - if (nRC) { -#ifdef MYSQL_DATA_TRUNCATED - if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED) -#else - if (nRC == 1) -#endif - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to fetch data"), QSqlError::StatementError, d->stmt)); - return false; - } -#else - return false; -#endif - } else { - mysql_data_seek(d->result, i); - d->row = mysql_fetch_row(d->result); - if (!d->row) - return false; - } - - setAt(i); - return true; -} - -bool QMYSQLResult::fetchNext() -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; - if (d->preparedQuery) { -#if MYSQL_VERSION_ID >= 40108 - int nRC = mysql_stmt_fetch(d->stmt); - if (nRC) { -#ifdef MYSQL_DATA_TRUNCATED - if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED) -#else - if (nRC == 1) -#endif // MYSQL_DATA_TRUNCATED - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to fetch data"), QSqlError::StatementError, d->stmt)); - return false; - } -#else - return false; -#endif - } else { - d->row = mysql_fetch_row(d->result); - if (!d->row) - return false; - } - setAt(at() + 1); - return true; -} - -bool QMYSQLResult::fetchLast() -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; - if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries - bool success = fetchNext(); // did we move at all? - while (fetchNext()) {}; - return success; - } - - my_ulonglong numRows; - if (d->preparedQuery) { -#if MYSQL_VERSION_ID >= 40108 - numRows = mysql_stmt_num_rows(d->stmt); -#else - numRows = 0; -#endif - } else { - numRows = mysql_num_rows(d->result); - } - if (at() == int(numRows)) - return true; - if (!numRows) - return false; - return fetch(numRows - 1); -} - -bool QMYSQLResult::fetchFirst() -{ - if (at() == 0) - return true; - - if (isForwardOnly()) - return (at() == QSql::BeforeFirstRow) ? fetchNext() : false; - return fetch(0); -} - -QVariant QMYSQLResult::data(int field) -{ - Q_D(QMYSQLResult); - if (!isSelect() || field >= d->fields.count()) { - qWarning("QMYSQLResult::data: column %d out of range", field); - return QVariant(); - } - - if (!driver()) - return QVariant(); - - int fieldLength = 0; - const QMYSQLResultPrivate::QMyField &f = d->fields.at(field); - QString val; - if (d->preparedQuery) { - if (f.nullIndicator) - return QVariant(f.type); - - if (qIsInteger(f.type)) - return QVariant(f.type, f.outField); - - if (f.type != QVariant::ByteArray) - val = toUnicode(d->drv_d_func()->tc, f.outField, f.bufLength); - } else { - if (d->row[field] == NULL) { - // NULL value - return QVariant(f.type); - } - - fieldLength = mysql_fetch_lengths(d->result)[field]; - - if (f.type != QVariant::ByteArray) - val = toUnicode(d->drv_d_func()->tc, d->row[field], fieldLength); - } - - switch (static_cast<int>(f.type)) { - case QVariant::LongLong: - return QVariant(val.toLongLong()); - case QVariant::ULongLong: - return QVariant(val.toULongLong()); - case QMetaType::Char: - case QMetaType::Short: - case QVariant::Int: - return QVariant(val.toInt()); - case QMetaType::UChar: - case QMetaType::UShort: - case QVariant::UInt: - return QVariant(val.toUInt()); - case QVariant::Double: { - QVariant v; - bool ok=false; - double dbl = val.toDouble(&ok); - switch(numericalPrecisionPolicy()) { - case QSql::LowPrecisionInt32: - v=QVariant(dbl).toInt(); - break; - case QSql::LowPrecisionInt64: - v = QVariant(dbl).toLongLong(); - break; - case QSql::LowPrecisionDouble: - v = QVariant(dbl); - break; - case QSql::HighPrecision: - default: - v = val; - ok = true; - break; - } - if(ok) - return v; - else - return QVariant(); - } - return QVariant(val.toDouble()); - case QVariant::Date: - return qDateFromString(val); - case QVariant::Time: - return qTimeFromString(val); - case QVariant::DateTime: - return qDateTimeFromString(val); - case QVariant::ByteArray: { - - QByteArray ba; - if (d->preparedQuery) { - ba = QByteArray(f.outField, f.bufLength); - } else { - ba = QByteArray(d->row[field], fieldLength); - } - return QVariant(ba); - } - default: - case QVariant::String: - return QVariant(val); - } - qWarning("QMYSQLResult::data: unknown data type"); - return QVariant(); -} - -bool QMYSQLResult::isNull(int field) -{ - Q_D(const QMYSQLResult); - if (field < 0 || field >= d->fields.count()) - return true; - if (d->preparedQuery) - return d->fields.at(field).nullIndicator; - else - return d->row[field] == NULL; -} - -bool QMYSQLResult::reset (const QString& query) -{ - Q_D(QMYSQLResult); - if (!driver() || !driver()->isOpen() || driver()->isOpenError()) - return false; - - d->preparedQuery = false; - - cleanup(); - - const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query)); - 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())); - return false; - } - d->result = mysql_store_result(d->drv_d_func()->mysql); - if (!d->result && mysql_field_count(d->drv_d_func()->mysql) > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), - QSqlError::StatementError, d->drv_d_func())); - return false; - } - int numFields = mysql_field_count(d->drv_d_func()->mysql); - setSelect(numFields != 0); - d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql); - - if (isSelect()) { - for(int i = 0; i < numFields; i++) { - MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); - d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); - } - setAt(QSql::BeforeFirstRow); - } - setActive(true); - return isActive(); -} - -int QMYSQLResult::size() -{ - Q_D(const QMYSQLResult); - if (driver() && isSelect()) - if (d->preparedQuery) -#if MYSQL_VERSION_ID >= 40108 - return mysql_stmt_num_rows(d->stmt); -#else - return -1; -#endif - else - return int(mysql_num_rows(d->result)); - else - return -1; -} - -int QMYSQLResult::numRowsAffected() -{ - Q_D(const QMYSQLResult); - return d->rowsAffected; -} - -QVariant QMYSQLResult::lastInsertId() const -{ - Q_D(const QMYSQLResult); - if (!isActive() || !driver()) - return QVariant(); - - if (d->preparedQuery) { -#if MYSQL_VERSION_ID >= 40108 - quint64 id = mysql_stmt_insert_id(d->stmt); - if (id) - return QVariant(id); -#endif - } else { - quint64 id = mysql_insert_id(d->drv_d_func()->mysql); - if (id) - return QVariant(id); - } - return QVariant(); -} - -QSqlRecord QMYSQLResult::record() const -{ - Q_D(const QMYSQLResult); - QSqlRecord info; - MYSQL_RES *res; - if (!isActive() || !isSelect() || !driver()) - return info; - -#if MYSQL_VERSION_ID >= 40108 - res = d->preparedQuery ? d->meta : d->result; -#else - res = d->result; -#endif - - if (!mysql_errno(d->drv_d_func()->mysql)) { - mysql_field_seek(res, 0); - MYSQL_FIELD* field = mysql_fetch_field(res); - while(field) { - info.append(qToField(field, d->drv_d_func()->tc)); - field = mysql_fetch_field(res); - } - } - mysql_field_seek(res, 0); - return info; -} - -bool QMYSQLResult::nextResult() -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; -#if MYSQL_VERSION_ID >= 40100 - setAt(-1); - setActive(false); - - if (d->result && isSelect()) - mysql_free_result(d->result); - d->result = 0; - setSelect(false); - - for (int i = 0; i < d->fields.count(); ++i) - delete[] d->fields[i].outField; - d->fields.clear(); - - int status = mysql_next_result(d->drv_d_func()->mysql); - if (status > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), - QSqlError::StatementError, d->drv_d_func())); - return false; - } else if (status == -1) { - return false; // No more result sets - } - - d->result = mysql_store_result(d->drv_d_func()->mysql); - int numFields = mysql_field_count(d->drv_d_func()->mysql); - if (!d->result && numFields > 0) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), - QSqlError::StatementError, d->drv_d_func())); - return false; - } - - setSelect(numFields > 0); - d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql); - - if (isSelect()) { - for (int i = 0; i < numFields; i++) { - MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); - d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); - } - } - - setActive(true); - return true; -#else - return false; -#endif -} - -void QMYSQLResult::virtual_hook(int id, void *data) -{ - QSqlResult::virtual_hook(id, data); -} - - -#if MYSQL_VERSION_ID >= 40108 - -static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type) -{ - Q_ASSERT(type == QVariant::Time || type == QVariant::Date - || type == QVariant::DateTime); - - MYSQL_TIME *myTime = new MYSQL_TIME; - memset(myTime, 0, sizeof(MYSQL_TIME)); - - if (type == QVariant::Time || type == QVariant::DateTime) { - myTime->hour = time.hour(); - myTime->minute = time.minute(); - myTime->second = time.second(); - myTime->second_part = time.msec() * 1000; - } - if (type == QVariant::Date || type == QVariant::DateTime) { - myTime->year = date.year(); - myTime->month = date.month(); - myTime->day = date.day(); - } - - return myTime; -} - -bool QMYSQLResult::prepare(const QString& query) -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; -#if MYSQL_VERSION_ID >= 40108 - cleanup(); - if (!d->drv_d_func()->preparedQuerysEnabled) - return QSqlResult::prepare(query); - - int r; - - if (query.isEmpty()) - return false; - - if (!d->stmt) - d->stmt = mysql_stmt_init(d->drv_d_func()->mysql); - if (!d->stmt) { - setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), - QSqlError::StatementError, d->drv_d_func())); - return false; - } - - const QByteArray encQuery(fromUnicode(d->drv_d_func()->tc, query)); - r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length()); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to prepare statement"), QSqlError::StatementError, d->stmt)); - cleanup(); - return false; - } - - if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues - d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)]; - } - - setSelect(d->bindInValues()); - d->preparedQuery = true; - return true; -#else - return false; -#endif -} - -bool QMYSQLResult::exec() -{ - Q_D(QMYSQLResult); - if (!driver()) - return false; - if (!d->preparedQuery) - return QSqlResult::exec(); - if (!d->stmt) - return false; - - int r = 0; - MYSQL_BIND* currBind; - QVector<MYSQL_TIME *> timeVector; - QVector<QByteArray> stringVector; - QVector<my_bool> nullVector; - - const QVector<QVariant> values = boundValues(); - - r = mysql_stmt_reset(d->stmt); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to reset statement"), QSqlError::StatementError, d->stmt)); - return false; - } - - if (mysql_stmt_param_count(d->stmt) > 0 && - mysql_stmt_param_count(d->stmt) == (uint)values.count()) { - - nullVector.resize(values.count()); - for (int i = 0; i < values.count(); ++i) { - const QVariant &val = boundValues().at(i); - void *data = const_cast<void *>(val.constData()); - - currBind = &d->outBinds[i]; - - nullVector[i] = static_cast<my_bool>(val.isNull()); - currBind->is_null = &nullVector[i]; - currBind->length = 0; - currBind->is_unsigned = 0; - - switch (val.type()) { - case QVariant::ByteArray: - currBind->buffer_type = MYSQL_TYPE_BLOB; - currBind->buffer = const_cast<char *>(val.toByteArray().constData()); - currBind->buffer_length = val.toByteArray().size(); - break; - - case QVariant::Time: - case QVariant::Date: - case QVariant::DateTime: { - MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.type()); - timeVector.append(myTime); - - currBind->buffer = myTime; - switch(val.type()) { - case QVariant::Time: - currBind->buffer_type = MYSQL_TYPE_TIME; - myTime->time_type = MYSQL_TIMESTAMP_TIME; - break; - case QVariant::Date: - currBind->buffer_type = MYSQL_TYPE_DATE; - myTime->time_type = MYSQL_TIMESTAMP_DATE; - break; - case QVariant::DateTime: - currBind->buffer_type = MYSQL_TYPE_DATETIME; - myTime->time_type = MYSQL_TIMESTAMP_DATETIME; - break; - default: - break; - } - currBind->buffer_length = sizeof(MYSQL_TIME); - currBind->length = 0; - break; } - case QVariant::UInt: - case QVariant::Int: - currBind->buffer_type = MYSQL_TYPE_LONG; - currBind->buffer = data; - currBind->buffer_length = sizeof(int); - currBind->is_unsigned = (val.type() != QVariant::Int); - break; - case QVariant::Bool: - currBind->buffer_type = MYSQL_TYPE_TINY; - currBind->buffer = data; - currBind->buffer_length = sizeof(bool); - currBind->is_unsigned = false; - break; - case QVariant::Double: - currBind->buffer_type = MYSQL_TYPE_DOUBLE; - currBind->buffer = data; - currBind->buffer_length = sizeof(double); - break; - case QVariant::LongLong: - case QVariant::ULongLong: - currBind->buffer_type = MYSQL_TYPE_LONGLONG; - currBind->buffer = data; - currBind->buffer_length = sizeof(qint64); - currBind->is_unsigned = (val.type() == QVariant::ULongLong); - break; - case QVariant::String: - default: { - QByteArray ba = fromUnicode(d->drv_d_func()->tc, val.toString()); - stringVector.append(ba); - currBind->buffer_type = MYSQL_TYPE_STRING; - currBind->buffer = const_cast<char *>(ba.constData()); - currBind->buffer_length = ba.length(); - break; } - } - } - - r = mysql_stmt_bind_param(d->stmt, d->outBinds); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind value"), QSqlError::StatementError, d->stmt)); - qDeleteAll(timeVector); - return false; - } - } - r = mysql_stmt_execute(d->stmt); - - qDeleteAll(timeVector); - - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to execute statement"), QSqlError::StatementError, d->stmt)); - return false; - } - //if there is meta-data there is also data - setSelect(d->meta); - - d->rowsAffected = mysql_stmt_affected_rows(d->stmt); - - if (isSelect()) { - my_bool update_max_length = true; - - r = mysql_stmt_bind_result(d->stmt, d->inBinds); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); - return false; - } - if (d->hasBlobs) - mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length); - - r = mysql_stmt_store_result(d->stmt); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to store statement results"), QSqlError::StatementError, d->stmt)); - return false; - } - - if (d->hasBlobs) { - // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes - // when called without a preceding call to mysql_stmt_bind_result() - // in versions < 4.1.8 - d->bindBlobs(); - r = mysql_stmt_bind_result(d->stmt, d->inBinds); - if (r != 0) { - setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", - "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); - return false; - } - } - setAt(QSql::BeforeFirstRow); - } - setActive(true); - return true; -} -#endif -///////////////////////////////////////////////////////// - -static int qMySqlConnectionCount = 0; -static bool qMySqlInitHandledByUser = false; - -static void qLibraryInit() -{ -#ifndef Q_NO_MYSQL_EMBEDDED -# if MYSQL_VERSION_ID >= 40000 - if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1) - return; - -# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 - if (mysql_library_init(0, 0, 0)) { -# else - if (mysql_server_init(0, 0, 0)) { -# endif - qWarning("QMYSQLDriver::qServerInit: unable to start server."); - } -# endif // MYSQL_VERSION_ID -#endif // Q_NO_MYSQL_EMBEDDED -} - -static void qLibraryEnd() -{ -#ifndef Q_NO_MYSQL_EMBEDDED -# if MYSQL_VERSION_ID > 40000 -# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 - mysql_library_end(); -# else - mysql_server_end(); -# endif -# endif -#endif -} - -QMYSQLDriver::QMYSQLDriver(QObject * parent) - : QSqlDriver(*new QMYSQLDriverPrivate, parent) -{ - init(); - qLibraryInit(); -} - -/*! - Create a driver instance with the open connection handle, \a con. - The instance's parent (owner) is \a parent. -*/ - -QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent) - : QSqlDriver(*new QMYSQLDriverPrivate, parent) -{ - Q_D(QMYSQLDriver); - init(); - if (con) { - d->mysql = (MYSQL *) con; -#ifndef QT_NO_TEXTCODEC - d->tc = codec(con); -#endif - setOpen(true); - setOpenError(false); - if (qMySqlConnectionCount == 1) - qMySqlInitHandledByUser = true; - } else { - qLibraryInit(); - } -} - -void QMYSQLDriver::init() -{ - Q_D(QMYSQLDriver); - d->mysql = 0; - qMySqlConnectionCount++; -} - -QMYSQLDriver::~QMYSQLDriver() -{ - qMySqlConnectionCount--; - if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser) - qLibraryEnd(); -} - -bool QMYSQLDriver::hasFeature(DriverFeature f) const -{ - Q_D(const QMYSQLDriver); - switch (f) { - case Transactions: -// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34 -#ifdef CLIENT_TRANSACTIONS - if (d->mysql) { - if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS) - return true; - } -#endif - return false; - case NamedPlaceholders: - case BatchOperations: - case SimpleLocking: - case EventNotifications: - case FinishQuery: - case CancelQuery: - return false; - case QuerySize: - case BLOB: - case LastInsertId: - case Unicode: - case LowPrecisionNumbers: - return true; - case PreparedQueries: - case PositionalPlaceholders: -#if MYSQL_VERSION_ID >= 40108 - return d->preparedQuerysEnabled; -#else - return false; -#endif - case MultipleResultSets: -#if MYSQL_VERSION_ID >= 40100 - return true; -#else - return false; -#endif - } - return false; -} - -static void setOptionFlag(uint &optionFlags, const QString &opt) -{ - if (opt == QLatin1String("CLIENT_COMPRESS")) - optionFlags |= CLIENT_COMPRESS; - else if (opt == QLatin1String("CLIENT_FOUND_ROWS")) - optionFlags |= CLIENT_FOUND_ROWS; - else if (opt == QLatin1String("CLIENT_IGNORE_SPACE")) - optionFlags |= CLIENT_IGNORE_SPACE; - else if (opt == QLatin1String("CLIENT_INTERACTIVE")) - optionFlags |= CLIENT_INTERACTIVE; - else if (opt == QLatin1String("CLIENT_NO_SCHEMA")) - optionFlags |= CLIENT_NO_SCHEMA; - else if (opt == QLatin1String("CLIENT_ODBC")) - optionFlags |= CLIENT_ODBC; - else if (opt == QLatin1String("CLIENT_SSL")) - qWarning("QMYSQLDriver: SSL_KEY, SSL_CERT and SSL_CA should be used instead of CLIENT_SSL."); - else - qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData()); -} - -bool QMYSQLDriver::open(const QString& db, - const QString& user, - const QString& password, - const QString& host, - int port, - const QString& connOpts) -{ - Q_D(QMYSQLDriver); - if (isOpen()) - close(); - - /* This is a hack to get MySQL's stored procedure support working. - Since a stored procedure _may_ return multiple result sets, - we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_ - stored procedure call will fail. - */ - unsigned int optionFlags = Q_CLIENT_MULTI_STATEMENTS; - const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts)); - QString unixSocket; - QString sslCert; - QString sslCA; - QString sslKey; - QString sslCAPath; - QString sslCipher; -#if MYSQL_VERSION_ID >= 50000 - my_bool reconnect=false; - uint connectTimeout = 0; - uint readTimeout = 0; - uint writeTimeout = 0; -#endif - - // extract the real options from the string - for (int i = 0; i < opts.count(); ++i) { - QString tmp(opts.at(i).simplified()); - int idx; - if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) { - QString val = tmp.mid(idx + 1).simplified(); - QString opt = tmp.left(idx).simplified(); - if (opt == QLatin1String("UNIX_SOCKET")) - unixSocket = val; -#if MYSQL_VERSION_ID >= 50000 - else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) { - if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty()) - reconnect = true; - } else if (opt == QLatin1String("MYSQL_OPT_CONNECT_TIMEOUT")) { - connectTimeout = val.toInt(); - } else if (opt == QLatin1String("MYSQL_OPT_READ_TIMEOUT")) { - readTimeout = val.toInt(); - } else if (opt == QLatin1String("MYSQL_OPT_WRITE_TIMEOUT")) { - writeTimeout = val.toInt(); - } -#endif - else if (opt == QLatin1String("SSL_KEY")) - sslKey = val; - else if (opt == QLatin1String("SSL_CERT")) - sslCert = val; - else if (opt == QLatin1String("SSL_CA")) - sslCA = val; - else if (opt == QLatin1String("SSL_CAPATH")) - sslCAPath = val; - else if (opt == QLatin1String("SSL_CIPHER")) - sslCipher = val; - else if (val == QLatin1String("TRUE") || val == QLatin1String("1")) - setOptionFlag(optionFlags, tmp.left(idx).simplified()); - else - qWarning("QMYSQLDriver::open: Illegal connect option value '%s'", - tmp.toLocal8Bit().constData()); - } else { - setOptionFlag(optionFlags, tmp); - } - } - - if (!(d->mysql = mysql_init((MYSQL*) 0))) { - setLastError(qMakeError(tr("Unable to allocate a MYSQL object"), - QSqlError::ConnectionError, d)); - setOpenError(true); - return false; - } - - if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() || - !sslCAPath.isNull() || !sslCipher.isNull()) { - mysql_ssl_set(d->mysql, - sslKey.isNull() ? static_cast<const char *>(0) - : QFile::encodeName(sslKey).constData(), - sslCert.isNull() ? static_cast<const char *>(0) - : QFile::encodeName(sslCert).constData(), - sslCA.isNull() ? static_cast<const char *>(0) - : QFile::encodeName(sslCA).constData(), - sslCAPath.isNull() ? static_cast<const char *>(0) - : QFile::encodeName(sslCAPath).constData(), - sslCipher.isNull() ? static_cast<const char *>(0) - : sslCipher.toLocal8Bit().constData()); - } - -#if MYSQL_VERSION_ID >= 50000 - if (connectTimeout != 0) - mysql_options(d->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connectTimeout); - if (readTimeout != 0) - mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout); - if (writeTimeout != 0) - mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout); -#endif - MYSQL *mysql = mysql_real_connect(d->mysql, - host.isNull() ? static_cast<const char *>(0) - : host.toLocal8Bit().constData(), - user.isNull() ? static_cast<const char *>(0) - : user.toLocal8Bit().constData(), - password.isNull() ? static_cast<const char *>(0) - : password.toLocal8Bit().constData(), - db.isNull() ? static_cast<const char *>(0) - : db.toLocal8Bit().constData(), - (port > -1) ? port : 0, - unixSocket.isNull() ? static_cast<const char *>(0) - : unixSocket.toLocal8Bit().constData(), - optionFlags); - - 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)); - mysql_close(d->mysql); - setOpenError(true); - return false; - } -#if MYSQL_VERSION_ID >= 50000 - if (reconnect) - mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect); -#endif - } else { - setLastError(qMakeError(tr("Unable to connect"), - QSqlError::ConnectionError, d)); - mysql_close(d->mysql); - d->mysql = NULL; - setOpenError(true); - return false; - } - -#if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007 - // force the communication to be utf8 - mysql_set_character_set(d->mysql, "utf8"); -#endif -#ifndef QT_NO_TEXTCODEC - d->tc = codec(d->mysql); -#endif - -#if MYSQL_VERSION_ID >= 40108 - d->preparedQuerysEnabled = mysql_get_client_version() >= 40108 - && mysql_get_server_version(d->mysql) >= 40100; -#else - d->preparedQuerysEnabled = false; -#endif - -#ifndef QT_NO_THREAD - mysql_thread_init(); -#endif - - - setOpen(true); - setOpenError(false); - return true; -} - -void QMYSQLDriver::close() -{ - Q_D(QMYSQLDriver); - if (isOpen()) { -#ifndef QT_NO_THREAD - mysql_thread_end(); -#endif - mysql_close(d->mysql); - d->mysql = NULL; - setOpen(false); - setOpenError(false); - } -} - -QSqlResult *QMYSQLDriver::createResult() const -{ - return new QMYSQLResult(this); -} - -QStringList QMYSQLDriver::tables(QSql::TableType type) const -{ - Q_D(const QMYSQLDriver); - QStringList tl; -#if MYSQL_VERSION_ID >= 40100 - if( mysql_get_server_version(d->mysql) < 50000) - { -#endif - if (!isOpen()) - return tl; - if (!(type & QSql::Tables)) - return tl; - - MYSQL_RES* tableRes = mysql_list_tables(d->mysql, NULL); - MYSQL_ROW row; - int i = 0; - while (tableRes) { - mysql_data_seek(tableRes, i); - row = mysql_fetch_row(tableRes); - if (!row) - break; - tl.append(toUnicode(d->tc, row[0])); - i++; - } - mysql_free_result(tableRes); -#if MYSQL_VERSION_ID >= 40100 - } else { - QSqlQuery q(createResult()); - if(type & QSql::Tables) { - QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'"); - q.exec(sql); - - while(q.next()) - tl.append(q.value(0).toString()); - } - if(type & QSql::Views) { - QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'"); - q.exec(sql); - - while(q.next()) - tl.append(q.value(0).toString()); - } - } -#endif - return tl; -} - -QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const -{ - QSqlIndex idx; - if (!isOpen()) - return idx; - - QSqlQuery i(createResult()); - QString stmt(QLatin1String("show index from %1;")); - QSqlRecord fil = record(tablename); - i.exec(stmt.arg(tablename)); - while (i.isActive() && i.next()) { - if (i.value(2).toString() == QLatin1String("PRIMARY")) { - idx.append(fil.field(i.value(4).toString())); - idx.setCursorName(i.value(0).toString()); - idx.setName(i.value(2).toString()); - } - } - - return idx; -} - -QSqlRecord QMYSQLDriver::record(const QString& tablename) const -{ - Q_D(const QMYSQLDriver); - QString table=tablename; - if(isIdentifierEscaped(table, QSqlDriver::TableName)) - table = stripDelimiters(table, QSqlDriver::TableName); - - QSqlRecord info; - if (!isOpen()) - return info; - MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0); - if (!r) { - return info; - } - MYSQL_FIELD* field; - - while ((field = mysql_fetch_field(r))) - info.append(qToField(field, d->tc)); - mysql_free_result(r); - return info; -} - -QVariant QMYSQLDriver::handle() const -{ - Q_D(const QMYSQLDriver); - return QVariant::fromValue(d->mysql); -} - -bool QMYSQLDriver::beginTransaction() -{ - Q_D(QMYSQLDriver); -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::beginTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "BEGIN WORK")) { - setLastError(qMakeError(tr("Unable to begin transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -bool QMYSQLDriver::commitTransaction() -{ - Q_D(QMYSQLDriver); -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::commitTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "COMMIT")) { - setLastError(qMakeError(tr("Unable to commit transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -bool QMYSQLDriver::rollbackTransaction() -{ - Q_D(QMYSQLDriver); -#ifndef CLIENT_TRANSACTIONS - return false; -#endif - if (!isOpen()) { - qWarning("QMYSQLDriver::rollbackTransaction: Database not open"); - return false; - } - if (mysql_query(d->mysql, "ROLLBACK")) { - setLastError(qMakeError(tr("Unable to rollback transaction"), - QSqlError::StatementError, d)); - return false; - } - return true; -} - -QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const -{ - Q_D(const QMYSQLDriver); - QString r; - if (field.isNull()) { - r = QLatin1String("NULL"); - } else { - switch(field.type()) { - case QVariant::Double: - r = QString::number(field.value().toDouble(), 'g', field.precision()); - break; - case QVariant::String: - // Escape '\' characters - r = QSqlDriver::formatValue(field, trimStrings); - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); - break; - case QVariant::ByteArray: - if (isOpen()) { - const QByteArray ba = field.value().toByteArray(); - // buffer has to be at least length*2+1 bytes - char* buffer = new char[ba.size() * 2 + 1]; - 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('\'')); - delete[] buffer; - break; - } else { - qWarning("QMYSQLDriver::formatValue: Database not open"); - } - // fall through - default: - r = QSqlDriver::formatValue(field, trimStrings); - } - } - return r; -} - -QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const -{ - QString res = identifier; - if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) { - res.prepend(QLatin1Char('`')).append(QLatin1Char('`')); - res.replace(QLatin1Char('.'), QLatin1String("`.`")); - } - return res; -} - -bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const -{ - Q_UNUSED(type); - return identifier.size() > 2 - && identifier.startsWith(QLatin1Char('`')) //left delimited - && identifier.endsWith(QLatin1Char('`')); //right delimited -} - -QT_END_NAMESPACE diff --git a/src/sql/drivers/mysql/qsql_mysql.pri b/src/sql/drivers/mysql/qsql_mysql.pri deleted file mode 100644 index 3cfb6144a1..0000000000 --- a/src/sql/drivers/mysql/qsql_mysql.pri +++ /dev/null @@ -1,16 +0,0 @@ -HEADERS += $$PWD/qsql_mysql_p.h -SOURCES += $$PWD/qsql_mysql.cpp - -QMAKE_CXXFLAGS *= $$QT_CFLAGS_MYSQL -LIBS += $$QT_LFLAGS_MYSQL - -unix { - isEmpty(QT_LFLAGS_MYSQL) { - !contains(LIBS, .*mysqlclient.*):!contains(LIBS, .*mysqld.*) { - use_libmysqlclient_r:LIBS += -lmysqlclient_r - else:LIBS += -lmysqlclient - } - } -} else { - !contains(LIBS, .*mysql.*):!contains(LIBS, .*mysqld.*):LIBS += -llibmysql -} diff --git a/src/sql/drivers/mysql/qsql_mysql_p.h b/src/sql/drivers/mysql/qsql_mysql_p.h deleted file mode 100644 index 7641f9aa34..0000000000 --- a/src/sql/drivers/mysql/qsql_mysql_p.h +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSQL_MYSQL_H -#define QSQL_MYSQL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtSql/qsqldriver.h> - -#if defined (Q_OS_WIN32) -#include <QtCore/qt_windows.h> -#endif - -#include <mysql.h> - -#ifdef QT_PLUGIN -#define Q_EXPORT_SQLDRIVER_MYSQL -#else -#define Q_EXPORT_SQLDRIVER_MYSQL Q_SQL_EXPORT -#endif - -QT_BEGIN_NAMESPACE - -class QMYSQLDriverPrivate; - -class Q_EXPORT_SQLDRIVER_MYSQL QMYSQLDriver : public QSqlDriver -{ - friend class QMYSQLResultPrivate; - Q_DECLARE_PRIVATE(QMYSQLDriver) - Q_OBJECT -public: - explicit QMYSQLDriver(QObject *parent=0); - explicit QMYSQLDriver(MYSQL *con, QObject * parent=0); - ~QMYSQLDriver(); - bool hasFeature(DriverFeature f) const Q_DECL_OVERRIDE; - bool open(const QString & db, - const QString & user, - const QString & password, - const QString & host, - int port, - const QString& connOpts) Q_DECL_OVERRIDE; - void close() Q_DECL_OVERRIDE; - QSqlResult *createResult() const Q_DECL_OVERRIDE; - QStringList tables(QSql::TableType) const Q_DECL_OVERRIDE; - QSqlIndex primaryIndex(const QString& tablename) const Q_DECL_OVERRIDE; - QSqlRecord record(const QString& tablename) const Q_DECL_OVERRIDE; - QString formatValue(const QSqlField &field, - bool trimStrings) const Q_DECL_OVERRIDE; - QVariant handle() const Q_DECL_OVERRIDE; - QString escapeIdentifier(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; - - bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const Q_DECL_OVERRIDE; - -protected: - bool beginTransaction() Q_DECL_OVERRIDE; - bool commitTransaction() Q_DECL_OVERRIDE; - bool rollbackTransaction() Q_DECL_OVERRIDE; -private: - void init(); -}; - -QT_END_NAMESPACE - -#endif // QSQL_MYSQL_H |