diff options
Diffstat (limited to 'src/sql')
24 files changed, 402 insertions, 114 deletions
diff --git a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp index 75ac9fe134..2c0e824db3 100644 --- a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp +++ b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp @@ -84,3 +84,58 @@ q.exec("execute procedure my_procedure"); q.next(); qDebug() << q.value(0); // outputs the first RETURN/OUT value //! [26] + + +//! [31] +QSqlDatabase: QMYSQL driver not loaded +QSqlDatabase: available drivers: QMYSQL +//! [31] + + +//! [34] +column.contains(QRegularExpression("pattern")); +//! [34] + + +//! [36] +QSqlQuery query(db); +query.setForwardOnly(true); +query.exec("SELECT * FROM table"); +while (query.next()) { + // Handle changes in every iteration of the loop + QVariant v = query.result()->handle(); + if (qstrcmp(v.typeName(), "PGresult*") == 0) { + PGresult *handle = *static_cast<PGresult **>(v.data()); + if (handle != 0) { + // Do something... + } + } +} +//! [36] + + +//! [37] +int value; +QSqlQuery query1(db); +query1.setForwardOnly(true); +query1.exec("select * FROM table1"); +while (query1.next()) { + value = query1.value(0).toInt(); + if (value == 1) { + QSqlQuery query2(db); + query2.exec("update table2 set col=2"); // WRONG: This will discard all results of + } // query1, and cause the loop to quit +} +//! [37] + + +//! [39] +QSqlDatabase db = QSqlDatabase::addDatabase("QODBC3"); +QString connectString = QStringLiteral( + "DRIVER=/path/to/installation/libodbcHDB.so;" + "SERVERNODE=hostname:port;" + "UID=USER;" + "PWD=PASSWORD;" + "SCROLLABLERESULT=true"); +db.setDatabaseName(connectString); +//! [39] diff --git a/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc b/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc index 04ea30915d..d127bdf8a5 100644 --- a/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc +++ b/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc @@ -225,3 +225,15 @@ cd $QTDIR/qtbase/src/plugins/sqldrivers qmake -- OCI_INCDIR=/usr/include/oracle/10.1.0.3/client OCI_LIBDIR=/usr/lib/oracle/10.1.0.3/client/lib "OCI_LIBS=-Wl,-rpath,/usr/lib/oracle/10.1.0.3/client/lib -lclntsh -lnnz10" make sub-oci //! [33] + + +//! [35] +QSqlDatabase: QPSQL driver not loaded +QSqlDatabase: available drivers: QSQLITE QMYSQL QMYSQL3 QODBC QODBC3 QPSQL QPSQL7 +Could not create database object +//! [35] + + +//! [38] +QPSQLDriver::getResult: Query results lost - probably discarded on executing another SQL query. +//! [38] diff --git a/src/sql/doc/src/sql-driver.qdoc b/src/sql/doc/src/sql-driver.qdoc index c8de78dd79..fd95e89812 100644 --- a/src/sql/doc/src/sql-driver.qdoc +++ b/src/sql/doc/src/sql-driver.qdoc @@ -299,6 +299,12 @@ e.g., the SQLSTATEs. Before setting this connect option, consult your ODBC documentation about behavior differences you can expect. + When using the SAP HANA database, the connection has to be + established using the option "SCROLLABLERESULT=TRUE", as the + HANA ODBC driver does not provide scrollable results by default, e.g.: + + \snippet code/doc_src_sql-driver.cpp 39 + If you experience very slow access of the ODBC datasource, make sure that ODBC call tracing is turned off in the ODBC datasource manager. @@ -380,6 +386,45 @@ Binary Large Objects are supported through the \c BYTEA field type in PostgreSQL server versions >= 7.1. + \section3 QPSQL Forward-only query support + + To use forward-only queries, you must build the QPSQL plugin with + PostreSQL client library version 9.2 or later. If the plugin is + built with an older version, then forward-only mode will not be + available - calling QSqlQuery::setForwardOnly() with \c true will + have no effect. + + \warning If you build the QPSQL plugin with PostgreSQL version 9.2 or later, + then you must distribute your application with libpq version 9.2 or later. + Otherwise, loading the QPSQL plugin will fail with the following message: + + \snippet code/doc_src_sql-driver.qdoc 35 + + While navigating the results in forward-only mode, the handle of + QSqlResult may change. Applications that use the low-level handle of + SQL result must get a new handle after each call to any of QSqlResult + fetch functions. Example: + + \snippet code/doc_src_sql-driver.cpp 36 + + While reading the results of a forward-only query with PostgreSQL, + the database connection cannot be used to execute other queries. + This is a limitation of libpq library. Example: + + \snippet code/doc_src_sql-driver.cpp 37 + + This problem will not occur if query1 and query2 use different + database connections, or if we execute query2 after the while loop. + + \note Some methods of QSqlDatabase like tables(), primaryIndex() + implicity execute SQL queries, so these also cannot be used while + navigating the results of forward-only query. + + \note QPSQL will print the following warning if it detects a loss of + query results: + + \snippet code/doc_src_sql-driver.qdoc 38 + \section3 How to Build the QPSQL Plugin on Unix and \macos You need the PostgreSQL client library and headers installed. @@ -404,7 +449,7 @@ \target QTDS \section2 QTDS for Sybase Adaptive Server - \note TDS is no longer used by MS Sql Server, and is superceded by + \note TDS is no longer used by MS Sql Server, and is superseded by \l{QODBC}{ODBC}. QTDS is obsolete from Qt 4.7. It is not possible to set the port with QSqlDatabase::setPort() due to limitations in the @@ -534,6 +579,22 @@ \snippet code/doc_src_sql-driver.qdoc 23 + \section3 Enable REGEXP operator + + SQLite comes with a REGEXP operation. However the needed implementation must + be provided by the user. For convenience a default implementation can be + enabled by \l{QSqlDatabase::setConnectOptions()} {setting the connect + option} \c{QSQLITE_ENABLE_REGEXP} before \l{QSqlDatabase::open()} {the + database connection is opened}. Then a SQL statement like "column REGEXP + 'pattern'" basically expands to the Qt code + + \snippet code/doc_src_sql-driver.cpp 34 + + For better performance the regular expressions are cached internally. By + default the cache size is 25, but it can be changed through the option's + value. For example passing "\c{QSQLITE_ENABLE_REGEXP=10}" reduces the + cache size to 10. + \section3 QSQLITE File Format Compatibility SQLite minor releases sometimes break file format forward compatibility. diff --git a/src/sql/kernel/qsqlcachedresult_p.h b/src/sql/kernel/qsqlcachedresult_p.h index 9bcfd49f1a..543a902554 100644 --- a/src/sql/kernel/qsqlcachedresult_p.h +++ b/src/sql/kernel/qsqlcachedresult_p.h @@ -78,20 +78,20 @@ protected: virtual bool gotoNext(ValueCache &values, int index) = 0; - QVariant data(int i) Q_DECL_OVERRIDE; - bool isNull(int i) Q_DECL_OVERRIDE; - bool fetch(int i) Q_DECL_OVERRIDE; - bool fetchNext() Q_DECL_OVERRIDE; - bool fetchPrevious() Q_DECL_OVERRIDE; - bool fetchFirst() Q_DECL_OVERRIDE; - bool fetchLast() Q_DECL_OVERRIDE; + QVariant data(int i) override; + bool isNull(int i) override; + bool fetch(int i) override; + bool fetchNext() override; + bool fetchPrevious() override; + bool fetchFirst() override; + bool fetchLast() override; int colCount() const; ValueCache &cache(); - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - void detachFromResultSet() Q_DECL_OVERRIDE; - void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) Q_DECL_OVERRIDE; + void virtual_hook(int id, void *data) override; + void detachFromResultSet() override; + void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) override; private: bool cacheNext(); }; diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 06c5f56d50..291b35f8a6 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -50,6 +50,7 @@ #include "private/qsqlnulldriver_p.h" #include "qmutex.h" #include "qhash.h" +#include "qthread.h" #include <stdlib.h> QT_BEGIN_NAMESPACE @@ -58,11 +59,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QSqlDriverFactoryInterface_iid, QLatin1String("/sqldrivers"))) -#if !defined(Q_CC_MSVC) || _MSC_VER >= 1900 -// ### Qt6: remove the #ifdef -const -#endif -char *QSqlDatabase::defaultConnection = const_cast<char *>("qt_sql_default_connection"); +const char *QSqlDatabase::defaultConnection = const_cast<char *>("qt_sql_default_connection"); typedef QHash<QString, QSqlDriverCreatorBase*> DriverDict; @@ -135,6 +132,8 @@ QSqlDatabasePrivate::QSqlDatabasePrivate(const QSqlDatabasePrivate &other) : ref connOptions = other.connOptions; driver = other.driver; precisionPolicy = other.precisionPolicy; + if (driver) + driver->setNumericalPrecisionPolicy(other.driver->numericalPrecisionPolicy()); } QSqlDatabasePrivate::~QSqlDatabasePrivate() @@ -230,6 +229,11 @@ QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open) dict->lock.lockForRead(); QSqlDatabase db = dict->value(name); dict->lock.unlock(); + if (db.driver() && db.driver()->thread() != QThread::currentThread()) { + qWarning("QSqlDatabasePrivate::database: requested database does not belong to the calling thread."); + return QSqlDatabase(); + } + if (db.isValid() && !db.isOpen() && open) { if (!db.open()) qWarning() << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text(); @@ -253,6 +257,8 @@ void QSqlDatabasePrivate::copy(const QSqlDatabasePrivate *other) port = other->port; connOptions = other->connOptions; precisionPolicy = other->precisionPolicy; + if (driver) + driver->setNumericalPrecisionPolicy(other->driver->numericalPrecisionPolicy()); } void QSqlDatabasePrivate::disable() @@ -307,7 +313,7 @@ void QSqlDatabasePrivate::disable() */ /*! - \fn QSqlDriver *QSqlDriverCreator::createObject() const + \fn template <class T> QSqlDriver *QSqlDriverCreator<T>::createObject() const \reimp */ @@ -1186,6 +1192,7 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const \li QSQLITE_OPEN_READONLY \li QSQLITE_OPEN_URI \li QSQLITE_ENABLE_SHARED_CACHE + \li QSQLITE_ENABLE_REGEXP \endlist \li diff --git a/src/sql/kernel/qsqldatabase.h b/src/sql/kernel/qsqldatabase.h index 0b4aca8cdd..3aadab9b2f 100644 --- a/src/sql/kernel/qsqldatabase.h +++ b/src/sql/kernel/qsqldatabase.h @@ -64,7 +64,7 @@ template <class T> class QSqlDriverCreator : public QSqlDriverCreatorBase { public: - QSqlDriver *createObject() const Q_DECL_OVERRIDE { return new T; } + QSqlDriver *createObject() const override { return new T; } }; class Q_SQL_EXPORT QSqlDatabase @@ -111,12 +111,7 @@ public: QSqlDriver* driver() const; - static -#if !defined(Q_CC_MSVC) || _MSC_VER >= 1900 - // ### Qt6: remove the #ifdef - const -#endif - char *defaultConnection; + static const char *defaultConnection; static QSqlDatabase addDatabase(const QString& type, const QString& connectionName = QLatin1String(defaultConnection)); diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp index 6fe5b351dc..2d306e9fae 100644 --- a/src/sql/kernel/qsqldriver.cpp +++ b/src/sql/kernel/qsqldriver.cpp @@ -672,7 +672,7 @@ QString QSqlDriver::formatValue(const QSqlField &field, bool trimStrings) const break; } } - // fall through + Q_FALLTHROUGH(); default: r = field.value().toString(); break; diff --git a/src/sql/kernel/qsqldriver.h b/src/sql/kernel/qsqldriver.h index 1296bd5d51..1e03be48d3 100644 --- a/src/sql/kernel/qsqldriver.h +++ b/src/sql/kernel/qsqldriver.h @@ -89,7 +89,7 @@ public: DB2 }; - explicit QSqlDriver(QObject *parent = Q_NULLPTR); + explicit QSqlDriver(QObject *parent = nullptr); ~QSqlDriver(); virtual bool isOpen() const; bool isOpenError() const; @@ -139,7 +139,7 @@ Q_SIGNALS: void notification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload); protected: - QSqlDriver(QSqlDriverPrivate &dd, QObject *parent = Q_NULLPTR); + QSqlDriver(QSqlDriverPrivate &dd, QObject *parent = nullptr); virtual void setOpen(bool o); virtual void setOpenError(bool e); virtual void setLastError(const QSqlError& e); diff --git a/src/sql/kernel/qsqldriverplugin.h b/src/sql/kernel/qsqldriverplugin.h index c0f4c00943..001368a291 100644 --- a/src/sql/kernel/qsqldriverplugin.h +++ b/src/sql/kernel/qsqldriverplugin.h @@ -55,7 +55,7 @@ class Q_SQL_EXPORT QSqlDriverPlugin : public QObject { Q_OBJECT public: - explicit QSqlDriverPlugin(QObject *parent = Q_NULLPTR); + explicit QSqlDriverPlugin(QObject *parent = nullptr); ~QSqlDriverPlugin(); virtual QSqlDriver *create(const QString &key) = 0; diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp index d1fc5d4585..41ea497ad7 100644 --- a/src/sql/kernel/qsqlerror.cpp +++ b/src/sql/kernel/qsqlerror.cpp @@ -91,6 +91,7 @@ public: */ /*! + \fn QSqlError::QSqlError(const QString &driverText, const QString &databaseText, ErrorType type, int number) \obsolete Constructs an error containing the driver error text \a @@ -98,6 +99,34 @@ public: type \a type and the optional error number \a number. */ +/*! \fn QSqlError::QSqlError(QSqlError &&other) + Move-constructs a QSqlError instance, making it point at the same + object that \a other was pointing to. + + \note The moved-from object \a other is placed in a + partially-formed state, in which the only valid operations are + destruction and assignment of a new value. + + \since 5.10 +*/ + +/*! \fn QSqlError::operator=(QSqlError &&other) + Move-assigns \a other to this QSqlError instance. + + \note The moved-from object \a other is placed in a + partially-formed state, in which the only valid operations are + destruction and assignment of a new value. + + \since 5.10 +*/ + +/*! \fn QSqlError::swap(QSqlError &other) + Swaps error \a other with this error. This operation is very fast + and never fails. + + \since 5.10 +*/ + #if QT_DEPRECATED_SINCE(5, 3) QSqlError::QSqlError(const QString& driverText, const QString& databaseText, ErrorType type, int number) @@ -116,8 +145,10 @@ QSqlError::QSqlError(const QString& driverText, const QString& databaseText, Err Constructs an error containing the driver error text \a driverText, the database-specific error text \a databaseText, the type \a type and the error code \a code. -*/ + \note DB2: It is possible for DB2 to report more than one error code. + When this happens, \c ; is used as separator between the error codes. +*/ QSqlError::QSqlError(const QString &driverText, const QString &databaseText, ErrorType type, const QString &code) { @@ -146,7 +177,10 @@ QSqlError::QSqlError(const QSqlError& other) QSqlError& QSqlError::operator=(const QSqlError& other) { - *d = *other.d; + if (d) + *d = *other.d; + else + d = new QSqlErrorPrivate(*other.d); return *this; } diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h index 0ccd32159d..6dac47a7fe 100644 --- a/src/sql/kernel/qsqlerror.h +++ b/src/sql/kernel/qsqlerror.h @@ -66,11 +66,16 @@ public: ErrorType type = NoError, const QString &errorCode = QString()); QSqlError(const QSqlError& other); + QSqlError(QSqlError &&other) Q_DECL_NOTHROW : d(other.d) { other.d = nullptr; } QSqlError& operator=(const QSqlError& other); + QSqlError &operator=(QSqlError &&other) Q_DECL_NOTHROW { swap(other); return *this; } + bool operator==(const QSqlError& other) const; bool operator!=(const QSqlError& other) const; ~QSqlError(); + void swap(QSqlError &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + QString driverText() const; QString databaseText() const; ErrorType type() const; @@ -102,6 +107,8 @@ private: }; }; +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QSqlError) + #ifndef QT_NO_DEBUG_STREAM Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlError &); #endif diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp index bb810b11df..782ab0d71c 100644 --- a/src/sql/kernel/qsqlfield.cpp +++ b/src/sql/kernel/qsqlfield.cpp @@ -47,9 +47,9 @@ class QSqlFieldPrivate { public: QSqlFieldPrivate(const QString &name, - QVariant::Type type) : + QVariant::Type type, const QString &tableName) : ref(1), nm(name), ro(false), type(type), req(QSqlField::Unknown), - len(-1), prec(-1), tp(-1), gen(true), autoval(false) + len(-1), prec(-1), tp(-1), gen(true), autoval(false), table(tableName) { } @@ -64,7 +64,8 @@ public: def(other.def), tp(other.tp), gen(other.gen), - autoval(other.autoval) + autoval(other.autoval), + table(other.table) {} bool operator==(const QSqlFieldPrivate& other) const @@ -77,7 +78,8 @@ public: && prec == other.prec && def == other.def && gen == other.gen - && autoval == other.autoval); + && autoval == other.autoval + && table == other.table); } QAtomicInt ref; @@ -91,6 +93,7 @@ public: int tp; uint gen: 1; uint autoval: 1; + QString table; }; @@ -152,15 +155,29 @@ public: */ /*! + Constructs an empty field called \a fieldName of variant type \a type. + + \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(), + setGenerated(), setReadOnly() +*/ +QSqlField::QSqlField(const QString &fieldName, QVariant::Type type) +{ + d = new QSqlFieldPrivate(fieldName, type, QString()); + val = QVariant(type); +} + +/*! + \overload Constructs an empty field called \a fieldName of variant type \a - type. + type in \a table. \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(), setGenerated(), setReadOnly() */ -QSqlField::QSqlField(const QString& fieldName, QVariant::Type type) +QSqlField::QSqlField(const QString &fieldName, QVariant::Type type, + const QString &table) { - d = new QSqlFieldPrivate(fieldName, type); + d = new QSqlFieldPrivate(fieldName, type, table); val = QVariant(type); } @@ -518,6 +535,7 @@ QDebug operator<<(QDebug dbg, const QSqlField &f) QDebugStateSaver saver(dbg); dbg.nospace(); dbg << "QSqlField(" << f.name() << ", " << QMetaType::typeName(f.type()); + dbg << ", tableName: " << (f.tableName().isEmpty() ? QStringLiteral("(not specified)") : f.tableName()); if (f.length() >= 0) dbg << ", length: " << f.length(); if (f.precision() >= 0) @@ -565,4 +583,29 @@ void QSqlField::setAutoValue(bool autoVal) d->autoval = autoVal; } +/*! + Sets the tableName of the field to \a table. + + \sa tableName() +*/ +void QSqlField::setTableName(const QString &table) +{ + detach(); + d->table = table; +} + +/*! + Returns the tableName of the field. + + \note When using the QPSQL driver, due to limitations in the libpq library, + the \c tableName() field is not populated in a QSqlField resulting + from a QSqlRecord obtained by QSqlQuery::record() of a forward-only query. + + \sa setTableName() +*/ +QString QSqlField::tableName() const +{ + return d->table; +} + QT_END_NAMESPACE diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h index 0d8c51f801..8650ba8715 100644 --- a/src/sql/kernel/qsqlfield.h +++ b/src/sql/kernel/qsqlfield.h @@ -56,6 +56,8 @@ public: explicit QSqlField(const QString& fieldName = QString(), QVariant::Type type = QVariant::Invalid); + QSqlField(const QString &fieldName, QVariant::Type type, + const QString &tableName); QSqlField(const QSqlField& other); QSqlField& operator=(const QSqlField& other); @@ -68,6 +70,8 @@ public: { return val; } void setName(const QString& name); QString name() const; + void setTableName(const QString &tableName); + QString tableName() const; bool isNull() const; void setReadOnly(bool readOnly); bool isReadOnly() const; diff --git a/src/sql/kernel/qsqlnulldriver_p.h b/src/sql/kernel/qsqlnulldriver_p.h index 92d8d30485..7a40199d71 100644 --- a/src/sql/kernel/qsqlnulldriver_p.h +++ b/src/sql/kernel/qsqlnulldriver_p.h @@ -66,27 +66,27 @@ public: { QSqlResult::setLastError( QSqlError(QLatin1String("Driver not loaded"), QLatin1String("Driver not loaded"), QSqlError::ConnectionError)); } protected: - inline QVariant data(int) Q_DECL_OVERRIDE { return QVariant(); } - inline bool reset (const QString&) Q_DECL_OVERRIDE { return false; } - inline bool fetch(int) Q_DECL_OVERRIDE { return false; } - inline bool fetchFirst() Q_DECL_OVERRIDE { return false; } - inline bool fetchLast() Q_DECL_OVERRIDE { return false; } - inline bool isNull(int) Q_DECL_OVERRIDE { return false; } - inline int size() Q_DECL_OVERRIDE { return -1; } - inline int numRowsAffected() Q_DECL_OVERRIDE { return 0; } + inline QVariant data(int) override { return QVariant(); } + inline bool reset (const QString&) override { return false; } + inline bool fetch(int) override { return false; } + inline bool fetchFirst() override { return false; } + inline bool fetchLast() override { return false; } + inline bool isNull(int) override { return false; } + inline int size() override { return -1; } + inline int numRowsAffected() override { return 0; } - inline void setAt(int) Q_DECL_OVERRIDE {} - inline void setActive(bool) Q_DECL_OVERRIDE {} - inline void setLastError(const QSqlError&) Q_DECL_OVERRIDE {} - inline void setQuery(const QString&) Q_DECL_OVERRIDE {} - inline void setSelect(bool) Q_DECL_OVERRIDE {} - inline void setForwardOnly(bool) Q_DECL_OVERRIDE {} + inline void setAt(int) override {} + inline void setActive(bool) override {} + inline void setLastError(const QSqlError&) override {} + inline void setQuery(const QString&) override {} + inline void setSelect(bool) override {} + inline void setForwardOnly(bool) override {} - inline bool exec() Q_DECL_OVERRIDE { return false; } - inline bool prepare(const QString&) Q_DECL_OVERRIDE { return false; } - inline bool savePrepare(const QString&) Q_DECL_OVERRIDE { return false; } - inline void bindValue(int, const QVariant&, QSql::ParamType) Q_DECL_OVERRIDE {} - inline void bindValue(const QString&, const QVariant&, QSql::ParamType) Q_DECL_OVERRIDE {} + inline bool exec() override { return false; } + inline bool prepare(const QString&) override { return false; } + inline bool savePrepare(const QString&) override { return false; } + inline void bindValue(int, const QVariant&, QSql::ParamType) override {} + inline void bindValue(const QString&, const QVariant&, QSql::ParamType) override {} }; class QSqlNullDriver : public QSqlDriver @@ -95,16 +95,16 @@ public: inline QSqlNullDriver(): QSqlDriver() { QSqlDriver::setLastError( QSqlError(QLatin1String("Driver not loaded"), QLatin1String("Driver not loaded"), QSqlError::ConnectionError)); } - inline bool hasFeature(DriverFeature) const Q_DECL_OVERRIDE { return false; } - inline bool open(const QString &, const QString &, const QString &, const QString &, int, const QString&) Q_DECL_OVERRIDE + inline bool hasFeature(DriverFeature) const override { return false; } + inline bool open(const QString &, const QString &, const QString &, const QString &, int, const QString&) override { return false; } - inline void close() Q_DECL_OVERRIDE {} - inline QSqlResult *createResult() const Q_DECL_OVERRIDE { return new QSqlNullResult(this); } + inline void close() override {} + inline QSqlResult *createResult() const override { return new QSqlNullResult(this); } protected: - inline void setOpen(bool) Q_DECL_OVERRIDE {} - inline void setOpenError(bool) Q_DECL_OVERRIDE {} - inline void setLastError(const QSqlError&) Q_DECL_OVERRIDE {} + inline void setOpen(bool) override {} + inline void setOpenError(bool) override {} + inline void setLastError(const QSqlError&) override {} }; QT_END_NAMESPACE diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp index b89d20976f..628bfa1880 100644 --- a/src/sql/kernel/qsqlquery.cpp +++ b/src/sql/kernel/qsqlquery.cpp @@ -878,6 +878,14 @@ bool QSqlQuery::isForwardOnly() const \note Calling setForwardOnly after execution of the query will result in unexpected results at best, and crashes at worst. + \note To make sure the forward-only query completed successfully, + the application should check lastError() for an error not only after + executing the query, but also after navigating the query results. + + \warning PostgreSQL: While navigating the query results in forward-only + mode, do not execute any other SQL command on the same database + connection. This will cause the query results to be lost. + \sa isForwardOnly(), next(), seek(), QSqlResult::setForwardOnly() */ void QSqlQuery::setForwardOnly(bool forward) diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp index d5adff67a4..ecbe3eacdb 100644 --- a/src/sql/kernel/qsqlrecord.cpp +++ b/src/sql/kernel/qsqlrecord.cpp @@ -232,10 +232,24 @@ QString QSqlRecord::fieldName(int index) const int QSqlRecord::indexOf(const QString& name) const { - QString nm = name.toUpper(); - for (int i = 0; i < count(); ++i) { - if (d->fields.at(i).name().toUpper() == nm) // TODO: case-insensitive comparison + QStringRef tableName; + QStringRef fieldName(&name); + const int idx = name.indexOf(QLatin1Char('.')); + if (idx != -1) { + tableName = name.leftRef(idx); + fieldName = name.midRef(idx + 1); + } + const int cnt = count(); + for (int i = 0; i < cnt; ++i) { + // Check the passed in name first in case it is an alias using a dot. + // Then check if both the table and field match when there is a table name specified. + const auto ¤tField = d->fields.at(i); + const auto ¤tFieldName = currentField.name(); + if (currentFieldName.compare(name, Qt::CaseInsensitive) == 0 + || (idx != -1 && currentFieldName.compare(fieldName, Qt::CaseInsensitive) == 0 + && currentField.tableName().compare(tableName, Qt::CaseInsensitive) == 0)) { return i; + } } return -1; } diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp index f79c1c71cd..cdb1379502 100644 --- a/src/sql/kernel/qsqlresult.cpp +++ b/src/sql/kernel/qsqlresult.cpp @@ -565,6 +565,14 @@ bool QSqlResult::isForwardOnly() const \note Calling setForwardOnly after execution of the query will result in unexpected results at best, and crashes at worst. + \note To make sure the forward-only query completed successfully, + the application should check lastError() for an error not only after + executing the query, but also after navigating the query results. + + \warning PostgreSQL: While navigating the query results in forward-only + mode, do not execute any other SQL command on the same database + connection. This will cause the query results to be lost. + \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly() */ void QSqlResult::setForwardOnly(bool forward) @@ -1002,6 +1010,10 @@ bool QSqlResult::nextResult() \warning The handle can be NULL if the result was not executed yet. + \warning PostgreSQL: in forward-only mode, the handle of QSqlResult can change + after calling fetch(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious(), + nextResult(). + The handle returned here is database-dependent, you should query the type name of the variant before accessing it. diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index 864c5b9946..c0b1061c6b 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -212,6 +212,30 @@ bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const return (!parent.isValid() && !d->atEnd); } +/*! + \since 5.10 + \reimp + + Returns the model's role names. + + Qt defines only one role for the QSqlQueryModel: + + \table + \header + \li Qt Role + \li QML Role Name + \row + \li Qt::DisplayRole + \li display + \endtable +*/ +QHash<int, QByteArray> QSqlQueryModel::roleNames() const +{ + return QHash<int, QByteArray> { + { Qt::DisplayRole, QByteArrayLiteral("display") } + }; +} + /*! \internal */ void QSqlQueryModel::beginInsertRows(const QModelIndex &parent, int first, int last) diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h index f786f71300..869a5f030c 100644 --- a/src/sql/models/qsqlquerymodel.h +++ b/src/sql/models/qsqlquerymodel.h @@ -58,22 +58,22 @@ class Q_SQL_EXPORT QSqlQueryModel: public QAbstractTableModel Q_DECLARE_PRIVATE(QSqlQueryModel) public: - explicit QSqlQueryModel(QObject *parent = Q_NULLPTR); + explicit QSqlQueryModel(QObject *parent = nullptr); virtual ~QSqlQueryModel(); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; QSqlRecord record(int row) const; QSqlRecord record() const; - QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int role = Qt::DisplayRole) const override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, - int role = Qt::EditRole) Q_DECL_OVERRIDE; + int role = Qt::EditRole) override; - bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; + bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; + bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; void setQuery(const QSqlQuery &query); void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase()); @@ -83,8 +83,10 @@ public: QSqlError lastError() const; - void fetchMore(const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool canFetchMore(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + void fetchMore(const QModelIndex &parent = QModelIndex()) override; + bool canFetchMore(const QModelIndex &parent = QModelIndex()) const override; + + QHash<int, QByteArray> roleNames() const override; protected: void beginInsertRows(const QModelIndex &parent, int first, int last); @@ -105,7 +107,7 @@ protected: virtual QModelIndex indexInQuery(const QModelIndex &item) const; void setLastError(const QSqlError &error); - QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = Q_NULLPTR); + QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = nullptr); }; QT_END_NAMESPACE diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index 9d6daa2634..1f590c4ab2 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -100,6 +100,12 @@ typedef QSqlRelationalTableModelSql Sql; */ /*! + \fn void QSqlRelation::swap(QSqlRelation &other) + + Swaps \c this with \a other. + */ + +/*! \fn QString QSqlRelation::tableName() const Returns the name of the table to which a foreign key refers. @@ -156,7 +162,7 @@ class QRelatedTableModel : public QSqlTableModel { public: QRelatedTableModel(QRelation *rel, QObject *parent = 0, QSqlDatabase db = QSqlDatabase()); - bool select() Q_DECL_OVERRIDE; + bool select() override; private: bool firstSelect; QRelation *relation; @@ -268,12 +274,12 @@ public: {} QString fullyQualifiedFieldName(const QString &tableName, const QString &fieldName) const; - int nameToIndex(const QString &name) const Q_DECL_OVERRIDE; + int nameToIndex(const QString &name) const override; mutable QVector<QRelation> relations; QSqlRecord baseRec; // the record without relations void clearChanges(); - void clearCache() Q_DECL_OVERRIDE; - void revertCachedRow(int row) Q_DECL_OVERRIDE; + void clearCache() override; + void revertCachedRow(int row) override; void translateFieldNames(QSqlRecord &values) const; QSqlRelationalTableModel::JoinMode joinMode; diff --git a/src/sql/models/qsqlrelationaltablemodel.h b/src/sql/models/qsqlrelationaltablemodel.h index f8b08b089f..90b7a6481f 100644 --- a/src/sql/models/qsqlrelationaltablemodel.h +++ b/src/sql/models/qsqlrelationaltablemodel.h @@ -88,31 +88,31 @@ public: LeftJoin }; - explicit QSqlRelationalTableModel(QObject *parent = Q_NULLPTR, + explicit QSqlRelationalTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()); virtual ~QSqlRelationalTableModel(); - QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; - bool setData(const QModelIndex &item, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; - bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &item, const QVariant &value, int role = Qt::EditRole) override; + bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; - void clear() Q_DECL_OVERRIDE; - bool select() Q_DECL_OVERRIDE; + void clear() override; + bool select() override; - void setTable(const QString &tableName) Q_DECL_OVERRIDE; + void setTable(const QString &tableName) override; virtual void setRelation(int column, const QSqlRelation &relation); QSqlRelation relation(int column) const; virtual QSqlTableModel *relationModel(int column) const; void setJoinMode( QSqlRelationalTableModel::JoinMode joinMode ); public Q_SLOTS: - void revertRow(int row) Q_DECL_OVERRIDE; + void revertRow(int row) override; protected: - QString selectStatement() const Q_DECL_OVERRIDE; - bool updateRowInTable(int row, const QSqlRecord &values) Q_DECL_OVERRIDE; - bool insertRowIntoTable(const QSqlRecord &values) Q_DECL_OVERRIDE; - QString orderByClause() const Q_DECL_OVERRIDE; + QString selectStatement() const override; + bool updateRowInTable(int row, const QSqlRecord &values) override; + bool insertRowIntoTable(const QSqlRecord &values) override; + QString orderByClause() const override; private: Q_DECLARE_PRIVATE(QSqlRelationalTableModel) diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index c0706ac22d..05feb87466 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -477,9 +477,9 @@ QVariant QSqlTableModel::data(const QModelIndex &index, int role) const if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole)) return QVariant(); - const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(index.row()); - if (mrow.op() != QSqlTableModelPrivate::None) - return mrow.rec().value(index.column()); + const auto it = d->cache.constFind(index.row()); + if (it != d->cache.constEnd() && it->op() != QSqlTableModelPrivate::None) + return it->rec().value(index.column()); return QSqlQueryModel::data(index, role); } @@ -532,7 +532,10 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const if (!index.isValid()) return false; - const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); + const auto it = d->cache.constFind(index.row()); + if (it == d->cache.constEnd()) + return false; + const QSqlTableModelPrivate::ModifiedRow &row = *it; if (row.submitted()) return false; @@ -1231,7 +1234,8 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const { Q_D(const QSqlTableModel); - if (d->cache.value(item.row()).insert()) + const auto it = d->cache.constFind(item.row()); + if (it != d->cache.constEnd() && it->insert()) return QModelIndex(); const int rowOffset = d->insertCount(item.row()); diff --git a/src/sql/models/qsqltablemodel.h b/src/sql/models/qsqltablemodel.h index 6a62c6993d..77b0517c74 100644 --- a/src/sql/models/qsqltablemodel.h +++ b/src/sql/models/qsqltablemodel.h @@ -60,25 +60,25 @@ class Q_SQL_EXPORT QSqlTableModel: public QSqlQueryModel public: enum EditStrategy {OnFieldChange, OnRowChange, OnManualSubmit}; - explicit QSqlTableModel(QObject *parent = Q_NULLPTR, QSqlDatabase db = QSqlDatabase()); + explicit QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()); virtual ~QSqlTableModel(); virtual void setTable(const QString &tableName); QString tableName() const; - Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const override; QSqlRecord record() const; QSqlRecord record(int row) const; - QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; bool isDirty() const; bool isDirty(const QModelIndex &index) const; - void clear() Q_DECL_OVERRIDE; + void clear() override; virtual void setEditStrategy(EditStrategy strategy); EditStrategy editStrategy() const; @@ -87,17 +87,17 @@ public: QSqlDatabase database() const; int fieldIndex(const QString &fieldName) const; - void sort(int column, Qt::SortOrder order) Q_DECL_OVERRIDE; + void sort(int column, Qt::SortOrder order) override; virtual void setSort(int column, Qt::SortOrder order); QString filter() const; virtual void setFilter(const QString &filter); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; - bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; + bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; bool insertRecord(int row, const QSqlRecord &record); bool setRecord(int row, const QSqlRecord &record); @@ -108,8 +108,8 @@ public Q_SLOTS: virtual bool select(); virtual bool selectRow(int row); - bool submit() Q_DECL_OVERRIDE; - void revert() Q_DECL_OVERRIDE; + bool submit() override; + void revert() override; bool submitAll(); void revertAll(); @@ -122,7 +122,7 @@ Q_SIGNALS: void beforeDelete(int row); protected: - QSqlTableModel(QSqlTableModelPrivate &dd, QObject *parent = Q_NULLPTR, QSqlDatabase db = QSqlDatabase()); + QSqlTableModel(QSqlTableModelPrivate &dd, QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()); virtual bool updateRowInTable(int row, const QSqlRecord &values); virtual bool insertRowIntoTable(const QSqlRecord &values); @@ -132,7 +132,7 @@ protected: void setPrimaryKey(const QSqlIndex &key); void setQuery(const QSqlQuery &query); - QModelIndex indexInQuery(const QModelIndex &item) const Q_DECL_OVERRIDE; + QModelIndex indexInQuery(const QModelIndex &item) const override; QSqlRecord primaryValues(int row) const; }; diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index 3b64cdfa47..490bb48a24 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -117,7 +117,7 @@ public: m_rec = m_db_values; setGenerated(m_rec, m_op == Delete); } - inline QSqlRecord rec() const { return m_rec; } + inline const QSqlRecord &rec() const { return m_rec; } inline QSqlRecord& recRef() { return m_rec; } inline void setValue(int c, const QVariant &v) { |