diff options
Diffstat (limited to 'src/sql/drivers')
27 files changed, 651 insertions, 466 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp index 9406861d4c..e58710e0f5 100644 --- a/src/sql/drivers/db2/qsql_db2.cpp +++ b/src/sql/drivers/db2/qsql_db2.cpp @@ -39,7 +39,8 @@ ** ****************************************************************************/ -#include "qsql_db2.h" +#include "qsql_db2_p.h" +#include <QtSql/private/qsqldriver_p.h> #include <qcoreapplication.h> #include <qdatetime.h> #include <qsqlfield.h> @@ -70,10 +71,10 @@ QT_BEGIN_NAMESPACE static const int COLNAMESIZE = 255; static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT }; -class QDB2DriverPrivate +class QDB2DriverPrivate : public QSqlDriverPrivate { public: - QDB2DriverPrivate(): hEnv(0), hDbc(0) {} + QDB2DriverPrivate() : QSqlDriverPrivate(), hEnv(0), hDbc(0) { dbmsType = DB2; } SQLHANDLE hEnv; SQLHANDLE hDbc; QString user; @@ -1131,15 +1132,14 @@ void QDB2Result::detachFromResultSet() /************************************/ QDB2Driver::QDB2Driver(QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QDB2DriverPrivate, parent) { - d = new QDB2DriverPrivate; } QDB2Driver::QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QDB2DriverPrivate, parent) { - d = new QDB2DriverPrivate; + Q_D(QDB2Driver); d->hEnv = (SQLHANDLE)env; d->hDbc = (SQLHANDLE)con; if (env && con) { @@ -1151,12 +1151,12 @@ QDB2Driver::QDB2Driver(Qt::HANDLE env, Qt::HANDLE con, QObject* parent) QDB2Driver::~QDB2Driver() { close(); - delete d; } bool QDB2Driver::open(const QString& db, const QString& user, const QString& password, const QString& host, int port, const QString& connOpts) { + Q_D(QDB2Driver); if (isOpen()) close(); SQLRETURN r; @@ -1259,6 +1259,7 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas void QDB2Driver::close() { + Q_D(QDB2Driver); SQLRETURN r; if (d->hDbc) { // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect @@ -1285,11 +1286,13 @@ void QDB2Driver::close() QSqlResult *QDB2Driver::createResult() const { + Q_D(const QDB2Driver); return new QDB2Result(this, d); } QSqlRecord QDB2Driver::record(const QString& tableName) const { + Q_D(const QDB2Driver); QSqlRecord fil; if (!isOpen()) return fil; @@ -1363,6 +1366,7 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const QStringList QDB2Driver::tables(QSql::TableType type) const { + Q_D(const QDB2Driver); QStringList tl; if (!isOpen()) return tl; @@ -1434,6 +1438,7 @@ QStringList QDB2Driver::tables(QSql::TableType type) const QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const { + Q_D(const QDB2Driver); QSqlIndex index(tablename); if (!isOpen()) return index; @@ -1535,6 +1540,7 @@ bool QDB2Driver::beginTransaction() bool QDB2Driver::commitTransaction() { + Q_D(QDB2Driver); if (!isOpen()) { qWarning("QDB2Driver::commitTransaction: Database not open"); return false; @@ -1552,6 +1558,7 @@ bool QDB2Driver::commitTransaction() bool QDB2Driver::rollbackTransaction() { + Q_D(QDB2Driver); if (!isOpen()) { qWarning("QDB2Driver::rollbackTransaction: Database not open"); return false; @@ -1569,6 +1576,7 @@ bool QDB2Driver::rollbackTransaction() bool QDB2Driver::setAutoCommit(bool autoCommit) { + Q_D(QDB2Driver); SQLUINTEGER ac = autoCommit ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; SQLRETURN r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_AUTOCOMMIT, @@ -1627,6 +1635,7 @@ QString QDB2Driver::formatValue(const QSqlField &field, bool trimStrings) const QVariant QDB2Driver::handle() const { + Q_D(const QDB2Driver); return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc); } diff --git a/src/sql/drivers/db2/qsql_db2.pri b/src/sql/drivers/db2/qsql_db2.pri index 963732aaee..c9e65e2c2e 100644 --- a/src/sql/drivers/db2/qsql_db2.pri +++ b/src/sql/drivers/db2/qsql_db2.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_db2.h +HEADERS += $$PWD/qsql_db2_p.h SOURCES += $$PWD/qsql_db2.cpp unix { diff --git a/src/sql/drivers/db2/qsql_db2.h b/src/sql/drivers/db2/qsql_db2_p.h index 4e25c317eb..89b07c9c83 100644 --- a/src/sql/drivers/db2/qsql_db2.h +++ b/src/sql/drivers/db2/qsql_db2_p.h @@ -42,6 +42,19 @@ #ifndef QSQL_DB2_H #define QSQL_DB2_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 <QtCore/qglobal.h> + #ifdef QT_PLUGIN #define Q_EXPORT_SQLDRIVER_DB2 #else @@ -51,15 +64,8 @@ #include <QtSql/qsqlresult.h> #include <QtSql/qsqldriver.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QDB2Driver; class QDB2DriverPrivate; class QDB2ResultPrivate; @@ -95,6 +101,7 @@ private: class Q_EXPORT_SQLDRIVER_DB2 QDB2Driver : public QSqlDriver { + Q_DECLARE_PRIVATE(QDB2Driver) Q_OBJECT public: explicit QDB2Driver(QObject* parent = 0); @@ -121,11 +128,8 @@ public: private: bool setAutoCommit(bool autoCommit); - QDB2DriverPrivate* d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_DB2_H diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp index 5fd07318ec..bd97db189c 100644 --- a/src/sql/drivers/ibase/qsql_ibase.cpp +++ b/src/sql/drivers/ibase/qsql_ibase.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_ibase.h" +#include "qsql_ibase_p.h" #include <qcoreapplication.h> #include <qdatetime.h> #include <qvariant.h> @@ -47,6 +47,8 @@ #include <qsqlfield.h> #include <qsqlindex.h> #include <qsqlquery.h> +#include <QtSql/private/qsqlcachedresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <qlist.h> #include <qvector.h> #include <qtextcodec.h> @@ -308,13 +310,15 @@ struct QIBaseEventBuffer { QIBaseSubscriptionState subscriptionState; }; -class QIBaseDriverPrivate +class QIBaseDriverPrivate : public QSqlDriverPrivate { + Q_DECLARE_PUBLIC(QIBaseDriver) public: - QIBaseDriverPrivate(QIBaseDriver *d) : q(d), ibase(0), trans(0), tc(0) {} + QIBaseDriverPrivate() : QSqlDriverPrivate(), ibase(0), trans(0), tc(0) { dbmsType = Interbase; } bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError) { + Q_Q(QIBaseDriver); QString imsg; ISC_LONG sqlcode; if (!getIBaseError(imsg, status, sqlcode, tc)) @@ -326,7 +330,6 @@ public: } public: - QIBaseDriver* q; isc_db_handle ibase; isc_tr_handle trans; QTextCodec *tc; @@ -346,6 +349,31 @@ static void qFreeEventBuffer(QIBaseEventBuffer* eBuffer) delete eBuffer; } +class QIBaseResultPrivate; + +class QIBaseResult : public QSqlCachedResult +{ + friend class QIBaseResultPrivate; + +public: + explicit QIBaseResult(const QIBaseDriver* db); + virtual ~QIBaseResult(); + + bool prepare(const QString& query); + bool exec(); + QVariant handle() const; + +protected: + bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + QSqlRecord record() const; + +private: + QIBaseResultPrivate* d; +}; + class QIBaseResultPrivate { public: @@ -391,9 +419,9 @@ public: QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb): - q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d->ibase), sqlda(0), inda(0), queryType(-1), tc(ddb->d->tc) + q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d_func()->ibase), sqlda(0), inda(0), queryType(-1), tc(ddb->d_func()->tc) { - localTransaction = (ddb->d->ibase == 0); + localTransaction = (ddb->d_func()->ibase == 0); } void QIBaseResultPrivate::cleanup() @@ -834,9 +862,9 @@ bool QIBaseResultPrivate::transaction() { if (trans) return true; - if (db->d->trans) { + if (db->d_func()->trans) { localTransaction = false; - trans = db->d->trans; + trans = db->d_func()->trans; return true; } localTransaction = true; @@ -1369,15 +1397,14 @@ QVariant QIBaseResult::handle() const /*********************************/ QIBaseDriver::QIBaseDriver(QObject * parent) - : QSqlDriver(parent) + : QSqlDriver(*new QIBaseDriverPrivate, parent) { - d = new QIBaseDriverPrivate(this); } QIBaseDriver::QIBaseDriver(isc_db_handle connection, QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QIBaseDriverPrivate, parent) { - d = new QIBaseDriverPrivate(this); + Q_D(QIBaseDriver); d->ibase = connection; setOpen(true); setOpenError(false); @@ -1385,7 +1412,6 @@ QIBaseDriver::QIBaseDriver(isc_db_handle connection, QObject *parent) QIBaseDriver::~QIBaseDriver() { - delete d; } bool QIBaseDriver::hasFeature(DriverFeature f) const @@ -1418,6 +1444,7 @@ bool QIBaseDriver::open(const QString & db, int /*port*/, const QString & connOpts) { + Q_D(QIBaseDriver); if (isOpen()) close(); @@ -1500,6 +1527,7 @@ bool QIBaseDriver::open(const QString & db, void QIBaseDriver::close() { + Q_D(QIBaseDriver); if (isOpen()) { if (d->eventBuffers.size()) { @@ -1536,6 +1564,7 @@ QSqlResult *QIBaseDriver::createResult() const bool QIBaseDriver::beginTransaction() { + Q_D(QIBaseDriver); if (!isOpen() || isOpenError()) return false; if (d->trans) @@ -1548,6 +1577,7 @@ bool QIBaseDriver::beginTransaction() bool QIBaseDriver::commitTransaction() { + Q_D(QIBaseDriver); if (!isOpen() || isOpenError()) return false; if (!d->trans) @@ -1561,6 +1591,7 @@ bool QIBaseDriver::commitTransaction() bool QIBaseDriver::rollbackTransaction() { + Q_D(QIBaseDriver); if (!isOpen() || isOpenError()) return false; if (!d->trans) @@ -1723,6 +1754,7 @@ QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) cons QVariant QIBaseDriver::handle() const { + Q_D(const QIBaseDriver); return QVariant(qRegisterMetaType<isc_db_handle>("isc_db_handle"), &d->ibase); } @@ -1751,6 +1783,7 @@ static isc_callback qEventCallback(char *result, short length, char *updated) bool QIBaseDriver::subscribeToNotification(const QString &name) { + Q_D(QIBaseDriver); if (!isOpen()) { qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open."); return false; @@ -1800,6 +1833,7 @@ bool QIBaseDriver::subscribeToNotification(const QString &name) bool QIBaseDriver::unsubscribeFromNotification(const QString &name) { + Q_D(QIBaseDriver); if (!isOpen()) { qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open."); return false; @@ -1829,11 +1863,13 @@ bool QIBaseDriver::unsubscribeFromNotification(const QString &name) QStringList QIBaseDriver::subscribedToNotifications() const { + Q_D(const QIBaseDriver); return QStringList(d->eventBuffers.keys()); } void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer) { + Q_D(QIBaseDriver); QMap<QString, QIBaseEventBuffer *>::const_iterator i; for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) { QIBaseEventBuffer* eBuffer = i.value(); diff --git a/src/sql/drivers/ibase/qsql_ibase.pri b/src/sql/drivers/ibase/qsql_ibase.pri index 26017e8727..ef3b68d34e 100644 --- a/src/sql/drivers/ibase/qsql_ibase.pri +++ b/src/sql/drivers/ibase/qsql_ibase.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_ibase.h +HEADERS += $$PWD/qsql_ibase_p.h SOURCES += $$PWD/qsql_ibase.cpp unix { diff --git a/src/sql/drivers/ibase/qsql_ibase.h b/src/sql/drivers/ibase/qsql_ibase_p.h index 2ce20966c6..ab9edfd1a5 100644 --- a/src/sql/drivers/ibase/qsql_ibase.h +++ b/src/sql/drivers/ibase/qsql_ibase_p.h @@ -42,52 +42,31 @@ #ifndef QSQL_IBASE_H #define QSQL_IBASE_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/qsqlresult.h> #include <QtSql/qsqldriver.h> -#include <QtSql/private/qsqlcachedresult_p.h> #include <ibase.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QIBaseDriverPrivate; -class QIBaseResultPrivate; class QIBaseDriver; -class QIBaseResult : public QSqlCachedResult -{ - friend class QIBaseResultPrivate; - -public: - explicit QIBaseResult(const QIBaseDriver* db); - virtual ~QIBaseResult(); - - bool prepare(const QString& query); - bool exec(); - QVariant handle() const; - -protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx); - bool reset (const QString& query); - int size(); - int numRowsAffected(); - QSqlRecord record() const; - -private: - QIBaseResultPrivate* d; -}; - class QIBaseDriver : public QSqlDriver { - Q_OBJECT - friend class QIBaseDriverPrivate; friend class QIBaseResultPrivate; + Q_DECLARE_PRIVATE(QIBaseDriver) + Q_OBJECT public: explicit QIBaseDriver(QObject *parent = 0); explicit QIBaseDriver(isc_db_handle connection, QObject *parent = 0); @@ -125,12 +104,8 @@ public: private Q_SLOTS: void qHandleEventNotification(void* updatedResultBuffer); - -private: - QIBaseDriverPrivate* d; }; QT_END_NAMESPACE -QT_END_HEADER #endif // QSQL_IBASE_H diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp index b4aa5cd4cc..0e20cf539e 100644 --- a/src/sql/drivers/mysql/qsql_mysql.cpp +++ b/src/sql/drivers/mysql/qsql_mysql.cpp @@ -39,8 +39,9 @@ ** ****************************************************************************/ -#include "qsql_mysql.h" +#include "qsql_mysql_p.h" +#include <QtSql/private/qsqldriver_p.h> #include <qcoreapplication.h> #include <qvariant.h> #include <qdatetime.h> @@ -76,16 +77,16 @@ Q_DECLARE_METATYPE(MYSQL_STMT*) QT_BEGIN_NAMESPACE -class QMYSQLDriverPrivate +class QMYSQLDriverPrivate : public QSqlDriverPrivate { public: - QMYSQLDriverPrivate() : mysql(0), + QMYSQLDriverPrivate() : QSqlDriverPrivate(), mysql(0), #ifndef QT_NO_TEXTCODEC tc(QTextCodec::codecForLocale()), #else tc(0), #endif - preparedQuerysEnabled(false) {} + preparedQuerysEnabled(false) { dbmsType = MySqlServer; } MYSQL *mysql; QTextCodec *tc; @@ -166,7 +167,7 @@ class QMYSQLResultPrivate : public QObject { Q_OBJECT public: - QMYSQLResultPrivate(const QMYSQLDriver* dp, const QMYSQLResult* d) : driver(dp), result(0), q(d), + QMYSQLResultPrivate(const QMYSQLDriver* dp, const QMYSQLResult* d) : driver(dp), result(0), q(d), rowsAffected(0), hasBlobs(false) #if MYSQL_VERSION_ID >= 40108 , stmt(0), meta(0), inBinds(0), outBinds(0) @@ -434,8 +435,8 @@ void QMYSQLResult::cleanup() // 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 (d->driver && d->driver->d->mysql && mysql_next_result(d->driver->d->mysql) == 0) { - MYSQL_RES *res = mysql_store_result(d->driver->d->mysql); + while (d->driver && d->driver->d_func()->mysql && mysql_next_result(d->driver->d_func()->mysql) == 0) { + MYSQL_RES *res = mysql_store_result(d->driver->d_func()->mysql); if (res) mysql_free_result(res); } @@ -605,7 +606,7 @@ QVariant QMYSQLResult::data(int field) return QVariant(f.type); if (f.type != QVariant::ByteArray) - val = toUnicode(d->driver->d->tc, f.outField, f.bufLength); + val = toUnicode(d->driver->d_func()->tc, f.outField, f.bufLength); } else { if (d->row[field] == NULL) { // NULL value @@ -613,7 +614,7 @@ QVariant QMYSQLResult::data(int field) } fieldLength = mysql_fetch_lengths(d->result)[field]; if (f.type != QVariant::ByteArray) - val = toUnicode(d->driver->d->tc, d->row[field], fieldLength); + val = toUnicode(d->driver->d_func()->tc, d->row[field], fieldLength); } switch(f.type) { @@ -692,22 +693,22 @@ bool QMYSQLResult::reset (const QString& query) cleanup(); - const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); - if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) { + const QByteArray encQuery(fromUnicode(d->driver->d_func()->tc, query)); + if (mysql_real_query(d->driver->d_func()->mysql, encQuery.data(), encQuery.length())) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"), - QSqlError::StatementError, d->driver->d)); + QSqlError::StatementError, d->driver->d_func())); return false; } - d->result = mysql_store_result(d->driver->d->mysql); - if (!d->result && mysql_field_count(d->driver->d->mysql) > 0) { + d->result = mysql_store_result(d->driver->d_func()->mysql); + if (!d->result && mysql_field_count(d->driver->d_func()->mysql) > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), - QSqlError::StatementError, d->driver->d)); + QSqlError::StatementError, d->driver->d_func())); return false; } - int numFields = mysql_field_count(d->driver->d->mysql); + int numFields = mysql_field_count(d->driver->d_func()->mysql); setSelect(numFields != 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d_func()->mysql); if (isSelect()) { for(int i = 0; i < numFields; i++) { @@ -752,7 +753,7 @@ QVariant QMYSQLResult::lastInsertId() const return QVariant(id); #endif } else { - quint64 id = mysql_insert_id(d->driver->d->mysql); + quint64 id = mysql_insert_id(d->driver->d_func()->mysql); if (id) return QVariant(id); } @@ -772,11 +773,11 @@ QSqlRecord QMYSQLResult::record() const res = d->result; #endif - if (!mysql_errno(d->driver->d->mysql)) { + if (!mysql_errno(d->driver->d_func()->mysql)) { mysql_field_seek(res, 0); MYSQL_FIELD* field = mysql_fetch_field(res); while(field) { - info.append(qToField(field, d->driver->d->tc)); + info.append(qToField(field, d->driver->d_func()->tc)); field = mysql_fetch_field(res); } } @@ -788,7 +789,7 @@ bool QMYSQLResult::nextResult() { if(!d->driver) return false; -#if MYSQL_VERSION_ID >= 40100 +#if MYSQL_VERSION_ID >= 40100 setAt(-1); setActive(false); @@ -796,31 +797,31 @@ bool QMYSQLResult::nextResult() 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->driver->d->mysql); + int status = mysql_next_result(d->driver->d_func()->mysql); if (status > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), - QSqlError::StatementError, d->driver->d)); + QSqlError::StatementError, d->driver->d_func())); return false; } else if (status == -1) { return false; // No more result sets } - d->result = mysql_store_result(d->driver->d->mysql); - int numFields = mysql_field_count(d->driver->d->mysql); + d->result = mysql_store_result(d->driver->d_func()->mysql); + int numFields = mysql_field_count(d->driver->d_func()->mysql); if (!d->result && numFields > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), - QSqlError::StatementError, d->driver->d)); + QSqlError::StatementError, d->driver->d_func())); return false; } setSelect(numFields > 0); d->fields.resize(numFields); - d->rowsAffected = mysql_affected_rows(d->driver->d->mysql); + d->rowsAffected = mysql_affected_rows(d->driver->d_func()->mysql); if (isSelect()) { for (int i = 0; i < numFields; i++) { @@ -873,7 +874,7 @@ bool QMYSQLResult::prepare(const QString& query) return false; #if MYSQL_VERSION_ID >= 40108 cleanup(); - if (!d->driver->d->preparedQuerysEnabled) + if (!d->driver->d_func()->preparedQuerysEnabled) return QSqlResult::prepare(query); int r; @@ -882,14 +883,14 @@ bool QMYSQLResult::prepare(const QString& query) return false; if (!d->stmt) - d->stmt = mysql_stmt_init(d->driver->d->mysql); + d->stmt = mysql_stmt_init(d->driver->d_func()->mysql); if (!d->stmt) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), - QSqlError::StatementError, d->driver->d)); + QSqlError::StatementError, d->driver->d_func())); return false; } - const QByteArray encQuery(fromUnicode(d->driver->d->tc, query)); + const QByteArray encQuery(fromUnicode(d->driver->d_func()->tc, query)); r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length()); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", @@ -1009,7 +1010,7 @@ bool QMYSQLResult::exec() break; case QVariant::String: default: { - QByteArray ba = fromUnicode(d->driver->d->tc, val.toString()); + QByteArray ba = fromUnicode(d->driver->d_func()->tc, val.toString()); stringVector.append(ba); currBind->buffer_type = MYSQL_TYPE_STRING; currBind->buffer = const_cast<char *>(ba.constData()); @@ -1114,7 +1115,7 @@ static void qLibraryEnd() } QMYSQLDriver::QMYSQLDriver(QObject * parent) - : QSqlDriver(parent) + : QSqlDriver(*new QMYSQLDriverPrivate, parent) { init(); qLibraryInit(); @@ -1126,8 +1127,9 @@ QMYSQLDriver::QMYSQLDriver(QObject * parent) */ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent) - : QSqlDriver(parent) + : QSqlDriver(*new QMYSQLDriverPrivate, parent) { + Q_D(QMYSQLDriver); init(); if (con) { d->mysql = (MYSQL *) con; @@ -1145,7 +1147,7 @@ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent) void QMYSQLDriver::init() { - d = new QMYSQLDriverPrivate(); + Q_D(QMYSQLDriver); d->mysql = 0; qMySqlConnectionCount++; } @@ -1155,11 +1157,11 @@ QMYSQLDriver::~QMYSQLDriver() qMySqlConnectionCount--; if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser) qLibraryEnd(); - delete d; } 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 @@ -1227,6 +1229,7 @@ bool QMYSQLDriver::open(const QString& db, int port, const QString& connOpts) { + Q_D(QMYSQLDriver); if (isOpen()) close(); @@ -1328,6 +1331,7 @@ bool QMYSQLDriver::open(const QString& db, void QMYSQLDriver::close() { + Q_D(QMYSQLDriver); if (isOpen()) { #ifndef QT_NO_THREAD mysql_thread_end(); @@ -1346,6 +1350,7 @@ QSqlResult *QMYSQLDriver::createResult() const 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) @@ -1374,14 +1379,14 @@ QStringList QMYSQLDriver::tables(QSql::TableType type) const 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()); } @@ -1413,6 +1418,7 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const QSqlRecord QMYSQLDriver::record(const QString& tablename) const { + Q_D(const QMYSQLDriver); QString table=tablename; if(isIdentifierEscaped(table, QSqlDriver::TableName)) table = stripDelimiters(table, QSqlDriver::TableName); @@ -1434,11 +1440,13 @@ QSqlRecord QMYSQLDriver::record(const QString& tablename) const 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 @@ -1456,6 +1464,7 @@ bool QMYSQLDriver::beginTransaction() bool QMYSQLDriver::commitTransaction() { + Q_D(QMYSQLDriver); #ifndef CLIENT_TRANSACTIONS return false; #endif @@ -1473,6 +1482,7 @@ bool QMYSQLDriver::commitTransaction() bool QMYSQLDriver::rollbackTransaction() { + Q_D(QMYSQLDriver); #ifndef CLIENT_TRANSACTIONS return false; #endif @@ -1490,6 +1500,7 @@ bool QMYSQLDriver::rollbackTransaction() QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const { + Q_D(const QMYSQLDriver); QString r; if (field.isNull()) { r = QLatin1String("NULL"); diff --git a/src/sql/drivers/mysql/qsql_mysql.pri b/src/sql/drivers/mysql/qsql_mysql.pri index 0423eb4ed9..50f49ca548 100644 --- a/src/sql/drivers/mysql/qsql_mysql.pri +++ b/src/sql/drivers/mysql/qsql_mysql.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_mysql.h +HEADERS += $$PWD/qsql_mysql_p.h SOURCES += $$PWD/qsql_mysql.cpp !isEmpty(MYSQL_PATH) { diff --git a/src/sql/drivers/mysql/qsql_mysql.h b/src/sql/drivers/mysql/qsql_mysql_p.h index 37e18c8fb1..a1be139b2a 100644 --- a/src/sql/drivers/mysql/qsql_mysql.h +++ b/src/sql/drivers/mysql/qsql_mysql_p.h @@ -42,6 +42,17 @@ #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> #include <QtSql/qsqlresult.h> @@ -57,15 +68,8 @@ #define Q_EXPORT_SQLDRIVER_MYSQL Q_SQL_EXPORT #endif -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QMYSQLDriverPrivate; class QMYSQLResultPrivate; class QMYSQLDriver; @@ -106,8 +110,9 @@ private: class Q_EXPORT_SQLDRIVER_MYSQL QMYSQLDriver : public QSqlDriver { - Q_OBJECT friend class QMYSQLResult; + Q_DECLARE_PRIVATE(QMYSQLDriver) + Q_OBJECT public: explicit QMYSQLDriver(QObject *parent=0); explicit QMYSQLDriver(MYSQL *con, QObject * parent=0); @@ -137,11 +142,8 @@ protected: bool rollbackTransaction(); private: void init(); - QMYSQLDriverPrivate* d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_MYSQL_H diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index e2bb9a4eaf..fe9ae42e6f 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_oci.h" +#include "qsql_oci_p.h" #include <qcoreapplication.h> #include <qvariant.h> @@ -51,6 +51,8 @@ #include <qsqlfield.h> #include <qsqlindex.h> #include <qsqlquery.h> +#include <QtSql/private/qsqlcachedresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <qstringlist.h> #include <qvarlengtharray.h> #include <qvector.h> @@ -99,7 +101,7 @@ enum { QOCIEncoding = 2000 }; // AL16UTF16 // Always set the OCI_ATTR_CHARSET_FORM to SQLCS_NCHAR is safe // because Oracle server will deal with the implicit Conversion // Between CHAR and NCHAR. -// see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705 +// see: http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/oci05bnd.htm#422705 static const ub1 qOraCharsetForm = SQLCS_NCHAR; #endif @@ -162,6 +164,33 @@ Q_DECLARE_METATYPE(QOCIRowIdPointer) QT_END_INCLUDE_NAMESPACE class QOCICols; +struct QOCIResultPrivate; + +class Q_EXPORT_SQLDRIVER_OCI QOCIResult : public QSqlCachedResult +{ + friend class QOCIDriver; + friend struct QOCIResultPrivate; + friend class QOCICols; +public: + QOCIResult(const QOCIDriver * db, const QOCIDriverPrivate* p); + ~QOCIResult(); + bool prepare(const QString& query); + bool exec(); + QVariant handle() const; + +protected: + bool gotoNext(ValueCache &values, int index); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + QSqlRecord record() const; + QVariant lastInsertId() const; + bool execBatch(bool arrayBind = false); + void virtual_hook(int id, void *data); + +private: + QOCIResultPrivate *d; +}; struct QOCIResultPrivate { @@ -464,8 +493,9 @@ void QOCIResultPrivate::outValues(QVector<QVariant> &values, IndicatorArray &ind } -struct QOCIDriverPrivate +class QOCIDriverPrivate : public QSqlDriverPrivate { +public: QOCIDriverPrivate(); OCIEnv *env; @@ -483,9 +513,10 @@ struct QOCIDriverPrivate }; QOCIDriverPrivate::QOCIDriverPrivate() - : env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false), serverVersion(-1), - prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM) + : QSqlDriverPrivate(), env(0), svc(0), srvhp(0), authp(0), err(0), transaction(false), + serverVersion(-1), prefetchRows(-1), prefetchMem(QOCI_PREFETCH_MEM) { + dbmsType = Oracle; } void QOCIDriverPrivate::allocErrorHandle() @@ -2057,10 +2088,9 @@ void QOCIResult::virtual_hook(int id, void *data) QOCIDriver::QOCIDriver(QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QOCIDriverPrivate, parent) { - d = new QOCIDriverPrivate(); - + Q_D(QOCIDriver); #ifdef QOCI_THREADED const ub4 mode = OCI_UTF16 | OCI_OBJECT | OCI_THREADED; #else @@ -2085,9 +2115,9 @@ QOCIDriver::QOCIDriver(QObject* parent) } QOCIDriver::QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QOCIDriverPrivate, parent) { - d = new QOCIDriverPrivate(); + Q_D(QOCIDriver); d->env = env; d->svc = ctx; @@ -2101,6 +2131,7 @@ QOCIDriver::QOCIDriver(OCIEnv* env, OCISvcCtx* ctx, QObject* parent) QOCIDriver::~QOCIDriver() { + Q_D(QOCIDriver); if (isOpen()) close(); int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR); @@ -2109,12 +2140,11 @@ QOCIDriver::~QOCIDriver() r = OCIHandleFree(d->env, OCI_HTYPE_ENV); if (r != OCI_SUCCESS) qWarning("Unable to free Environment handle: %d", r); - - delete d; } bool QOCIDriver::hasFeature(DriverFeature f) const { + Q_D(const QOCIDriver); switch (f) { case Transactions: case LastInsertId: @@ -2173,6 +2203,7 @@ bool QOCIDriver::open(const QString & db, int port, const QString &opts) { + Q_D(QOCIDriver); int r; if (isOpen()) @@ -2183,7 +2214,7 @@ bool QOCIDriver::open(const QString & db, // Connect without tnsnames.ora if a hostname is given QString connectionString = db; if (!hostname.isEmpty()) - connectionString = + connectionString = QString::fromLatin1("(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=%1)(Port=%2))" "(CONNECT_DATA=(SID=%3)))").arg(hostname).arg((port > -1 ? port : 1521)).arg(db); @@ -2259,6 +2290,7 @@ bool QOCIDriver::open(const QString & db, void QOCIDriver::close() { + Q_D(QOCIDriver); if (!isOpen()) return; @@ -2276,11 +2308,13 @@ void QOCIDriver::close() QSqlResult *QOCIDriver::createResult() const { + Q_D(const QOCIDriver); return new QOCIResult(this, d); } bool QOCIDriver::beginTransaction() { + Q_D(QOCIDriver); if (!isOpen()) { qWarning("QOCIDriver::beginTransaction: Database not open"); return false; @@ -2301,6 +2335,7 @@ bool QOCIDriver::beginTransaction() bool QOCIDriver::commitTransaction() { + Q_D(QOCIDriver); if (!isOpen()) { qWarning("QOCIDriver::commitTransaction: Database not open"); return false; @@ -2320,6 +2355,7 @@ bool QOCIDriver::commitTransaction() bool QOCIDriver::rollbackTransaction() { + Q_D(QOCIDriver); if (!isOpen()) { qWarning("QOCIDriver::rollbackTransaction: Database not open"); return false; @@ -2339,6 +2375,7 @@ bool QOCIDriver::rollbackTransaction() QStringList QOCIDriver::tables(QSql::TableType type) const { + Q_D(const QOCIDriver); QStringList tl; QStringList sysUsers = QStringList() << QLatin1String("MDSYS") << QLatin1String("LBACSYS") @@ -2444,6 +2481,7 @@ void qSplitTableAndOwner(const QString & tname, QString * tbl, QSqlRecord QOCIDriver::record(const QString& tablename) const { + Q_D(const QOCIDriver); QSqlRecord fil; if (!isOpen()) return fil; @@ -2517,6 +2555,7 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const { + Q_D(const QOCIDriver); QSqlIndex idx(tablename); if (!isOpen()) return idx; @@ -2637,6 +2676,7 @@ QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const QVariant QOCIDriver::handle() const { + Q_D(const QOCIDriver); return QVariant::fromValue(d->env); } diff --git a/src/sql/drivers/oci/qsql_oci.pri b/src/sql/drivers/oci/qsql_oci.pri index 60ccc4c227..66ccdb1abb 100644 --- a/src/sql/drivers/oci/qsql_oci.pri +++ b/src/sql/drivers/oci/qsql_oci.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_oci.h +HEADERS += $$PWD/qsql_oci_p.h SOURCES += $$PWD/qsql_oci.cpp unix { @@ -6,4 +6,4 @@ unix { } else { LIBS *= -loci } -macx:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ +mac:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ diff --git a/src/sql/drivers/oci/qsql_oci.h b/src/sql/drivers/oci/qsql_oci_p.h index 2488e696d2..c55a4209fa 100644 --- a/src/sql/drivers/oci/qsql_oci.h +++ b/src/sql/drivers/oci/qsql_oci_p.h @@ -42,9 +42,19 @@ #ifndef QSQL_OCI_H #define QSQL_OCI_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/qsqlresult.h> #include <QtSql/qsqldriver.h> -#include <QtSql/private/qsqlcachedresult_p.h> #ifdef QT_PLUGIN #define Q_EXPORT_SQLDRIVER_OCI @@ -52,51 +62,18 @@ #define Q_EXPORT_SQLDRIVER_OCI Q_SQL_EXPORT #endif -QT_BEGIN_HEADER - typedef struct OCIEnv OCIEnv; typedef struct OCISvcCtx OCISvcCtx; QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QOCIDriver; class QOCICols; -struct QOCIDriverPrivate; -struct QOCIResultPrivate; - -class Q_EXPORT_SQLDRIVER_OCI QOCIResult : public QSqlCachedResult -{ - friend class QOCIDriver; - friend struct QOCIResultPrivate; - friend class QOCICols; -public: - QOCIResult(const QOCIDriver * db, const QOCIDriverPrivate* p); - ~QOCIResult(); - bool prepare(const QString& query); - bool exec(); - QVariant handle() const; - -protected: - bool gotoNext(ValueCache &values, int index); - bool reset (const QString& query); - int size(); - int numRowsAffected(); - QSqlRecord record() const; - QVariant lastInsertId() const; - bool execBatch(bool arrayBind = false); - void virtual_hook(int id, void *data); - -private: - QOCIResultPrivate *d; -}; +class QOCIDriverPrivate; class Q_EXPORT_SQLDRIVER_OCI QOCIDriver : public QSqlDriver { + Q_DECLARE_PRIVATE(QOCIDriver) Q_OBJECT friend struct QOCIResultPrivate; friend class QOCIPrivate; @@ -125,12 +102,8 @@ protected: bool beginTransaction(); bool commitTransaction(); bool rollbackTransaction(); -private: - QOCIDriverPrivate *d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_OCI_H diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 9517d95fc4..d36a224d8e 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_odbc.h" +#include "qsql_odbc_p.h" #include <qsqlrecord.h> #if defined (Q_OS_WIN32) @@ -57,6 +57,7 @@ #include <qmath.h> #include <QDebug> #include <QSqlQuery> +#include <QtSql/private/qsqldriver_p.h> QT_BEGIN_NAMESPACE @@ -111,14 +112,13 @@ inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input) return result; } -class QODBCDriverPrivate +class QODBCDriverPrivate : public QSqlDriverPrivate { public: enum DefaultCase{Lower, Mixed, Upper, Sensitive}; QODBCDriverPrivate() - : hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19), isMySqlServer(false), - isMSSqlServer(false), isFreeTDSDriver(false), hasSQLFetchScroll(true), - hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"')) + : QSqlDriverPrivate(), hEnv(0), hDbc(0), unicode(false), useSchema(false), disconnectCount(0), datetime_precision(19), + isFreeTDSDriver(false), hasSQLFetchScroll(true), hasMultiResultSets(false), isQuoteInitialized(false), quote(QLatin1Char('"')) { } @@ -129,15 +129,13 @@ public: bool useSchema; int disconnectCount; int datetime_precision; - bool isMySqlServer; - bool isMSSqlServer; bool isFreeTDSDriver; bool hasSQLFetchScroll; bool hasMultiResultSets; bool checkDriver() const; void checkUnicode(); - void checkSqlServer(); + void checkDBMS(); void checkHasSQLFetchScroll(); void checkHasMultiResults(); void checkSchemaUsage(); @@ -190,13 +188,13 @@ public: bool QODBCPrivate::isStmtHandleValid(const QSqlDriver *driver) { const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver); - return disconnectCount == odbcdriver->d->disconnectCount; + return disconnectCount == odbcdriver->d_func()->disconnectCount; } void QODBCPrivate::updateStmtHandleState(const QSqlDriver *driver) { const QODBCDriver *odbcdriver = static_cast<const QODBCDriver*> (driver); - disconnectCount = odbcdriver->d->disconnectCount; + disconnectCount = odbcdriver->d_func()->disconnectCount; } static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0) @@ -960,11 +958,6 @@ bool QODBCResult::reset (const QString& query) return false; } - if(r == SQL_NO_DATA) { - setSelect(false); - return true; - } - SQLINTEGER bufferLength; SQLULEN isScrollable; r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength); @@ -1407,7 +1400,7 @@ bool QODBCResult::exec() // (How many leading digits do we want to keep? With SQL Server 2005, this should be 3: 123000000) int keep = (int)qPow(10.0, 9 - qMin(9, precision)); - dt->fraction /= keep * keep; + dt->fraction = (dt->fraction / keep) * keep; } r = SQLBindParameter(d->hStmt, @@ -1592,7 +1585,7 @@ bool QODBCResult::exec() } } r = SQLExecute(d->hStmt); - if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) { + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) { qWarning() << "QODBCResult::exec: Unable to execute statement:" << qODBCWarn(d); setLastError(qMakeError(QCoreApplication::translate("QODBCResult", "Unable to execute statement"), QSqlError::StatementError, d)); @@ -1677,6 +1670,38 @@ QSqlRecord QODBCResult::record() const return d->rInf; } +QVariant QODBCResult::lastInsertId() const +{ + QString sql; + + switch (d->driverPrivate->dbmsType) { + case QODBCDriverPrivate::MSSqlServer: + case QODBCDriverPrivate::Sybase: + sql = QLatin1String("SELECT @@IDENTITY;"); + break; + case QODBCDriverPrivate::MySqlServer: + sql = QLatin1String("SELECT LAST_INSERT_ID();"); + break; + case QODBCDriverPrivate::PostgreSQL: + sql = QLatin1String("SELECT lastval();"); + break; + default: + break; + } + + if (!sql.isEmpty()) { + QSqlQuery qry(driver()->createResult()); + if (qry.exec(sql) && qry.next()) + return qry.value(0); + + qSqlWarning(QLatin1String("QODBCResult::lastInsertId: Unable to get lastInsertId"), d); + } else { + qSqlWarning(QLatin1String("QODBCResult::lastInsertId: not implemented for this DBMS"), d); + } + + return QVariant(); +} + QVariant QODBCResult::handle() const { return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hStmt); @@ -1742,15 +1767,14 @@ void QODBCResult::setForwardOnly(bool forward) QODBCDriver::QODBCDriver(QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QODBCDriverPrivate, parent) { - init(); } -QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent) - : QSqlDriver(parent) +QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject *parent) + : QSqlDriver(*new QODBCDriverPrivate, parent) { - init(); + Q_D(QODBCDriver); d->hEnv = env; d->hDbc = con; if (env && con) { @@ -1759,19 +1783,14 @@ QODBCDriver::QODBCDriver(SQLHANDLE env, SQLHANDLE con, QObject * parent) } } -void QODBCDriver::init() -{ - d = new QODBCDriverPrivate(); -} - QODBCDriver::~QODBCDriver() { cleanup(); - delete d; } bool QODBCDriver::hasFeature(DriverFeature f) const { + Q_D(const QODBCDriver); switch (f) { case Transactions: { if (!d->hDbc) @@ -1797,16 +1816,20 @@ bool QODBCDriver::hasFeature(DriverFeature f) const return true; case QuerySize: case NamedPlaceholders: - case LastInsertId: case BatchOperations: case SimpleLocking: case EventNotifications: case CancelQuery: return false; + case LastInsertId: + return (d->dbmsType == QODBCDriverPrivate::MSSqlServer) + || (d->dbmsType == QODBCDriverPrivate::Sybase) + || (d->dbmsType == QODBCDriverPrivate::MySqlServer) + || (d->dbmsType == QODBCDriverPrivate::PostgreSQL); case MultipleResultSets: return d->hasMultiResultSets; case BLOB: { - if(d->isMySqlServer) + if (d->dbmsType == QODBCDriverPrivate::MySqlServer) return true; else return false; @@ -1822,6 +1845,7 @@ bool QODBCDriver::open(const QString & db, int, const QString& connOpts) { + Q_D(QODBCDriver); if (isOpen()) close(); SQLRETURN r; @@ -1896,13 +1920,13 @@ bool QODBCDriver::open(const QString & db, d->checkUnicode(); d->checkSchemaUsage(); - d->checkSqlServer(); + d->checkDBMS(); d->checkHasSQLFetchScroll(); d->checkHasMultiResults(); d->checkDateTimePrecision(); setOpen(true); setOpenError(false); - if(d->isMSSqlServer) { + if (d->dbmsType == QODBCDriverPrivate::MSSqlServer) { QSqlQuery i(createResult()); i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON")); } @@ -1918,9 +1942,8 @@ void QODBCDriver::close() void QODBCDriver::cleanup() { + Q_D(QODBCDriver); SQLRETURN r; - if (!d) - return; if(d->hDbc) { // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect @@ -2069,7 +2092,7 @@ void QODBCDriverPrivate::checkSchemaUsage() useSchema = (val != 0); } -void QODBCDriverPrivate::checkSqlServer() +void QODBCDriverPrivate::checkDBMS() { SQLRETURN r; QVarLengthArray<SQLTCHAR> serverString(200); @@ -2088,8 +2111,16 @@ void QODBCDriverPrivate::checkSqlServer() #else serverType = QString::fromUtf8((const char *)serverString.constData(), t); #endif - isMySqlServer = serverType.contains(QLatin1String("mysql"), Qt::CaseInsensitive); - isMSSqlServer = serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive); + if (serverType.contains(QLatin1String("PostgreSQL"), Qt::CaseInsensitive)) + dbmsType = PostgreSQL; + else if (serverType.contains(QLatin1String("Oracle"), Qt::CaseInsensitive)) + dbmsType = Oracle; + else if (serverType.contains(QLatin1String("MySql"), Qt::CaseInsensitive)) + dbmsType = MySqlServer; + else if (serverType.contains(QLatin1String("Microsoft SQL Server"), Qt::CaseInsensitive)) + dbmsType = MSSqlServer; + else if (serverType.contains(QLatin1String("Sybase"), Qt::CaseInsensitive)) + dbmsType = Sybase; } r = SQLGetInfo(hDbc, SQL_DRIVER_NAME, @@ -2160,11 +2191,13 @@ void QODBCDriverPrivate::checkDateTimePrecision() QSqlResult *QODBCDriver::createResult() const { - return new QODBCResult(this, d); + Q_D(const QODBCDriver); + return new QODBCResult(this, const_cast<QODBCDriverPrivate*>(d)); } bool QODBCDriver::beginTransaction() { + Q_D(QODBCDriver); if (!isOpen()) { qWarning() << "QODBCDriver::beginTransaction: Database not open"; return false; @@ -2184,6 +2217,7 @@ bool QODBCDriver::beginTransaction() bool QODBCDriver::commitTransaction() { + Q_D(QODBCDriver); if (!isOpen()) { qWarning() << "QODBCDriver::commitTransaction: Database not open"; return false; @@ -2201,6 +2235,7 @@ bool QODBCDriver::commitTransaction() bool QODBCDriver::rollbackTransaction() { + Q_D(QODBCDriver); if (!isOpen()) { qWarning() << "QODBCDriver::rollbackTransaction: Database not open"; return false; @@ -2218,6 +2253,7 @@ bool QODBCDriver::rollbackTransaction() bool QODBCDriver::endTrans() { + Q_D(QODBCDriver); SQLUINTEGER ac(SQL_AUTOCOMMIT_ON); SQLRETURN r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_AUTOCOMMIT, @@ -2232,6 +2268,7 @@ bool QODBCDriver::endTrans() QStringList QODBCDriver::tables(QSql::TableType type) const { + Q_D(const QODBCDriver); QStringList tl; if (!isOpen()) return tl; @@ -2309,6 +2346,7 @@ QStringList QODBCDriver::tables(QSql::TableType type) const QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const { + Q_D(const QODBCDriver); QSqlIndex index(tablename); if (!isOpen()) return index; @@ -2324,7 +2362,7 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const return index; } QString catalog, schema, table; - d->splitTableQualifier(tablename, catalog, schema, table); + const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table); if (isIdentifierEscaped(catalog, QSqlDriver::TableName)) catalog = stripDelimiters(catalog, QSqlDriver::TableName); @@ -2436,13 +2474,14 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const QSqlRecord QODBCDriver::record(const QString& tablename) const { + Q_D(const QODBCDriver); QSqlRecord fil; if (!isOpen()) return fil; SQLHANDLE hStmt; QString catalog, schema, table; - d->splitTableQualifier(tablename, catalog, schema, table); + const_cast<QODBCDriverPrivate*>(d)->splitTableQualifier(tablename, catalog, schema, table); if (isIdentifierEscaped(catalog, QSqlDriver::TableName)) catalog = stripDelimiters(catalog, QSqlDriver::TableName); @@ -2561,12 +2600,14 @@ QString QODBCDriver::formatValue(const QSqlField &field, QVariant QODBCDriver::handle() const { + Q_D(const QODBCDriver); return QVariant(qRegisterMetaType<SQLHANDLE>("SQLHANDLE"), &d->hDbc); } QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { - QChar quote = d->quoteChar(); + Q_D(const QODBCDriver); + QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar(); QString res = identifier; if(!identifier.isEmpty() && !identifier.startsWith(quote) && !identifier.endsWith(quote) ) { res.replace(quote, QString(quote)+QString(quote)); @@ -2578,7 +2619,8 @@ QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType) bool QODBCDriver::isIdentifierEscaped(const QString &identifier, IdentifierType) const { - QChar quote = d->quoteChar(); + Q_D(const QODBCDriver); + QChar quote = const_cast<QODBCDriverPrivate*>(d)->quoteChar(); return identifier.size() > 2 && identifier.startsWith(quote) //left delimited && identifier.endsWith(quote); //right delimited diff --git a/src/sql/drivers/odbc/qsql_odbc.pri b/src/sql/drivers/odbc/qsql_odbc.pri index 19ff784a04..b206df37c3 100644 --- a/src/sql/drivers/odbc/qsql_odbc.pri +++ b/src/sql/drivers/odbc/qsql_odbc.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_odbc.h +HEADERS += $$PWD/qsql_odbc_p.h SOURCES += $$PWD/qsql_odbc.cpp unix { diff --git a/src/sql/drivers/odbc/qsql_odbc.h b/src/sql/drivers/odbc/qsql_odbc_p.h index 4fba49b9c5..b18768a5a2 100644 --- a/src/sql/drivers/odbc/qsql_odbc.h +++ b/src/sql/drivers/odbc/qsql_odbc_p.h @@ -42,6 +42,17 @@ #ifndef QSQL_ODBC_H #define QSQL_ODBC_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> #include <QtSql/qsqlresult.h> @@ -70,15 +81,8 @@ #include <sqlext.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QODBCPrivate; class QODBCDriverPrivate; class QODBCDriver; @@ -93,6 +97,7 @@ public: bool prepare(const QString& query); bool exec(); + QVariant lastInsertId() const; QVariant handle() const; virtual void setForwardOnly(bool forward); @@ -118,6 +123,7 @@ private: class Q_EXPORT_SQLDRIVER_ODBC QODBCDriver : public QSqlDriver { + Q_DECLARE_PRIVATE(QODBCDriver) Q_OBJECT public: explicit QODBCDriver(QObject *parent=0); @@ -149,15 +155,11 @@ protected: bool rollbackTransaction(); private: - void init(); bool endTrans(); void cleanup(); - QODBCDriverPrivate* d; friend class QODBCPrivate; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_ODBC_H diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index 0eadceb1d1..9331f5c371 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_psql.h" +#include "qsql_psql_p.h" #include <qcoreapplication.h> #include <qvariant.h> @@ -54,6 +54,7 @@ #include <qstringlist.h> #include <qmutex.h> #include <QtSql/private/qsqlresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <libpq-fe.h> #include <pg_config.h> @@ -121,17 +122,26 @@ inline void qPQfreemem(void *buffer) PQfreemem(buffer); } -class QPSQLDriverPrivate +class QPSQLDriverPrivate : public QSqlDriverPrivate { + Q_DECLARE_PUBLIC(QPSQLDriver) public: - QPSQLDriverPrivate(QPSQLDriver *qq) : q(qq), connection(0), isUtf8(false), pro(QPSQLDriver::Version6), sn(0), pendingNotifyCheck(false) {} - QPSQLDriver *q; + QPSQLDriverPrivate() : QSqlDriverPrivate(), + connection(0), + isUtf8(false), + pro(QPSQLDriver::Version6), + sn(0), + pendingNotifyCheck(false), + hasBackslashEscape(false) + { dbmsType = PostgreSQL; } + PGconn *connection; bool isUtf8; QPSQLDriver::Protocol pro; QSocketNotifier *sn; QStringList seid; mutable bool pendingNotifyCheck; + bool hasBackslashEscape; void appendTables(QStringList &tl, QSqlQuery &t, QChar type); PGresult * exec(const char * stmt) const; @@ -139,6 +149,7 @@ public: QPSQLDriver::Protocol getPSQLVersion(); bool setEncodingUtf8(); void setDatestyle(); + void detectBackslashEscape(); }; void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) @@ -167,10 +178,11 @@ void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) PGresult * QPSQLDriverPrivate::exec(const char * stmt) const { + Q_Q(const QPSQLDriver); PGresult *result = PQexec(connection, stmt); if (seid.size() && !pendingNotifyCheck) { pendingNotifyCheck = true; - QMetaObject::invokeMethod(q, "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0)); + QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection, Q_ARG(int,0)); } return result; } @@ -180,14 +192,25 @@ PGresult * QPSQLDriverPrivate::exec(const QString & stmt) const return exec(isUtf8 ? stmt.toUtf8().constData() : stmt.toLocal8Bit().constData()); } -class QPSQLResultPrivate +class QPSQLResultPrivate : public QSqlResultPrivate { + Q_DECLARE_PUBLIC(QPSQLResult) public: - QPSQLResultPrivate(QPSQLResult *qq): q(qq), driver(0), result(0), currentSize(-1), preparedQueriesEnabled(false) {} - static QString fieldSerial(int i) { return QLatin1Char('$') + QString::number(i + 1); } + QPSQLResultPrivate() + : QSqlResultPrivate(), + result(0), + currentSize(-1), + preparedQueriesEnabled(false) + { } + + QString fieldSerial(int i) const { return QLatin1Char('$') + QString::number(i + 1); } + void deallocatePreparedStmt(); + const QPSQLDriverPrivate * privDriver() const + { + Q_Q(const QPSQLResult); + return reinterpret_cast<const QPSQLDriver *>(q->driver())->d_func(); + } - QPSQLResult *q; - const QPSQLDriverPrivate *driver; PGresult *result; int currentSize; bool preparedQueriesEnabled; @@ -210,6 +233,7 @@ static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, bool QPSQLResultPrivate::processResults() { + Q_Q(QPSQLResult); if (!result) return false; @@ -226,7 +250,7 @@ bool QPSQLResultPrivate::processResults() return true; } q->setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", - "Unable to create query"), QSqlError::StatementError, driver, result)); + "Unable to create query"), QSqlError::StatementError, privDriver(), result)); return false; } @@ -276,42 +300,42 @@ static QVariant::Type qDecodePSQLType(int t) return type; } -static void qDeallocatePreparedStmt(QPSQLResultPrivate *d) +void QPSQLResultPrivate::deallocatePreparedStmt() { - const QString stmt = QLatin1String("DEALLOCATE ") + d->preparedStmtId; - PGresult *result = d->driver->exec(stmt); + const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId; + PGresult *result = privDriver()->exec(stmt); if (PQresultStatus(result) != PGRES_COMMAND_OK) - qWarning("Unable to free statement: %s", PQerrorMessage(d->driver->connection)); + qWarning("Unable to free statement: %s", PQerrorMessage(privDriver()->connection)); PQclear(result); - d->preparedStmtId.clear(); + preparedStmtId.clear(); } -QPSQLResult::QPSQLResult(const QPSQLDriver* db, const QPSQLDriverPrivate* p) - : QSqlResult(db) +QPSQLResult::QPSQLResult(const QPSQLDriver* db) + : QSqlResult(*new QPSQLResultPrivate, db) { - d = new QPSQLResultPrivate(this); - d->driver = p; + Q_D(QPSQLResult); d->preparedQueriesEnabled = db->hasFeature(QSqlDriver::PreparedQueries); } QPSQLResult::~QPSQLResult() { + Q_D(QPSQLResult); cleanup(); if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull()) - qDeallocatePreparedStmt(d); - - delete d; + d->deallocatePreparedStmt(); } QVariant QPSQLResult::handle() const { + Q_D(const QPSQLResult); return QVariant::fromValue(d->result); } void QPSQLResult::cleanup() { + Q_D(QPSQLResult); if (d->result) PQclear(d->result); d->result = 0; @@ -322,6 +346,7 @@ void QPSQLResult::cleanup() bool QPSQLResult::fetch(int i) { + Q_D(const QPSQLResult); if (!isActive()) return false; if (i < 0) @@ -341,11 +366,13 @@ bool QPSQLResult::fetchFirst() bool QPSQLResult::fetchLast() { + Q_D(const QPSQLResult); return fetch(PQntuples(d->result) - 1); } QVariant QPSQLResult::data(int i) { + Q_D(const QPSQLResult); if (i >= PQnfields(d->result)) { qWarning("QPSQLResult::data: column %d out of range", i); return QVariant(); @@ -359,7 +386,7 @@ QVariant QPSQLResult::data(int i) case QVariant::Bool: return QVariant((bool)(val[0] == 't')); case QVariant::String: - return d->driver->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val); + return d->privDriver()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val); case QVariant::LongLong: if (val[0] == '-') return QString::fromLatin1(val).toLongLong(); @@ -446,34 +473,44 @@ QVariant QPSQLResult::data(int i) bool QPSQLResult::isNull(int field) { + Q_D(const QPSQLResult); PQgetvalue(d->result, at(), field); return PQgetisnull(d->result, at(), field); } bool QPSQLResult::reset (const QString& query) { + Q_D(QPSQLResult); cleanup(); if (!driver()) return false; if (!driver()->isOpen() || driver()->isOpenError()) return false; - d->result = d->driver->exec(query); + d->result = d->privDriver()->exec(query); return d->processResults(); } int QPSQLResult::size() { + Q_D(const QPSQLResult); return d->currentSize; } int QPSQLResult::numRowsAffected() { + Q_D(const QPSQLResult); return QString::fromLatin1(PQcmdTuples(d->result)).toInt(); } QVariant QPSQLResult::lastInsertId() const { - if (isActive()) { + Q_D(const QPSQLResult); + if (d->privDriver()->pro >= QPSQLDriver::Version81) { + QSqlQuery qry(driver()->createResult()); + // Most recent sequence value obtained from nextval + if (qry.exec(QLatin1String("SELECT lastval();")) && qry.next()) + return qry.value(0); + } else if (isActive()) { Oid id = PQoidValue(d->result); if (id != InvalidOid) return QVariant(id); @@ -483,6 +520,7 @@ QVariant QPSQLResult::lastInsertId() const QSqlRecord QPSQLResult::record() const { + Q_D(const QPSQLResult); QSqlRecord info; if (!isActive() || !isSelect()) return info; @@ -490,7 +528,7 @@ QSqlRecord QPSQLResult::record() const int count = PQnfields(d->result); for (int i = 0; i < count; ++i) { QSqlField f; - if (d->driver->isUtf8) + if (d->privDriver()->isUtf8) f.setName(QString::fromUtf8(PQfname(d->result, i))); else f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); @@ -551,22 +589,23 @@ QString qMakePreparedStmtId() bool QPSQLResult::prepare(const QString &query) { + Q_D(QPSQLResult); if (!d->preparedQueriesEnabled) return QSqlResult::prepare(query); cleanup(); if (!d->preparedStmtId.isEmpty()) - qDeallocatePreparedStmt(d); + d->deallocatePreparedStmt(); const QString stmtId = qMakePreparedStmtId(); - const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(QSqlResultPrivate::positionalToNamedBinding(query, QPSQLResultPrivate::fieldSerial)); + const QString stmt = QString::fromLatin1("PREPARE %1 AS ").arg(stmtId).append(d->positionalToNamedBinding(query)); - PGresult *result = d->driver->exec(stmt); + PGresult *result = d->privDriver()->exec(stmt); if (PQresultStatus(result) != PGRES_COMMAND_OK) { setLastError(qMakeError(QCoreApplication::translate("QPSQLResult", - "Unable to prepare statement"), QSqlError::StatementError, d->driver, result)); + "Unable to prepare statement"), QSqlError::StatementError, d->privDriver(), result)); PQclear(result); d->preparedStmtId.clear(); return false; @@ -579,19 +618,20 @@ bool QPSQLResult::prepare(const QString &query) bool QPSQLResult::exec() { + Q_D(QPSQLResult); if (!d->preparedQueriesEnabled) return QSqlResult::exec(); cleanup(); QString stmt; - const QString params = qCreateParamString(boundValues(), d->q->driver()); + const QString params = qCreateParamString(boundValues(), driver()); if (params.isEmpty()) stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId); else stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params); - d->result = d->driver->exec(stmt); + d->result = d->privDriver()->exec(stmt); return d->processResults(); } @@ -615,6 +655,23 @@ void QPSQLDriverPrivate::setDatestyle() PQclear(result); } +void QPSQLDriverPrivate::detectBackslashEscape() +{ + // standard_conforming_strings option introduced in 8.2 + // http://www.postgresql.org/docs/8.2/static/runtime-config-compatible.html + if (pro < QPSQLDriver::Version82) { + hasBackslashEscape = true; + } else { + hasBackslashEscape = false; + PGresult* result = exec(QLatin1Literal("SELECT '\\\\' x")); + int status = PQresultStatus(result); + if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) + if (QString::fromLatin1(PQgetvalue(result, 0, 0)) == QLatin1Literal("\\")) + hasBackslashEscape = true; + PQclear(result); + } +} + static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) { switch (vMaj) { @@ -714,42 +771,39 @@ QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion() } QPSQLDriver::QPSQLDriver(QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QPSQLDriverPrivate, parent) { - init(); } QPSQLDriver::QPSQLDriver(PGconn *conn, QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QPSQLDriverPrivate, parent) { - init(); + Q_D(QPSQLDriver); d->connection = conn; if (conn) { d->pro = d->getPSQLVersion(); + d->detectBackslashEscape(); setOpen(true); setOpenError(false); } } -void QPSQLDriver::init() -{ - d = new QPSQLDriverPrivate(this); -} - QPSQLDriver::~QPSQLDriver() { + Q_D(QPSQLDriver); if (d->connection) PQfinish(d->connection); - delete d; } QVariant QPSQLDriver::handle() const { + Q_D(const QPSQLDriver); return QVariant::fromValue(d->connection); } bool QPSQLDriver::hasFeature(DriverFeature f) const { + Q_D(const QPSQLDriver); switch (f) { case Transactions: case QuerySize: @@ -796,6 +850,7 @@ bool QPSQLDriver::open(const QString & db, int port, const QString& connOpts) { + Q_D(QPSQLDriver); if (isOpen()) close(); QString connectString; @@ -827,6 +882,7 @@ bool QPSQLDriver::open(const QString & db, } d->pro = d->getPSQLVersion(); + d->detectBackslashEscape(); d->isUtf8 = d->setEncodingUtf8(); d->setDatestyle(); @@ -837,6 +893,7 @@ bool QPSQLDriver::open(const QString & db, void QPSQLDriver::close() { + Q_D(QPSQLDriver); if (isOpen()) { d->seid.clear(); @@ -856,11 +913,12 @@ void QPSQLDriver::close() QSqlResult *QPSQLDriver::createResult() const { - return new QPSQLResult(this, d); + return new QPSQLResult(this); } bool QPSQLDriver::beginTransaction() { + Q_D(const QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::beginTransaction: Database not open"); return false; @@ -878,6 +936,7 @@ bool QPSQLDriver::beginTransaction() bool QPSQLDriver::commitTransaction() { + Q_D(QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::commitTransaction: Database not open"); return false; @@ -911,6 +970,7 @@ bool QPSQLDriver::commitTransaction() bool QPSQLDriver::rollbackTransaction() { + Q_D(QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::rollbackTransaction: Database not open"); return false; @@ -928,6 +988,7 @@ bool QPSQLDriver::rollbackTransaction() QStringList QPSQLDriver::tables(QSql::TableType type) const { + Q_D(const QPSQLDriver); QStringList tl; if (!isOpen()) return tl; @@ -935,9 +996,9 @@ QStringList QPSQLDriver::tables(QSql::TableType type) const t.setForwardOnly(true); if (type & QSql::Tables) - d->appendTables(tl, t, QLatin1Char('r')); + const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('r')); if (type & QSql::Views) - d->appendTables(tl, t, QLatin1Char('v')); + const_cast<QPSQLDriverPrivate*>(d)->appendTables(tl, t, QLatin1Char('v')); if (type & QSql::SystemTables) { t.exec(QLatin1String("select relname from pg_class where (relkind = 'r') " "and (relname like 'pg_%') ")); @@ -959,6 +1020,7 @@ static void qSplitTableName(QString &tablename, QString &schema) QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const { + Q_D(const QPSQLDriver); QSqlIndex idx(tablename); if (!isOpen()) return idx; @@ -1040,6 +1102,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const QSqlRecord QPSQLDriver::record(const QString& tablename) const { + Q_D(const QPSQLDriver); QSqlRecord info; if (!isOpen()) return info; @@ -1177,6 +1240,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const { + Q_D(const QPSQLDriver); QString r; if (field.isNull()) { r = QLatin1String("NULL"); @@ -1212,12 +1276,10 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const } break; case QVariant::String: - { - // Escape '\' characters r = QSqlDriver::formatValue(field, trimStrings); - r.replace(QLatin1String("\\"), QLatin1String("\\\\")); + if (d->hasBackslashEscape) + r.replace(QLatin1String("\\"), QLatin1String("\\\\")); break; - } case QVariant::Bool: if (field.value().toBool()) r = QLatin1String("TRUE"); @@ -1274,16 +1336,19 @@ QString QPSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) bool QPSQLDriver::isOpen() const { + Q_D(const QPSQLDriver); return PQstatus(d->connection) == CONNECTION_OK; } QPSQLDriver::Protocol QPSQLDriver::protocol() const { + Q_D(const QPSQLDriver); return d->pro; } bool QPSQLDriver::subscribeToNotification(const QString &name) { + Q_D(QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::subscribeToNotificationImplementation: database not open."); return false; @@ -1321,6 +1386,7 @@ bool QPSQLDriver::subscribeToNotification(const QString &name) bool QPSQLDriver::unsubscribeFromNotification(const QString &name) { + Q_D(QPSQLDriver); if (!isOpen()) { qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: database not open."); return false; @@ -1352,11 +1418,13 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name) QStringList QPSQLDriver::subscribedToNotifications() const { + Q_D(const QPSQLDriver); return d->seid; } void QPSQLDriver::_q_handleNotification(int) { + Q_D(QPSQLDriver); d->pendingNotifyCheck = false; PQconsumeInput(d->connection); diff --git a/src/sql/drivers/psql/qsql_psql.pri b/src/sql/drivers/psql/qsql_psql.pri index 9b647d8200..d0ded5e625 100644 --- a/src/sql/drivers/psql/qsql_psql.pri +++ b/src/sql/drivers/psql/qsql_psql.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_psql.h +HEADERS += $$PWD/qsql_psql_p.h SOURCES += $$PWD/qsql_psql.cpp unix|win32-g++* { diff --git a/src/sql/drivers/psql/qsql_psql.h b/src/sql/drivers/psql/qsql_psql_p.h index 444ef1bccc..5f4aa68b9e 100644 --- a/src/sql/drivers/psql/qsql_psql.h +++ b/src/sql/drivers/psql/qsql_psql_p.h @@ -42,6 +42,17 @@ #ifndef QSQL_PSQL_H #define QSQL_PSQL_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/qsqlresult.h> #include <QtSql/qsqldriver.h> @@ -51,28 +62,21 @@ #define Q_EXPORT_SQLDRIVER_PSQL Q_SQL_EXPORT #endif -QT_BEGIN_HEADER - typedef struct pg_conn PGconn; typedef struct pg_result PGresult; QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QPSQLResultPrivate; -class QPSQLDriverPrivate; class QPSQLDriver; class QSqlRecordInfo; class QPSQLResult : public QSqlResult { - friend class QPSQLResultPrivate; + Q_DECLARE_PRIVATE(QPSQLResult) + public: - QPSQLResult(const QPSQLDriver* db, const QPSQLDriverPrivate* p); + QPSQLResult(const QPSQLDriver* db); ~QPSQLResult(); QVariant handle() const; @@ -92,13 +96,15 @@ protected: QVariant lastInsertId() const; bool prepare(const QString& query); bool exec(); - -private: - QPSQLResultPrivate *d; }; +class QPSQLDriverPrivate; + class Q_EXPORT_SQLDRIVER_PSQL QPSQLDriver : public QSqlDriver { + friend class QPSQLResultPrivate; + Q_DECLARE_PRIVATE(QPSQLDriver) + Q_OBJECT public: enum Protocol { @@ -150,14 +156,8 @@ protected: private Q_SLOTS: void _q_handleNotification(int); - -private: - void init(); - QPSQLDriverPrivate *d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_PSQL_H diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index f11279f262..ffeb7921b3 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_sqlite.h" +#include "qsql_sqlite_p.h" #include <qcoreapplication.h> #include <qvariant.h> @@ -47,6 +47,8 @@ #include <qsqlfield.h> #include <qsqlindex.h> #include <qsqlquery.h> +#include <QtSql/private/qsqlcachedresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <qstringlist.h> #include <qvector.h> #include <qdebug.h> @@ -67,7 +69,7 @@ Q_DECLARE_METATYPE(sqlite3_stmt*) QT_BEGIN_NAMESPACE -static QString _q_escapeIdentifier(const QString &identifier) +static QString _q_escapeIdentifier(const QString &identifier) { QString res = identifier; if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { @@ -106,10 +108,37 @@ static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::Er type, errorCode); } -class QSQLiteDriverPrivate +class QSQLiteResultPrivate; + +class QSQLiteResult : public QSqlCachedResult +{ + friend class QSQLiteDriver; + friend class QSQLiteResultPrivate; +public: + explicit QSQLiteResult(const QSQLiteDriver* db); + ~QSQLiteResult(); + QVariant handle() const; + +protected: + bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); + bool reset(const QString &query); + bool prepare(const QString &query); + bool exec(); + int size(); + int numRowsAffected(); + QVariant lastInsertId() const; + QSqlRecord record() const; + void detachFromResultSet(); + void virtual_hook(int id, void *data); + +private: + QSQLiteResultPrivate* d; +}; + +class QSQLiteDriverPrivate : public QSqlDriverPrivate { public: - inline QSQLiteDriverPrivate() : access(0) {} + inline QSQLiteDriverPrivate() : QSqlDriverPrivate(), access(0) { dbmsType = SQLite; } sqlite3 *access; QList <QSQLiteResult *> results; }; @@ -206,8 +235,7 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset) } } - int dotIdx = colName.lastIndexOf(QLatin1Char('.')); - QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), fieldType); + QSqlField fld(colName, fieldType); fld.setSqlType(stp); rInf.append(fld); } @@ -318,15 +346,15 @@ QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db) : QSqlCachedResult(db) { d = new QSQLiteResultPrivate(this); - d->access = db->d->access; - db->d->results.append(this); + d->access = db->d_func()->access; + const_cast<QSQLiteDriverPrivate*>(db->d_func())->results.append(this); } QSQLiteResult::~QSQLiteResult() { const QSqlDriver *sqlDriver = driver(); if (sqlDriver) - qobject_cast<const QSQLiteDriver *>(sqlDriver)->d->results.removeOne(this); + const_cast<QSQLiteDriverPrivate*>(qobject_cast<const QSQLiteDriver *>(sqlDriver)->d_func())->results.removeOne(this); d->cleanup(); delete d; } @@ -502,15 +530,14 @@ QVariant QSQLiteResult::handle() const ///////////////////////////////////////////////////////// QSQLiteDriver::QSQLiteDriver(QObject * parent) - : QSqlDriver(parent) + : QSqlDriver(*new QSQLiteDriverPrivate, parent) { - d = new QSQLiteDriverPrivate(); } QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QSQLiteDriverPrivate, parent) { - d = new QSQLiteDriverPrivate(); + Q_D(QSQLiteDriver); d->access = connection; setOpen(true); setOpenError(false); @@ -519,7 +546,6 @@ QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent) QSQLiteDriver::~QSQLiteDriver() { - delete d; } bool QSQLiteDriver::hasFeature(DriverFeature f) const @@ -552,6 +578,7 @@ bool QSQLiteDriver::hasFeature(DriverFeature f) const */ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts) { + Q_D(QSQLiteDriver); if (isOpen()) close(); @@ -595,6 +622,7 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c void QSQLiteDriver::close() { + Q_D(QSQLiteDriver); if (isOpen()) { foreach (QSQLiteResult *result, d->results) { result->d->finalize(); @@ -751,6 +779,7 @@ QSqlRecord QSQLiteDriver::record(const QString &tbl) const QVariant QSQLiteDriver::handle() const { + Q_D(const QSQLiteDriver); return QVariant::fromValue(d->access); } diff --git a/src/sql/drivers/sqlite/qsql_sqlite.pri b/src/sql/drivers/sqlite/qsql_sqlite.pri index a2e80d4c74..e323f2eba5 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.pri +++ b/src/sql/drivers/sqlite/qsql_sqlite.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_sqlite.h +HEADERS += $$PWD/qsql_sqlite_p.h SOURCES += $$PWD/qsql_sqlite.cpp !system-sqlite:!contains(LIBS, .*sqlite3.*) { diff --git a/src/sql/drivers/sqlite/qsql_sqlite.h b/src/sql/drivers/sqlite/qsql_sqlite_p.h index 0fdcd4e240..526dd9a22a 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.h +++ b/src/sql/drivers/sqlite/qsql_sqlite_p.h @@ -42,9 +42,19 @@ #ifndef QSQL_SQLITE_H #define QSQL_SQLITE_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> #include <QtSql/qsqlresult.h> -#include <QtSql/private/qsqlcachedresult_p.h> struct sqlite3; @@ -54,46 +64,14 @@ struct sqlite3; #define Q_EXPORT_SQLDRIVER_SQLITE Q_SQL_EXPORT #endif -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QSQLiteDriverPrivate; -class QSQLiteResultPrivate; class QSQLiteDriver; -class QSQLiteResult : public QSqlCachedResult -{ - friend class QSQLiteDriver; - friend class QSQLiteResultPrivate; -public: - explicit QSQLiteResult(const QSQLiteDriver* db); - ~QSQLiteResult(); - QVariant handle() const; - -protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); - bool reset(const QString &query); - bool prepare(const QString &query); - bool exec(); - int size(); - int numRowsAffected(); - QVariant lastInsertId() const; - QSqlRecord record() const; - void detachFromResultSet(); - void virtual_hook(int id, void *data); - -private: - QSQLiteResultPrivate* d; -}; - class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver { + Q_DECLARE_PRIVATE(QSQLiteDriver) Q_OBJECT friend class QSQLiteResult; public: @@ -118,13 +96,8 @@ public: QSqlIndex primaryIndex(const QString &table) const; QVariant handle() const; QString escapeIdentifier(const QString &identifier, IdentifierType) const; - -private: - QSQLiteDriverPrivate* d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_SQLITE_H diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp index 02e4004901..7e56d5cc17 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp +++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_sqlite2.h" +#include "qsql_sqlite2_p.h" #include <qcoreapplication.h> #include <qvariant.h> @@ -50,6 +50,8 @@ #include <qsqlfield.h> #include <qsqlindex.h> #include <qsqlquery.h> +#include <QtSql/private/qsqlcachedresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <qstringlist.h> #include <qvector.h> @@ -81,7 +83,7 @@ static QVariant::Type nameToType(const QString& typeName) return QVariant::String; } -class QSQLite2DriverPrivate +class QSQLite2DriverPrivate : public QSqlDriverPrivate { public: QSQLite2DriverPrivate(); @@ -89,11 +91,36 @@ public: bool utf8; }; -QSQLite2DriverPrivate::QSQLite2DriverPrivate() : access(0) +QSQLite2DriverPrivate::QSQLite2DriverPrivate() : QSqlDriverPrivate(), access(0) { utf8 = (qstrcmp(sqlite_encoding, "UTF-8") == 0); + dbmsType = SQLite; } +class QSQLite2ResultPrivate; + +class QSQLite2Result : public QSqlCachedResult +{ + friend class QSQLite2Driver; + friend class QSQLite2ResultPrivate; +public: + explicit QSQLite2Result(const QSQLite2Driver* db); + ~QSQLite2Result(); + QVariant handle() const; + +protected: + bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + QSqlRecord record() const; + void detachFromResultSet(); + void virtual_hook(int id, void *data); + +private: + QSQLite2ResultPrivate* d; +}; + class QSQLite2ResultPrivate { public: @@ -170,7 +197,7 @@ void QSQLite2ResultPrivate::init(const char **cnames, int numCols) for (int i = 0; i < numCols; ++i) { const char* lastDot = strrchr(cnames[i], '.'); const char* fieldName = lastDot ? lastDot + 1 : cnames[i]; - + //remove quotations around the field name if any QString fieldStr = QString::fromLatin1(fieldName); QLatin1Char quote('\"'); @@ -219,7 +246,7 @@ bool QSQLite2ResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int firstRow.clear(); firstRow.resize(colNum); } - + switch(res) { case SQLITE_ROW: // check to see if should fill out columns @@ -254,8 +281,8 @@ QSQLite2Result::QSQLite2Result(const QSQLite2Driver* db) : QSqlCachedResult(db) { d = new QSQLite2ResultPrivate(this); - d->access = db->d->access; - d->utf8 = db->d->utf8; + d->access = db->d_func()->access; + d->utf8 = db->d_func()->utf8; } QSQLite2Result::~QSQLite2Result() @@ -349,16 +376,15 @@ QVariant QSQLite2Result::handle() const ///////////////////////////////////////////////////////// -QSQLite2Driver::QSQLite2Driver(QObject * parent) - : QSqlDriver(parent) +QSQLite2Driver::QSQLite2Driver(QObject *parent) + : QSqlDriver(*new QSQLite2DriverPrivate, parent) { - d = new QSQLite2DriverPrivate(); } QSQLite2Driver::QSQLite2Driver(sqlite *connection, QObject *parent) - : QSqlDriver(parent) + : QSqlDriver(*new QSQLite2DriverPrivate, parent) { - d = new QSQLite2DriverPrivate(); + Q_D(QSQLite2Driver); d->access = connection; setOpen(true); setOpenError(false); @@ -367,11 +393,11 @@ QSQLite2Driver::QSQLite2Driver(sqlite *connection, QObject *parent) QSQLite2Driver::~QSQLite2Driver() { - delete d; } bool QSQLite2Driver::hasFeature(DriverFeature f) const { + Q_D(const QSQLite2Driver); switch (f) { case Transactions: case SimpleLocking: @@ -389,6 +415,7 @@ bool QSQLite2Driver::hasFeature(DriverFeature f) const */ bool QSQLite2Driver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &) { + Q_D(QSQLite2Driver); if (isOpen()) close(); @@ -415,6 +442,7 @@ bool QSQLite2Driver::open(const QString & db, const QString &, const QString &, void QSQLite2Driver::close() { + Q_D(QSQLite2Driver); if (isOpen()) { sqlite_close(d->access); d->access = 0; @@ -430,6 +458,7 @@ QSqlResult *QSQLite2Driver::createResult() const bool QSQLite2Driver::beginTransaction() { + Q_D(QSQLite2Driver); if (!isOpen() || isOpenError()) return false; @@ -447,6 +476,7 @@ bool QSQLite2Driver::beginTransaction() bool QSQLite2Driver::commitTransaction() { + Q_D(QSQLite2Driver); if (!isOpen() || isOpenError()) return false; @@ -464,6 +494,7 @@ bool QSQLite2Driver::commitTransaction() bool QSQLite2Driver::rollbackTransaction() { + Q_D(QSQLite2Driver); if (!isOpen() || isOpenError()) return false; @@ -560,6 +591,7 @@ QSqlRecord QSQLite2Driver::record(const QString &tbl) const QVariant QSQLite2Driver::handle() const { + Q_D(const QSQLite2Driver); return QVariant::fromValue(d->access); } diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.pri b/src/sql/drivers/sqlite2/qsql_sqlite2.pri index 9a9f6cdf9e..5baba30db0 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.pri +++ b/src/sql/drivers/sqlite2/qsql_sqlite2.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_sqlite2.h +HEADERS += $$PWD/qsql_sqlite2_p.h SOURCES += $$PWD/qsql_sqlite2.cpp !contains(LIBS, .*sqlite.*):LIBS += -lsqlite diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.h b/src/sql/drivers/sqlite2/qsql_sqlite2_p.h index f141ad1cc2..ae38a662ac 100644 --- a/src/sql/drivers/sqlite2/qsql_sqlite2.h +++ b/src/sql/drivers/sqlite2/qsql_sqlite2_p.h @@ -42,11 +42,21 @@ #ifndef QSQL_SQLITE2_H #define QSQL_SQLITE2_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> #include <QtSql/qsqlresult.h> #include <QtSql/qsqlrecord.h> #include <QtSql/qsqlindex.h> -#include <QtSql/private/qsqlcachedresult_p.h> #if defined (Q_OS_WIN32) # include <QtCore/qt_windows.h> @@ -54,45 +64,16 @@ struct sqlite; -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QSQLite2DriverPrivate; -class QSQLite2ResultPrivate; class QSQLite2Driver; -class QSQLite2Result : public QSqlCachedResult -{ - friend class QSQLite2Driver; - friend class QSQLite2ResultPrivate; -public: - explicit QSQLite2Result(const QSQLite2Driver* db); - ~QSQLite2Result(); - QVariant handle() const; - -protected: - bool gotoNext(QSqlCachedResult::ValueCache& row, int idx); - bool reset (const QString& query); - int size(); - int numRowsAffected(); - QSqlRecord record() const; - void detachFromResultSet(); - void virtual_hook(int id, void *data); - -private: - QSQLite2ResultPrivate* d; -}; - class QSQLite2Driver : public QSqlDriver { - Q_OBJECT friend class QSQLite2Result; + Q_DECLARE_PRIVATE(QSQLite2Driver) + Q_OBJECT public: explicit QSQLite2Driver(QObject *parent = 0); explicit QSQLite2Driver(sqlite *connection, QObject *parent = 0); @@ -120,13 +101,8 @@ public: QSqlIndex primaryIndex(const QString &table) const; QVariant handle() const; QString escapeIdentifier(const QString &identifier, IdentifierType) const; - -private: - QSQLite2DriverPrivate* d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_SQLITE2_H diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp index 45bba42ca7..69534fe380 100644 --- a/src/sql/drivers/tds/qsql_tds.cpp +++ b/src/sql/drivers/tds/qsql_tds.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qsql_tds.h" +#include "qsql_tds_p.h" #include <qglobal.h> #ifdef Q_OS_WIN32 // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase. @@ -58,6 +58,8 @@ #include <qsqlfield.h> #include <qsqlindex.h> #include <qsqlquery.h> +#include <QtSql/private/qsqlcachedresult_p.h> +#include <QtSql/private/qsqldriver_p.h> #include <qstringlist.h> #include <qvector.h> @@ -135,16 +137,43 @@ QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo); } -class QTDSDriverPrivate +class QTDSDriverPrivate : public QSqlDriverPrivate { public: - QTDSDriverPrivate(): login(0), initialized(false) {} + QTDSDriverPrivate() : QSqlDriverPrivate(), login(0), initialized(false) { dbmsType = Sybase; } LOGINREC* login; // login information QString hostName; QString db; bool initialized; }; +struct QTDSColumnData +{ + void *data; + DBINT nullbind; +}; +Q_DECLARE_TYPEINFO(QTDSColumnData, Q_MOVABLE_TYPE); + +class QTDSResultPrivate; + +class QTDSResult : public QSqlCachedResult +{ +public: + explicit QTDSResult(const QTDSDriver* db); + ~QTDSResult(); + QVariant handle() const; + +protected: + void cleanup(); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + bool gotoNext(QSqlCachedResult::ValueCache &values, int index); + QSqlRecord record() const; + +private: + QTDSResultPrivate* d; +}; class QTDSResultPrivate { @@ -156,7 +185,7 @@ public: void addErrorMsg(QString& errMsg) { errorMsgs.append(errMsg); } QString getErrorMsgs() { return errorMsgs.join(QLatin1String("\n")); } void clearErrorMsgs() { errorMsgs.clear(); } - QVector<void *> buffer; + QVector<QTDSColumnData> buffer; QSqlRecord rec; private: @@ -298,12 +327,12 @@ QTDSResult::QTDSResult(const QTDSDriver* db) : QSqlCachedResult(db) { d = new QTDSResultPrivate(); - d->login = db->d->login; + d->login = db->d_func()->login; - d->dbproc = dbopen(d->login, const_cast<char*>(db->d->hostName.toLatin1().constData())); + d->dbproc = dbopen(d->login, const_cast<char*>(db->d_func()->hostName.toLatin1().constData())); if (!d->dbproc) return; - if (dbuse(d->dbproc, const_cast<char*>(db->d->db.toLatin1().constData())) == FAIL) + if (dbuse(d->dbproc, const_cast<char*>(db->d_func()->db.toLatin1().constData())) == FAIL) return; // insert d in error handler dict @@ -325,8 +354,8 @@ void QTDSResult::cleanup() { d->clearErrorMsgs(); d->rec.clear(); - for (int i = 0; i < d->buffer.size() / 2; ++i) - free(d->buffer.at(i * 2)); + for (int i = 0; i < d->buffer.size(); ++i) + free(d->buffer.at(i).data); d->buffer.clear(); // "can" stands for "cancel"... very clever. dbcanquery(d->dbproc); @@ -340,9 +369,9 @@ QVariant QTDSResult::handle() const return QVariant(qRegisterMetaType<DBPROCESS *>("DBPROCESS*"), &d->dbproc); } -static inline bool qIsNull(const void *ind) +static inline bool qIsNull(const QTDSColumnData &p) { - return *reinterpret_cast<const DBINT *>(&ind) == -1; + return p.nullbind == -1; } bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index) @@ -364,33 +393,33 @@ bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index) int idx = index + i; switch (d->rec.field(i).type()) { case QVariant::DateTime: - if (qIsNull(d->buffer.at(i * 2 + 1))) { + if (qIsNull(d->buffer.at(i))) { values[idx] = QVariant(QVariant::DateTime); } else { - DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i * 2); + DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i).data; QDate date = QDate::fromString(QLatin1String("1900-01-01"), Qt::ISODate); QTime time = QTime::fromString(QLatin1String("00:00:00"), Qt::ISODate); values[idx] = QDateTime(date.addDays(bdt->dtdays), time.addMSecs(int(bdt->dttime / 0.3))); } break; case QVariant::Int: - if (qIsNull(d->buffer.at(i * 2 + 1))) + if (qIsNull(d->buffer.at(i))) values[idx] = QVariant(QVariant::Int); else - values[idx] = *((int*)d->buffer.at(i * 2)); + values[idx] = *((int*)d->buffer.at(i).data); break; case QVariant::Double: case QVariant::String: - if (qIsNull(d->buffer.at(i * 2 + 1))) + if (qIsNull(d->buffer.at(i))) values[idx] = QVariant(QVariant::String); else - values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i * 2)).trimmed(); + values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i).data).trimmed(); break; case QVariant::ByteArray: { - if (qIsNull(d->buffer.at(i * 2 + 1))) + if (qIsNull(d->buffer.at(i))) values[idx] = QVariant(QVariant::ByteArray); else - values[idx] = QByteArray((const char*)d->buffer.at(i * 2)); + values[idx] = QByteArray((const char*)d->buffer.at(i).data); break; } default: @@ -430,7 +459,7 @@ bool QTDSResult::reset (const QString& query) setSelect((DBCMDROW(d->dbproc) == SUCCEED)); // decide whether or not we are dealing with a SELECT query int numCols = dbnumcols(d->dbproc); if (numCols > 0) { - d->buffer.resize(numCols * 2); + d->buffer.resize(numCols); init(numCols); } for (int i = 0; i < numCols; ++i) { @@ -470,11 +499,11 @@ bool QTDSResult::reset (const QString& query) break; } if (ret == SUCCEED) { - d->buffer[i * 2] = p; - ret = dbnullbind(d->dbproc, i+1, (DBINT*)(&d->buffer[i * 2 + 1])); + d->buffer[i].data = p; + ret = dbnullbind(d->dbproc, i+1, &d->buffer[i].nullbind); } else { - d->buffer[i * 2] = 0; - d->buffer[i * 2 + 1] = 0; + d->buffer[i].data = 0; + d->buffer[i].nullbind = 0; free(p); } if ((ret != SUCCEED) && (ret != -1)) { @@ -512,14 +541,15 @@ QSqlRecord QTDSResult::record() const /////////////////////////////////////////////////////////////////// QTDSDriver::QTDSDriver(QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QTDSDriverPrivate, parent) { init(); } QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent) - : QSqlDriver(parent) + : QSqlDriver(*new QTDSDriverPrivate, parent) { + Q_D(QTDSDriver); init(); d->login = rec; d->hostName = host; @@ -532,12 +562,13 @@ QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QO QVariant QTDSDriver::handle() const { + Q_D(const QTDSDriver); return QVariant(qRegisterMetaType<LOGINREC *>("LOGINREC*"), &d->login); } void QTDSDriver::init() { - d = new QTDSDriverPrivate(); + Q_D(QTDSDriver); d->initialized = (dbinit() == SUCCEED); // the following two code-lines will fail compilation on some FreeTDS versions // just comment them out if you have FreeTDS (you won't get any errors and warnings then) @@ -551,7 +582,6 @@ QTDSDriver::~QTDSDriver() dbmsghandle(0); // dbexit also calls dbclose if necessary dbexit(); - delete d; } bool QTDSDriver::hasFeature(DriverFeature f) const @@ -578,6 +608,7 @@ bool QTDSDriver::open(const QString & db, int /*port*/, const QString& /*connOpts*/) { + Q_D(QTDSDriver); if (isOpen()) close(); if (!d->initialized) { @@ -617,6 +648,7 @@ bool QTDSDriver::open(const QString & db, void QTDSDriver::close() { + Q_D(QTDSDriver); if (isOpen()) { #ifdef Q_USE_SYBASE dbloginfree(d->login); diff --git a/src/sql/drivers/tds/qsql_tds.pri b/src/sql/drivers/tds/qsql_tds.pri index 38aab2f3e4..67d037aa6b 100644 --- a/src/sql/drivers/tds/qsql_tds.pri +++ b/src/sql/drivers/tds/qsql_tds.pri @@ -1,4 +1,4 @@ -HEADERS += $$PWD/qsql_tds.h +HEADERS += $$PWD/qsql_tds_p.h SOURCES += $$PWD/qsql_tds.cpp unix|win32-g++*: { diff --git a/src/sql/drivers/tds/qsql_tds.h b/src/sql/drivers/tds/qsql_tds_p.h index 38cb2dc42e..dd7088a167 100644 --- a/src/sql/drivers/tds/qsql_tds.h +++ b/src/sql/drivers/tds/qsql_tds_p.h @@ -42,9 +42,19 @@ #ifndef QSQL_TDS_H #define QSQL_TDS_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/qsqlresult.h> #include <QtSql/qsqldriver.h> -#include <QtSql/private/qsqlcachedresult_p.h> #ifdef Q_OS_WIN32 #define WIN32_LEAN_AND_MEAN @@ -67,40 +77,14 @@ #define Q_EXPORT_SQLDRIVER_TDS Q_SQL_EXPORT #endif -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -#if 0 -#pragma qt_no_master_include -#pragma qt_sync_stop_processing -#endif - class QTDSDriverPrivate; -class QTDSResultPrivate; class QTDSDriver; -class QTDSResult : public QSqlCachedResult -{ -public: - explicit QTDSResult(const QTDSDriver* db); - ~QTDSResult(); - QVariant handle() const; - -protected: - void cleanup(); - bool reset (const QString& query); - int size(); - int numRowsAffected(); - bool gotoNext(QSqlCachedResult::ValueCache &values, int index); - QSqlRecord record() const; - -private: - QTDSResultPrivate* d; -}; - class Q_EXPORT_SQLDRIVER_TDS QTDSDriver : public QSqlDriver { + Q_DECLARE_PRIVATE(QTDSDriver) Q_OBJECT friend class QTDSResult; public: @@ -132,11 +116,8 @@ protected: bool rollbackTransaction(); private: void init(); - QTDSDriverPrivate *d; }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QSQL_TDS_H |