summaryrefslogtreecommitdiffstats
path: root/src/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql')
-rw-r--r--src/sql/doc/snippets/code/doc_src_sql-driver.cpp55
-rw-r--r--src/sql/doc/snippets/code/doc_src_sql-driver.qdoc12
-rw-r--r--src/sql/doc/src/sql-driver.qdoc63
-rw-r--r--src/sql/kernel/qsqlcachedresult_p.h20
-rw-r--r--src/sql/kernel/qsqldatabase.cpp19
-rw-r--r--src/sql/kernel/qsqldatabase.h9
-rw-r--r--src/sql/kernel/qsqldriver.cpp2
-rw-r--r--src/sql/kernel/qsqldriver.h4
-rw-r--r--src/sql/kernel/qsqldriverplugin.h2
-rw-r--r--src/sql/kernel/qsqlerror.cpp38
-rw-r--r--src/sql/kernel/qsqlerror.h7
-rw-r--r--src/sql/kernel/qsqlfield.cpp57
-rw-r--r--src/sql/kernel/qsqlfield.h4
-rw-r--r--src/sql/kernel/qsqlnulldriver_p.h52
-rw-r--r--src/sql/kernel/qsqlquery.cpp8
-rw-r--r--src/sql/kernel/qsqlrecord.cpp20
-rw-r--r--src/sql/kernel/qsqlresult.cpp12
-rw-r--r--src/sql/models/qsqlquerymodel.cpp24
-rw-r--r--src/sql/models/qsqlquerymodel.h24
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp14
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.h24
-rw-r--r--src/sql/models/qsqltablemodel.cpp14
-rw-r--r--src/sql/models/qsqltablemodel.h30
-rw-r--r--src/sql/models/qsqltablemodel_p.h2
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 &currentField = d->fields.at(i);
+ const auto &currentFieldName = 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)
{