summaryrefslogtreecommitdiffstats
path: root/src/sql/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/kernel')
-rw-r--r--src/sql/kernel/qsqlcachedresult.cpp3
-rw-r--r--src/sql/kernel/qsqldatabase.cpp405
-rw-r--r--src/sql/kernel/qsqldatabase.h13
-rw-r--r--src/sql/kernel/qsqldriver.cpp60
-rw-r--r--src/sql/kernel/qsqldriver.h6
-rw-r--r--src/sql/kernel/qsqlerror.cpp53
-rw-r--r--src/sql/kernel/qsqlerror.h20
-rw-r--r--src/sql/kernel/qsqlfield.cpp287
-rw-r--r--src/sql/kernel/qsqlfield.h35
-rw-r--r--src/sql/kernel/qsqlindex.cpp71
-rw-r--r--src/sql/kernel/qsqlindex.h20
-rw-r--r--src/sql/kernel/qsqlquery.cpp190
-rw-r--r--src/sql/kernel/qsqlquery.h15
-rw-r--r--src/sql/kernel/qsqlrecord.cpp222
-rw-r--r--src/sql/kernel/qsqlrecord.h45
-rw-r--r--src/sql/kernel/qsqlresult.cpp123
-rw-r--r--src/sql/kernel/qsqlresult.h13
-rw-r--r--src/sql/kernel/qsqlresult_p.h7
18 files changed, 919 insertions, 669 deletions
diff --git a/src/sql/kernel/qsqlcachedresult.cpp b/src/sql/kernel/qsqlcachedresult.cpp
index 2e453fe763..3cc0b6419a 100644
--- a/src/sql/kernel/qsqlcachedresult.cpp
+++ b/src/sql/kernel/qsqlcachedresult.cpp
@@ -3,7 +3,6 @@
#include "private/qsqlcachedresult_p.h"
-#include <qdatetime.h>
#include <qvariant.h>
#include <QtSql/private/qsqldriver_p.h>
@@ -21,7 +20,7 @@ QT_BEGIN_NAMESPACE
to indicate that we are not interested in the actual values.
*/
-static const uint initial_cache_size = 128;
+static constexpr qsizetype initial_cache_size = 128;
void QSqlCachedResultPrivate::cleanup()
{
diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp
index 920740fcbe..6aab93bd34 100644
--- a/src/sql/kernel/qsqldatabase.cpp
+++ b/src/sql/kernel/qsqldatabase.cpp
@@ -3,55 +3,72 @@
#include "qsqldatabase.h"
#include "qsqlquery.h"
-#include "qdebug.h"
+#include "qloggingcategory.h"
#include "qcoreapplication.h"
#include "qreadwritelock.h"
-#include "qsqlresult.h"
#include "qsqldriver.h"
+#include "qsqldriver_p.h"
#include "qsqldriverplugin.h"
#include "qsqlindex.h"
+#include "QtCore/qapplicationstatic.h"
#include "private/qfactoryloader_p.h"
#include "private/qsqlnulldriver_p.h"
-#include "qmutex.h"
#include "qhash.h"
#include "qthread.h"
-#include <stdlib.h>
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcSqlDb, "qt.sql.qsqldatabase")
+
using namespace Qt::StringLiterals;
+#define CHECK_QCOREAPPLICATION \
+ if (Q_UNLIKELY(!QCoreApplication::instance())) { \
+ qCWarning(lcSqlDb, "QSqlDatabase requires a QCoreApplication"); \
+ return; \
+ }
+#define CHECK_QCOREAPPLICATION_RETVAL \
+ if (Q_UNLIKELY(!QCoreApplication::instance())) { \
+ qCWarning(lcSqlDb, "QSqlDatabase requires a QCoreApplication"); \
+ return {}; \
+ }
+
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
(QSqlDriverFactoryInterface_iid, "/sqldrivers"_L1))
-const char *QSqlDatabase::defaultConnection = const_cast<char *>("qt_sql_default_connection");
-
-typedef QHash<QString, QSqlDriverCreatorBase*> DriverDict;
+const char *QSqlDatabase::defaultConnection = "qt_sql_default_connection";
-class QConnectionDict: public QHash<QString, QSqlDatabase>
-{
-public:
- inline bool contains_ts(const QString &key)
+namespace {
+ struct QtSqlGlobals
{
- QReadLocker locker(&lock);
- return contains(key);
- }
- inline QStringList keys_ts() const
- {
- QReadLocker locker(&lock);
- return keys();
- }
-
- mutable QReadWriteLock lock;
-};
-Q_GLOBAL_STATIC(QConnectionDict, dbDict)
+ ~QtSqlGlobals();
+ QSqlDatabase connection(const QString &key) const
+ {
+ QReadLocker locker(&lock);
+ return connections.value(key);
+ }
+ bool connectionExists(const QString &key) const
+ {
+ QReadLocker locker(&lock);
+ return connections.contains(key);
+ }
+ QStringList connectionNames() const
+ {
+ QReadLocker locker(&lock);
+ return connections.keys();
+ }
+ mutable QReadWriteLock lock;
+ QHash<QString, QSqlDriverCreatorBase*> registeredDrivers;
+ QHash<QString, QSqlDatabase> connections;
+ };
+}
+Q_APPLICATION_STATIC(QtSqlGlobals, s_sqlGlobals)
class QSqlDatabasePrivate
{
public:
- QSqlDatabasePrivate(QSqlDatabase *d, QSqlDriver *dr = nullptr):
+ QSqlDatabasePrivate(QSqlDriver *dr):
ref(1),
- q(d),
driver(dr),
port(-1)
{
@@ -64,7 +81,6 @@ public:
void disable();
QAtomicInt ref;
- QSqlDatabase *q;
QSqlDriver* driver;
QString dbname;
QString uname;
@@ -81,13 +97,10 @@ public:
static void addDatabase(const QSqlDatabase &db, const QString & name);
static void removeDatabase(const QString& name);
static void invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn = true);
- static DriverDict &driverDict();
- static void cleanConnections();
};
QSqlDatabasePrivate::QSqlDatabasePrivate(const QSqlDatabasePrivate &other) : ref(1)
{
- q = other.q;
dbname = other.dbname;
uname = other.uname;
pword = other.pword;
@@ -107,51 +120,25 @@ QSqlDatabasePrivate::~QSqlDatabasePrivate()
delete driver;
}
-void QSqlDatabasePrivate::cleanConnections()
-{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
-
- QConnectionDict::iterator it = dict->begin();
- while (it != dict->end()) {
- invalidateDb(it.value(), it.key(), false);
- ++it;
- }
- dict->clear();
-}
-
-static bool qDriverDictInit = false;
-static void cleanDriverDict()
+QtSqlGlobals::~QtSqlGlobals()
{
- qDeleteAll(QSqlDatabasePrivate::driverDict());
- QSqlDatabasePrivate::driverDict().clear();
- QSqlDatabasePrivate::cleanConnections();
- qDriverDictInit = false;
-}
-
-DriverDict &QSqlDatabasePrivate::driverDict()
-{
- static DriverDict dict;
- if (!qDriverDictInit) {
- qDriverDictInit = true;
- qAddPostRoutine(cleanDriverDict);
- }
- return dict;
+ qDeleteAll(registeredDrivers);
+ for (const auto &[k, v] : std::as_const(connections).asKeyValueRange())
+ QSqlDatabasePrivate::invalidateDb(v, k, false);
}
QSqlDatabasePrivate *QSqlDatabasePrivate::shared_null()
{
static QSqlNullDriver dr;
- static QSqlDatabasePrivate n(nullptr, &dr);
+ static QSqlDatabasePrivate n(&dr);
return &n;
}
void QSqlDatabasePrivate::invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn)
{
if (db.d->ref.loadRelaxed() != 1 && doWarn) {
- qWarning("QSqlDatabasePrivate::removeDatabase: connection '%s' is still in use, "
- "all queries will cease to work.", name.toLocal8Bit().constData());
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::removeDatabase: connection '%ls' is still in use, "
+ "all queries will cease to work.", qUtf16Printable(name));
db.d->disable();
db.d->connName.clear();
}
@@ -159,28 +146,28 @@ void QSqlDatabasePrivate::invalidateDb(const QSqlDatabase &db, const QString &na
void QSqlDatabasePrivate::removeDatabase(const QString &name)
{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
- if (!dict->contains(name))
+ if (!sqlGlobals->connections.contains(name))
return;
- invalidateDb(dict->take(name), name);
+ invalidateDb(sqlGlobals->connections.take(name), name);
}
void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &name)
{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
-
- if (dict->contains(name)) {
- invalidateDb(dict->take(name), name);
- qWarning("QSqlDatabasePrivate::addDatabase: duplicate connection name '%s', old "
- "connection removed.", name.toLocal8Bit().data());
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
+
+ if (sqlGlobals->connections.contains(name)) {
+ invalidateDb(sqlGlobals->connections.take(name), name);
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::addDatabase: duplicate connection name '%ls', old "
+ "connection removed.", qUtf16Printable(name));
}
- dict->insert(name, db);
+ sqlGlobals->connections.insert(name, db);
db.d->connName = name;
}
@@ -188,22 +175,18 @@ void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &nam
*/
QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)
{
- const QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
-
- dict->lock.lockForRead();
- QSqlDatabase db = dict->value(name);
- dict->lock.unlock();
+ CHECK_QCOREAPPLICATION_RETVAL
+ QSqlDatabase db = s_sqlGlobals()->connection(name);
if (!db.isValid())
return db;
if (db.driver()->thread() != QThread::currentThread()) {
- qWarning("QSqlDatabasePrivate::database: requested database does not belong to the calling thread.");
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::database: requested database does not belong to the calling thread.");
return QSqlDatabase();
}
if (open && !db.isOpen()) {
if (!db.open())
- qWarning() << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text();
+ qCWarning(lcSqlDb) << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text();
}
return db;
@@ -215,7 +198,6 @@ QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)
*/
void QSqlDatabasePrivate::copy(const QSqlDatabasePrivate *other)
{
- q = other->q;
dbname = other->dbname;
uname = other->uname;
pword = other->pword;
@@ -257,6 +239,8 @@ void QSqlDatabasePrivate::disable()
Destroys the SQL driver creator object.
*/
+QSqlDriverCreatorBase::~QSqlDriverCreatorBase()
+ = default;
/*!
\fn QSqlDriver *QSqlDriverCreatorBase::createObject() const
@@ -301,6 +285,10 @@ void QSqlDatabasePrivate::disable()
QSqlDriver. Alternatively, you can subclass your own database
driver from QSqlDriver. See \l{How to Write Your Own Database
Driver} for more information.
+ A QSqlDatabase instance must only be accessed by the thread it
+ was created in. Therefore you have to make sure to create them
+ in the correct context. Alternatively you can change the context
+ with QSqlDatabase::moveToThread().
Create a connection (i.e., an instance of QSqlDatabase) by calling
one of the static addDatabase() functions, where you specify
@@ -392,9 +380,6 @@ void QSqlDatabasePrivate::disable()
\li registers a custom-made driver
\endtable
- \note QSqlDatabase::exec() is deprecated. Use QSqlQuery::exec()
- instead.
-
\note When using transactions, you must start the
transaction before you create your query.
@@ -498,23 +483,25 @@ void QSqlDatabase::removeDatabase(const QString& connectionName)
QStringList QSqlDatabase::drivers()
{
+ CHECK_QCOREAPPLICATION_RETVAL
QStringList list;
if (QFactoryLoader *fl = loader()) {
typedef QMultiMap<int, QString> PluginKeyMap;
- typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
const PluginKeyMap keyMap = fl->keyMap();
- const PluginKeyMapConstIterator cend = keyMap.constEnd();
- for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it)
- if (!list.contains(it.value()))
- list << it.value();
+ for (const QString &val : keyMap) {
+ if (!list.contains(val))
+ list << val;
+ }
}
- DriverDict dict = QSqlDatabasePrivate::driverDict();
- for (DriverDict::const_iterator i = dict.constBegin(); i != dict.constEnd(); ++i) {
- if (!list.contains(i.key()))
- list << i.key();
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QReadLocker locker(&sqlGlobals->lock);
+ const auto &dict = sqlGlobals->registeredDrivers;
+ for (const auto &[k, _] : dict.asKeyValueRange()) {
+ if (!list.contains(k))
+ list << k;
}
return list;
@@ -535,9 +522,12 @@ QStringList QSqlDatabase::drivers()
*/
void QSqlDatabase::registerSqlDriver(const QString& name, QSqlDriverCreatorBase *creator)
{
- delete QSqlDatabasePrivate::driverDict().take(name);
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
+ delete sqlGlobals->registeredDrivers.take(name);
if (creator)
- QSqlDatabasePrivate::driverDict().insert(name, creator);
+ sqlGlobals->registeredDrivers.insert(name, creator);
}
/*!
@@ -551,7 +541,8 @@ void QSqlDatabase::registerSqlDriver(const QString& name, QSqlDriverCreatorBase
bool QSqlDatabase::contains(const QString& connectionName)
{
- return dbDict()->contains_ts(connectionName);
+ CHECK_QCOREAPPLICATION_RETVAL
+ return s_sqlGlobals()->connectionExists(connectionName);
}
/*!
@@ -563,7 +554,8 @@ bool QSqlDatabase::contains(const QString& connectionName)
*/
QStringList QSqlDatabase::connectionNames()
{
- return dbDict()->keys_ts();
+ CHECK_QCOREAPPLICATION_RETVAL
+ return s_sqlGlobals()->connectionNames();
}
/*!
@@ -584,6 +576,7 @@ QStringList QSqlDatabase::connectionNames()
\row \li QODBC \li ODBC Driver (includes Microsoft SQL Server)
\row \li QPSQL \li PostgreSQL Driver
\row \li QSQLITE \li SQLite version 3 or above
+ \row \li QMIMER \li Mimer SQL 11 or above
\endtable
Additional third party drivers, including your own custom
@@ -593,8 +586,8 @@ QStringList QSqlDatabase::connectionNames()
*/
QSqlDatabase::QSqlDatabase(const QString &type)
+ : d(new QSqlDatabasePrivate(nullptr))
{
- d = new QSqlDatabasePrivate(this);
d->init(type);
}
@@ -605,8 +598,8 @@ QSqlDatabase::QSqlDatabase(const QString &type)
*/
QSqlDatabase::QSqlDatabase(QSqlDriver *driver)
+ : d(new QSqlDatabasePrivate(driver))
{
- d = new QSqlDatabasePrivate(this, driver);
}
/*!
@@ -615,8 +608,8 @@ QSqlDatabase::QSqlDatabase(QSqlDriver *driver)
objects.
*/
QSqlDatabase::QSqlDatabase()
+ : d(QSqlDatabasePrivate::shared_null())
{
- d = QSqlDatabasePrivate::shared_null();
d->ref.ref();
}
@@ -646,27 +639,27 @@ QSqlDatabase &QSqlDatabase::operator=(const QSqlDatabase &other)
void QSqlDatabasePrivate::init(const QString &type)
{
+ CHECK_QCOREAPPLICATION
drvName = type;
if (!driver) {
- DriverDict dict = QSqlDatabasePrivate::driverDict();
- for (DriverDict::const_iterator it = dict.constBegin();
- it != dict.constEnd() && !driver; ++it) {
- if (type == it.key()) {
- driver = ((QSqlDriverCreatorBase*)(*it))->createObject();
- }
- }
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QReadLocker locker(&sqlGlobals->lock);
+ const auto &dict = sqlGlobals->registeredDrivers;
+ auto it = dict.find(type);
+ if (it != dict.end())
+ driver = it.value()->createObject();
}
if (!driver && loader())
driver = qLoadPlugin<QSqlDriver, QSqlDriverPlugin>(loader(), type);
if (!driver) {
- qWarning("QSqlDatabase: %s driver not loaded", type.toLatin1().data());
- qWarning("QSqlDatabase: available drivers: %s",
- QSqlDatabase::drivers().join(u' ').toLatin1().data());
+ qCWarning(lcSqlDb, "QSqlDatabase: %ls driver not loaded", qUtf16Printable(type));
+ qCWarning(lcSqlDb, "QSqlDatabase: available drivers: %ls",
+ qUtf16Printable(QSqlDatabase::drivers().join(u' ')));
if (QCoreApplication::instance() == nullptr)
- qWarning("QSqlDatabase: an instance of QCoreApplication is required for loading driver plugins");
+ qCWarning(lcSqlDb, "QSqlDatabase: an instance of QCoreApplication is required for loading driver plugins");
driver = shared_null()->driver;
}
}
@@ -695,8 +688,9 @@ QSqlDatabase::~QSqlDatabase()
lastError() is not affected.
\sa QSqlQuery, lastError()
+ \deprecated [6.6] Use QSqlQuery::exec() instead.
*/
-
+#if QT_DEPRECATED_SINCE(6, 6)
QSqlQuery QSqlDatabase::exec(const QString & query) const
{
QSqlQuery r(d->driver->createResult());
@@ -706,6 +700,7 @@ QSqlQuery QSqlDatabase::exec(const QString & query) const
}
return r;
}
+#endif
/*!
Opens the database connection using the current connection
@@ -1099,90 +1094,8 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const
The format of the \a options string is a semicolon separated list
of option names or option=value pairs. The options depend on the
- database client used:
-
- \table
- \header \li ODBC \li MySQL \li PostgreSQL
- \row
-
- \li
- \list
- \li SQL_ATTR_ACCESS_MODE
- \li SQL_ATTR_LOGIN_TIMEOUT
- \li SQL_ATTR_CONNECTION_TIMEOUT
- \li SQL_ATTR_CURRENT_CATALOG
- \li SQL_ATTR_METADATA_ID
- \li SQL_ATTR_PACKET_SIZE
- \li SQL_ATTR_TRACEFILE
- \li SQL_ATTR_TRACE
- \li SQL_ATTR_CONNECTION_POOLING
- \li SQL_ATTR_ODBC_VERSION
- \endlist
-
- \li
- \list
- \li CLIENT_COMPRESS
- \li CLIENT_FOUND_ROWS
- \li CLIENT_IGNORE_SPACE
- \li CLIENT_ODBC
- \li CLIENT_NO_SCHEMA
- \li CLIENT_INTERACTIVE
- \li UNIX_SOCKET
- \li MYSQL_OPT_RECONNECT
- \li MYSQL_OPT_CONNECT_TIMEOUT
- \li MYSQL_OPT_READ_TIMEOUT
- \li MYSQL_OPT_WRITE_TIMEOUT
- \li SSL_KEY
- \li SSL_CERT
- \li SSL_CA
- \li SSL_CAPATH
- \li SSL_CIPHER
- \endlist
-
- \li
- \list
- \li connect_timeout
- \li options
- \li tty
- \li requiressl
- \li service
- \endlist
-
- \header \li DB2 \li OCI
- \row
-
- \li
- \list
- \li SQL_ATTR_ACCESS_MODE
- \li SQL_ATTR_LOGIN_TIMEOUT
- \endlist
-
- \li
- \list
- \li OCI_ATTR_PREFETCH_ROWS
- \li OCI_ATTR_PREFETCH_MEMORY
- \endlist
-
- \header \li SQLite \li Interbase
- \row
-
- \li
- \list
- \li QSQLITE_BUSY_TIMEOUT
- \li QSQLITE_OPEN_READONLY
- \li QSQLITE_OPEN_URI
- \li QSQLITE_ENABLE_SHARED_CACHE
- \li QSQLITE_ENABLE_REGEXP
- \li QSQLITE_NO_USE_EXTENDED_RESULT_CODES
- \endlist
-
- \li
- \list
- \li ISC_DPB_LC_CTYPE
- \li ISC_DPB_SQL_ROLE_NAME
- \endlist
-
- \endtable
+ database client used and are described for each plugin in the
+ \l{sql-driver.html}{SQL Database Drivers} page.
Examples:
\snippet code/src_sql_kernel_qsqldatabase.cpp 4
@@ -1223,6 +1136,7 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
}
/*! \fn QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver* driver, const QString& connectionName)
+ \overload
This overload is useful when you want to create a database
connection with a \l{QSqlDriver} {driver} you instantiated
@@ -1291,6 +1205,11 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
\li sqlite *connection
\li \c qsql_sqlite.cpp
\row
+ \li QMIMER
+ \li QMimerSQLDriver
+ \li MimerSession *connection
+ \li \c qsql_mimer.cpp
+ \row
\li QIBASE
\li QIBaseDriver
\li isc_db_handle connection
@@ -1334,6 +1253,8 @@ bool QSqlDatabase::isValid() const
\note The new connection has not been opened. Before using the new
connection, you must call open().
+
+ \reentrant
*/
QSqlDatabase QSqlDatabase::cloneDatabase(const QSqlDatabase &other, const QString &connectionName)
{
@@ -1365,24 +1286,11 @@ QSqlDatabase QSqlDatabase::cloneDatabase(const QSqlDatabase &other, const QStrin
QSqlDatabase QSqlDatabase::cloneDatabase(const QString &other, const QString &connectionName)
{
- const QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
-
- dict->lock.lockForRead();
- QSqlDatabase otherDb = dict->value(other);
- dict->lock.unlock();
- if (!otherDb.isValid())
- return QSqlDatabase();
-
- QSqlDatabase db(otherDb.driverName());
- db.d->copy(otherDb.d);
- QSqlDatabasePrivate::addDatabase(db, connectionName);
- return db;
+ CHECK_QCOREAPPLICATION_RETVAL
+ return cloneDatabase(s_sqlGlobals()->connection(other), connectionName);
}
/*!
- \since 4.4
-
Returns the connection name, which may be empty. \note The
connection name is not the \l{databaseName()} {database name}.
@@ -1394,10 +1302,11 @@ QString QSqlDatabase::connectionName() const
}
/*!
- \since 4.6
+ \property QSqlDatabase::numericalPrecisionPolicy
+ \since 6.8
- Sets the default numerical precision policy used by queries created
- on this database connection to \a precisionPolicy.
+ This property holds the default numerical precision policy used by
+ queries created on this database connection.
Note: Drivers that don't support fetching numerical values with low
precision will ignore the precision policy. You can use
@@ -1407,9 +1316,12 @@ QString QSqlDatabase::connectionName() const
Note: Setting the default precision policy to \a precisionPolicy
doesn't affect any currently active queries.
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
- QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlQuery::numericalPrecisionPolicy,
+ QSqlDriver::numericalPrecisionPolicy
*/
+/*!
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
+ */
void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
if (driver())
@@ -1418,12 +1330,7 @@ void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy pr
}
/*!
- \since 4.6
-
- Returns the current default precision policy for the database connection.
-
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
- QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
{
@@ -1433,6 +1340,50 @@ QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
return d->precisionPolicy;
}
+/*!
+ \since 6.8
+
+ Changes the thread affinity for QSqlDatabase and its associated driver.
+ This function returns \c true when the function succeeds. Event processing
+ will continue in the \a targetThread.
+
+ During this operation you have to make sure that there is no QSqlQuery
+ bound to this instance otherwise the QSqlDatabase will not be moved to
+ the given thread and the function returns \c false.
+
+ Since the associated driver is derived from QObject, all constraints for
+ moving a QObject to another thread also apply to this function.
+
+ \sa QObject::moveToThread(), {Threads and the SQL Module}
+*/
+bool QSqlDatabase::moveToThread(QThread *targetThread)
+{
+ if (auto drv = driver()) {
+ if (drv != QSqlDatabasePrivate::shared_null()->driver) {
+ // two instances are alive - the one here and the one in dbDict()
+ if (d->ref.loadRelaxed() > 2) {
+ qWarning("QSqlDatabasePrivate::moveToThread: connection '%ls' is still in use "
+ "in the current thread.", qUtf16Printable(d->connName));
+ return false;
+ }
+ return drv->moveToThread(targetThread);
+ }
+ }
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Returns a pointer to the associated QThread instance.
+*/
+QThread *QSqlDatabase::currentThread() const
+{
+ if (auto drv = driver())
+ return drv->thread();
+ return nullptr;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
@@ -1453,3 +1404,5 @@ QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
#endif
QT_END_NAMESPACE
+
+#include "moc_qsqldatabase.cpp"
diff --git a/src/sql/kernel/qsqldatabase.h b/src/sql/kernel/qsqldatabase.h
index 789f3e0ea4..073ca89c52 100644
--- a/src/sql/kernel/qsqldatabase.h
+++ b/src/sql/kernel/qsqldatabase.h
@@ -5,8 +5,10 @@
#define QSQLDATABASE_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qstring.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -16,11 +18,12 @@ class QSqlIndex;
class QSqlRecord;
class QSqlQuery;
class QSqlDatabasePrivate;
+class QThread;
class Q_SQL_EXPORT QSqlDriverCreatorBase
{
public:
- virtual ~QSqlDriverCreatorBase() {}
+ virtual ~QSqlDriverCreatorBase();
virtual QSqlDriver *createObject() const = 0;
};
@@ -33,7 +36,10 @@ public:
class Q_SQL_EXPORT QSqlDatabase
{
+ Q_GADGET
public:
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
QSqlDatabase();
QSqlDatabase(const QSqlDatabase &other);
~QSqlDatabase();
@@ -48,7 +54,10 @@ public:
QStringList tables(QSql::TableType type = QSql::Tables) const;
QSqlIndex primaryIndex(const QString& tablename) const;
QSqlRecord record(const QString& tablename) const;
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X_6_6("Use QSqlQuery::exec() instead.")
QSqlQuery exec(const QString& query = QString()) const;
+#endif
QSqlError lastError() const;
bool isValid() const;
@@ -72,6 +81,8 @@ public:
QString connectionName() const;
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ bool moveToThread(QThread *targetThread);
+ QThread *currentThread() const;
QSqlDriver* driver() const;
diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp
index 997441ab49..c0cb0374a9 100644
--- a/src/sql/kernel/qsqldriver.cpp
+++ b/src/sql/kernel/qsqldriver.cpp
@@ -7,8 +7,8 @@
#include "qsqlerror.h"
#include "qsqlfield.h"
#include "qsqlindex.h"
-#include "private/qobject_p.h"
#include "private/qsqldriver_p.h"
+#include "private/qtools_p.h"
#include <limits.h>
@@ -215,6 +215,7 @@ bool QSqlDriver::isOpenError() const
\value SQLite
\value Interbase
\value DB2
+ \value [since 6.6] MimerSQL
*/
/*!
@@ -403,7 +404,6 @@ bool QSqlDriver::isIdentifierEscaped(const QString &identifier, IdentifierType t
Reimplement this function if you want to provide your own implementation in your
QSqlDriver subclass,
- \since 4.5
\sa isIdentifierEscaped()
*/
QString QSqlDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
@@ -446,12 +446,11 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
{
const auto tableNameString = tableName.isEmpty() ? QString()
: prepareIdentifier(tableName, QSqlDriver::TableName, this);
- int i;
QString s;
s.reserve(128);
switch (type) {
case SelectStatement:
- for (i = 0; i < rec.count(); ++i) {
+ for (qsizetype i = 0; i < rec.count(); ++i) {
if (rec.isGenerated(i))
s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(", "_L1);
}
@@ -464,7 +463,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
{
const QString tableNamePrefix = tableNameString.isEmpty()
? QString() : tableNameString + u'.';
- for (int i = 0; i < rec.count(); ++i) {
+ for (qsizetype i = 0; i < rec.count(); ++i) {
if (!rec.isGenerated(i))
continue;
s.append(s.isEmpty() ? "WHERE "_L1 : " AND "_L1);
@@ -481,7 +480,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
}
case UpdateStatement:
s = s + "UPDATE "_L1 + tableNameString + " SET "_L1;
- for (i = 0; i < rec.count(); ++i) {
+ for (qsizetype i = 0; i < rec.count(); ++i) {
if (!rec.isGenerated(i))
continue;
s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(u'=');
@@ -502,7 +501,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
case InsertStatement: {
s = s + "INSERT INTO "_L1 + tableNameString + " ("_L1;
QString vals;
- for (i = 0; i < rec.count(); ++i) {
+ for (qsizetype i = 0; i < rec.count(); ++i) {
if (!rec.isGenerated(i))
continue;
s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(", "_L1);
@@ -516,7 +515,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
s.clear();
} else {
vals.chop(2); // remove trailing comma
- s[s.length() - 2] = u')';
+ s[s.size() - 2] = u')';
s.append("VALUES ("_L1).append(vals).append(u')');
}
break; }
@@ -598,7 +597,7 @@ QString QSqlDriver::formatValue(const QSqlField &field, bool trimStrings) const
{
QString result = field.value().toString();
if (trimStrings) {
- int end = result.length();
+ int end = result.size();
while (end && result.at(end-1).isSpace()) /* skip white space from end */
end--;
result.truncate(end);
@@ -613,15 +612,15 @@ QString QSqlDriver::formatValue(const QSqlField &field, bool trimStrings) const
break;
case QMetaType::QByteArray : {
if (hasFeature(BLOB)) {
- QByteArray ba = field.value().toByteArray();
- QString res;
- static const char hexchars[] = "0123456789abcdef";
- for (int i = 0; i < ba.size(); ++i) {
- uchar s = (uchar) ba[i];
- res += QLatin1Char(hexchars[s >> 4]);
- res += QLatin1Char(hexchars[s & 0x0f]);
+ const QByteArray ba = field.value().toByteArray();
+ r.reserve((ba.size() + 1) * 2);
+ r += u'\'';
+ for (const char c : ba) {
+ const uchar s = uchar(c);
+ r += QLatin1Char(QtMiscUtils::toHexLower(s >> 4));
+ r += QLatin1Char(QtMiscUtils::toHexLower(s & 0x0f));
}
- r = u'\'' + res + u'\'';
+ r += u'\'';
break;
}
}
@@ -680,7 +679,6 @@ QVariant QSqlDriver::handle() const
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa unsubscribeFromNotification(), subscribedToNotifications(), QSqlDriver::hasFeature()
*/
bool QSqlDriver::subscribeToNotification(const QString &name)
@@ -704,7 +702,6 @@ bool QSqlDriver::subscribeToNotification(const QString &name)
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa subscribeToNotification(), subscribedToNotifications()
*/
bool QSqlDriver::unsubscribeFromNotification(const QString &name)
@@ -719,7 +716,6 @@ bool QSqlDriver::unsubscribeFromNotification(const QString &name)
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa subscribeToNotification(), unsubscribeFromNotification()
*/
QStringList QSqlDriver::subscribedToNotifications() const
@@ -728,16 +724,7 @@ QStringList QSqlDriver::subscribedToNotifications() const
}
/*!
- \since 4.6
-
- Sets the default numerical precision policy used by queries created
- by this driver to \a precisionPolicy.
-
- Note: Setting the default precision policy to \a precisionPolicy
- doesn't affect any currently active queries.
-
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
- QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
*/
void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
@@ -746,12 +733,17 @@ void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy prec
}
/*!
- \since 4.6
+ \property QSqlDriver::numericalPrecisionPolicy
+ \since 6.8
- Returns the current default precision policy for the database connection.
+ This property holds the precision policy for the database connection.
+ \note Setting the precision policy doesn't affect any currently active queries.
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
- QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlQuery::numericalPrecisionPolicy,
+ QSqlDatabase::numericalPrecisionPolicy
+*/
+/*!
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlDriver::numericalPrecisionPolicy() const
{
diff --git a/src/sql/kernel/qsqldriver.h b/src/sql/kernel/qsqldriver.h
index 9de4ac419b..a5fe40fa15 100644
--- a/src/sql/kernel/qsqldriver.h
+++ b/src/sql/kernel/qsqldriver.h
@@ -9,6 +9,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -50,9 +51,12 @@ public:
Sybase,
SQLite,
Interbase,
- DB2
+ DB2,
+ MimerSQL,
};
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
explicit QSqlDriver(QObject *parent = nullptr);
~QSqlDriver();
virtual bool isOpen() const;
diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp
index fa4daed097..a52f209d53 100644
--- a/src/sql/kernel/qsqlerror.cpp
+++ b/src/sql/kernel/qsqlerror.cpp
@@ -19,7 +19,7 @@ QDebug operator<<(QDebug dbg, const QSqlError &s)
}
#endif
-class QSqlErrorPrivate
+class QSqlErrorPrivate : public QSharedData
{
public:
QString driverError;
@@ -27,7 +27,7 @@ public:
QSqlError::ErrorType errorType;
QString errorCode;
};
-
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlErrorPrivate)
/*!
\class QSqlError
@@ -88,9 +88,6 @@ public:
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)
@@ -106,45 +103,38 @@ QSqlError::QSqlError(const QString &driverText, const QString &databaseText,
/*!
Creates a copy of \a other.
*/
-QSqlError::QSqlError(const QSqlError& other)
- : d(new QSqlErrorPrivate(*other.d))
-{
-}
+QSqlError::QSqlError(const QSqlError &other)
+ = default;
/*!
Assigns the \a other error's values to this error.
*/
-QSqlError& QSqlError::operator=(const QSqlError& other)
-{
- if (&other == this)
- return *this;
- if (d && other.d)
- *d = *other.d;
- else if (d)
- *d = QSqlErrorPrivate();
- else if (other.d)
- d = new QSqlErrorPrivate(*other.d);
- return *this;
-}
+QSqlError &QSqlError::operator=(const QSqlError &other)
+ = default;
+
/*!
- Compare the \a other error's values to this error and returns \c true, if it equal.
+ Compare the \a other error's type() and nativeErrorCode()
+ to this error and returns \c true, if it equal.
*/
-bool QSqlError::operator==(const QSqlError& other) const
+bool QSqlError::operator==(const QSqlError &other) const
{
- return (d->errorType == other.d->errorType);
+ return (d->errorType == other.d->errorType &&
+ d->errorCode == other.d->errorCode);
}
/*!
- Compare the \a other error's values to this error and returns \c true if it is not equal.
+ Compare the \a other error's type() and nativeErrorCode()
+ to this error and returns \c true if it is not equal.
*/
-bool QSqlError::operator!=(const QSqlError& other) const
+bool QSqlError::operator!=(const QSqlError &other) const
{
- return (d->errorType != other.d->errorType);
+ return (d->errorType != other.d->errorType ||
+ d->errorCode != other.d->errorCode);
}
@@ -153,9 +143,7 @@ bool QSqlError::operator!=(const QSqlError& other) const
*/
QSqlError::~QSqlError()
-{
- delete d;
-}
+ = default;
/*!
Returns the text of the error as reported by the driver. This may
@@ -192,6 +180,9 @@ QSqlError::ErrorType QSqlError::type() const
/*!
Returns the database-specific error code, or an empty string if
it cannot be determined.
+ \note Some drivers (like DB2 or ODBC) may return more than one
+ error code. When this happens, \c ; is used as separator between
+ the error codes.
*/
QString QSqlError::nativeErrorCode() const
@@ -209,7 +200,7 @@ QString QSqlError::nativeErrorCode() const
QString QSqlError::text() const
{
QString result = d->databaseError;
- if (!d->databaseError.isEmpty() && !d->driverError.isEmpty() && !d->databaseError.endsWith("\n"_L1))
+ if (!d->databaseError.isEmpty() && !d->driverError.isEmpty() && !d->databaseError.endsWith(u'\n'))
result += u' ';
result += d->driverError;
return result;
diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h
index 6532f1af57..24f2921f5a 100644
--- a/src/sql/kernel/qsqlerror.h
+++ b/src/sql/kernel/qsqlerror.h
@@ -5,11 +5,13 @@
#define QSQLERROR_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
class QSqlErrorPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlErrorPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlError
{
@@ -25,16 +27,16 @@ public:
const QString &databaseText = QString(),
ErrorType type = NoError,
const QString &errorCode = QString());
- QSqlError(const QSqlError& other);
- QSqlError(QSqlError &&other) noexcept : d(other.d) { other.d = nullptr; }
- QSqlError& operator=(const QSqlError& other);
- QSqlError &operator=(QSqlError &&other) noexcept { swap(other); return *this; }
-
- bool operator==(const QSqlError& other) const;
- bool operator!=(const QSqlError& other) const;
+ QSqlError(const QSqlError &other);
+ QSqlError(QSqlError &&other) noexcept = default;
+ QSqlError& operator=(const QSqlError &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QSqlError)
~QSqlError();
- void swap(QSqlError &other) noexcept { qt_ptr_swap(d, other.d); }
+ bool operator==(const QSqlError &other) const;
+ bool operator!=(const QSqlError &other) const;
+
+ void swap(QSqlError &other) noexcept { d.swap(other.d); }
QString driverText() const;
QString databaseText() const;
@@ -44,7 +46,7 @@ public:
bool isValid() const;
private:
- QSqlErrorPrivate *d = nullptr;
+ QExplicitlySharedDataPointer<QSqlErrorPrivate> d;
};
Q_DECLARE_SHARED(QSqlError)
diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp
index a86a7ca686..0bd0ca5161 100644
--- a/src/sql/kernel/qsqlfield.cpp
+++ b/src/sql/kernel/qsqlfield.cpp
@@ -2,36 +2,20 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsqlfield.h"
-#include "qatomic.h"
#include "qdebug.h"
QT_BEGIN_NAMESPACE
-class QSqlFieldPrivate
+class QSqlFieldPrivate : public QSharedData
{
public:
QSqlFieldPrivate(const QString &name,
QMetaType type, const QString &tableName) :
- ref(1), nm(name), table(tableName), def(QVariant()), type(type),
+ nm(name), table(tableName), def(QVariant()), type(type),
req(QSqlField::Unknown), len(-1), prec(-1), tp(-1),
ro(false), gen(true), autoval(false)
{}
- QSqlFieldPrivate(const QSqlFieldPrivate &other)
- : ref(1),
- nm(other.nm),
- table(other.table),
- def(other.def),
- type(other.type),
- req(other.req),
- len(other.len),
- prec(other.prec),
- tp(other.tp),
- ro(other.ro),
- gen(other.gen),
- autoval(other.autoval)
- {}
-
bool operator==(const QSqlFieldPrivate& other) const
{
return (nm == other.nm
@@ -46,7 +30,6 @@ public:
&& autoval == other.autoval);
}
- QAtomicInt ref;
QString nm;
QString table;
QVariant def;
@@ -59,6 +42,7 @@ public:
bool gen: 1;
bool autoval: 1;
};
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlFieldPrivate)
/*!
@@ -115,7 +99,7 @@ public:
\value Unknown The database driver couldn't determine whether the field is required or
optional.
- \sa requiredStatus()
+ \sa requiredStatus
*/
/*!
@@ -125,9 +109,14 @@ public:
Constructs an empty field called \a fieldName of variant type \a
type in \a table.
+*/
- \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(),
- setGenerated(), setReadOnly()
+/*!
+ \fn void QSqlField::swap(QSqlField &other)
+ \since 6.6
+
+ Swaps this field with \a other. This function is very fast and
+ never fails.
*/
/*!
@@ -136,38 +125,26 @@ public:
\overload
Constructs an empty field called \a fieldName of type \a
type in \a table.
-
- \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(),
- setGenerated(), setReadOnly()
*/
QSqlField::QSqlField(const QString &fieldName, QMetaType type, const QString &table)
+ : val(QVariant(type, nullptr)),
+ d(new QSqlFieldPrivate(fieldName, type, table))
{
- d = new QSqlFieldPrivate(fieldName, type, table);
- val = QVariant(QMetaType(type), nullptr);
}
/*!
Constructs a copy of \a other.
*/
-QSqlField::QSqlField(const QSqlField& other)
-{
- d = other.d;
- d->ref.ref();
- val = other.val;
-}
+QSqlField::QSqlField(const QSqlField &other)
+ = default;
/*!
Sets the field equal to \a other.
*/
QSqlField& QSqlField::operator=(const QSqlField& other)
-{
- qAtomicAssign(d, other.d);
- val = other.val;
- return *this;
-}
-
+ = default;
/*! \fn bool QSqlField::operator!=(const QSqlField &other) const
Returns \c true if the field is unequal to \a other; otherwise returns
@@ -189,16 +166,10 @@ bool QSqlField::operator==(const QSqlField& other) const
*/
QSqlField::~QSqlField()
-{
- if (!d->ref.deref())
- delete d;
-}
+ = default;
/*!
- Sets the required status of this field to \a required.
-
- \sa requiredStatus(), setMetaType(), setLength(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l requiredStatus to \a required.
*/
void QSqlField::setRequiredStatus(RequiredStatus required)
{
@@ -211,16 +182,11 @@ void QSqlField::setRequiredStatus(RequiredStatus required)
Sets the required status of this field to \l Required if \a
required is true; otherwise sets it to \l Optional.
- \sa setRequiredStatus(), requiredStatus()
+ \sa requiredStatus
*/
/*!
- Sets the field's length to \a fieldLength. For strings this is the
- maximum number of characters the string can hold; the meaning
- varies for other types.
-
- \sa length(), setMetaType(), setRequiredStatus(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l length to \a fieldLength.
*/
void QSqlField::setLength(int fieldLength)
{
@@ -229,10 +195,7 @@ void QSqlField::setLength(int fieldLength)
}
/*!
- Sets the field's \a precision. This only affects numeric fields.
-
- \sa precision(), setMetaType(), setRequiredStatus(), setLength(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l precision to \a precision.
*/
void QSqlField::setPrecision(int precision)
{
@@ -241,10 +204,16 @@ void QSqlField::setPrecision(int precision)
}
/*!
- Sets the default value used for this field to \a value.
+ \property QSqlField::defaultValue
+ \since 6.8
- \sa defaultValue(), value(), setMetaType(), setRequiredStatus(),
- setLength(), setPrecision(), setGenerated(), setReadOnly()
+ This property holds the default value for this field.
+ Only some database drivers supports this property. Currently
+ those are SQLite, PostgreSQL, Oracle and MySQL/MariaDB.
+*/
+
+/*!
+ Sets \l defaultValue to \a value.
*/
void QSqlField::setDefaultValue(const QVariant &value)
{
@@ -252,23 +221,20 @@ void QSqlField::setDefaultValue(const QVariant &value)
d->def = value;
}
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
\internal
+ \deprecated [6.8] This internal value is no longer used.
*/
void QSqlField::setSqlType(int type)
{
detach();
d->tp = type;
}
+#endif
/*!
- Sets the generated state. If \a gen is false, no SQL will
- be generated for this field; otherwise, Qt classes such as
- QSqlQueryModel and QSqlTableModel will generate SQL for this
- field.
-
- \sa isGenerated(), setMetaType(), setRequiredStatus(), setLength(),
- setPrecision(), setDefaultValue(), setReadOnly()
+ Sets \l generated to \a gen.
*/
void QSqlField::setGenerated(bool gen)
{
@@ -278,19 +244,28 @@ void QSqlField::setGenerated(bool gen)
/*!
- Sets the value of the field to \a value. If the field is read-only
- (isReadOnly() returns \c true), nothing happens.
+ \property QSqlField::value
+ \since 6.8
+ This property holds the \a value as a QVariant
+
+ Setting a \a value to a read-only QSqlField is a no-op.
If the data type of \a value differs from the field's current
data type, an attempt is made to cast it to the proper type. This
preserves the data type of the field in the case of assignment,
e.g. a QString to an integer data type.
To set the value to NULL, use clear().
-
- \sa value(), isReadOnly(), defaultValue()
*/
+/*!
+ \fn QVariant QSqlField::value() const
+
+ Returns the value of \l value.
+*/
+/*!
+ Sets \l value to \a value.
+*/
void QSqlField::setValue(const QVariant& value)
{
if (isReadOnly())
@@ -301,8 +276,6 @@ void QSqlField::setValue(const QVariant& value)
/*!
Clears the value of the field and sets it to NULL.
If the field is read-only, nothing happens.
-
- \sa setValue(), isReadOnly(), requiredStatus()
*/
void QSqlField::clear()
@@ -312,12 +285,10 @@ void QSqlField::clear()
val = QVariant(d->type, nullptr);
}
-/*!
- Sets the name of the field to \a name.
- \sa name()
+/*!
+ Sets \l name to \a name.
*/
-
void QSqlField::setName(const QString& name)
{
detach();
@@ -325,9 +296,7 @@ void QSqlField::setName(const QString& name)
}
/*!
- Sets the read only flag of the field's value to \a readOnly. A
- read-only field cannot have its value set with setValue() and
- cannot be cleared to NULL with clear().
+ Sets \l readOnly to \a readOnly.
*/
void QSqlField::setReadOnly(bool readOnly)
{
@@ -336,17 +305,14 @@ void QSqlField::setReadOnly(bool readOnly)
}
/*!
- \fn QVariant QSqlField::value() const
-
- Returns the value of the field as a QVariant.
+ \property QSqlField::name
- Use isNull() to check if the field's value is NULL.
+ This property holds the name of the field.
+ This can be the column name or a user given alias.
*/
/*!
- Returns the name of the field.
-
- \sa setName()
+ Returns the value of \l name.
*/
QString QSqlField::name() const
{
@@ -354,13 +320,20 @@ QString QSqlField::name() const
}
/*!
- Returns the field's type as stored in the database.
+ \property QSqlField::metaType
+ \since 6.8
+
+ This property holds the field's type as stored in the database.
Note that the actual value might have a different type,
Numerical values that are too large to store in a long
int or double are usually stored as strings to prevent
precision loss.
- \sa setMetaType()
+ \sa QSqlDatabase::numericalPrecisionPolicy
+*/
+
+/*!
+ Returns the value of \l metaType.
*/
QMetaType QSqlField::metaType() const
{
@@ -368,10 +341,7 @@ QMetaType QSqlField::metaType() const
}
/*!
- Set's the field's variant type to \a type.
-
- \sa metaType(), setRequiredStatus(), setLength(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l metaType to \a type.
*/
void QSqlField::setMetaType(QMetaType type)
{
@@ -391,7 +361,7 @@ void QSqlField::setMetaType(QMetaType type)
int or double are usually stored as strings to prevent
precision loss.
- \sa metaType()
+ \sa metaType
*/
/*!
@@ -400,41 +370,56 @@ void QSqlField::setMetaType(QMetaType type)
Sets the field's variant type to \a type.
- \sa setMetaType()
+ \sa metaType
*/
/*!
- Returns \c true if the field's value is read-only; otherwise returns
- false.
+ \property QSqlField::readOnly
+ \since 6.8
+
+ When this property is \c true then this QSqlField cannot be modified.
+ A read-only field cannot have its value set with setValue() and
+ cannot be cleared to NULL with clear().
+*/
- \sa setReadOnly(), metaType(), requiredStatus(), length(), precision(),
- defaultValue(), isGenerated()
+/*!
+ Returns the value of \l readOnly.
*/
bool QSqlField::isReadOnly() const
-{ return d->ro; }
+{
+ return d->ro;
+}
/*!
Returns \c true if the field's value is NULL; otherwise returns
false.
- \sa value()
+ \sa value
*/
bool QSqlField::isNull() const
-{ return val.isNull(); }
+{
+ return val.isNull();
+}
/*! \internal
*/
void QSqlField::detach()
{
- qAtomicDetach(d);
+ d.detach();
}
/*!
- Returns \c true if this is a required field; otherwise returns \c false.
+ \property QSqlField::requiredStatus
+ \since 6.8
+
+ This property holds the RequiredStatus of the field.
An \c INSERT will fail if a required field does not have a value.
- \sa setRequiredStatus(), metaType(), length(), precision(), defaultValue(),
- isGenerated()
+ \sa RequiredStatus
+*/
+
+/*!
+ Returns the value of \l requiredStatus.
*/
QSqlField::RequiredStatus QSqlField::requiredStatus() const
{
@@ -442,13 +427,19 @@ QSqlField::RequiredStatus QSqlField::requiredStatus() const
}
/*!
- Returns the field's length.
+ \property QSqlField::length
+ \since 6.8
- If the returned value is negative, it means that the information
+ This property holds the field's length.
+
+ If the value is negative, it means that the information
is not available from the database.
+ For strings this is the maximum number of characters the string
+ can hold; the meaning varies for other types.
+*/
- \sa setLength(), metaType(), requiredStatus(), precision(), defaultValue(),
- isGenerated()
+/*!
+ Returns the value of \l length.
*/
int QSqlField::length() const
{
@@ -456,14 +447,17 @@ int QSqlField::length() const
}
/*!
- Returns the field's precision; this is only meaningful for numeric
- types.
+ \property QSqlField::precision
+ \since 6.8
+
+ This property holds the field's precision; this is only meaningful
+ for numeric types.
If the returned value is negative, it means that the information
is not available from the database.
-
- \sa setPrecision(), metaType(), requiredStatus(), length(), defaultValue(),
- isGenerated()
+*/
+/*!
+ Returns the value of \l precision.
*/
int QSqlField::precision() const
{
@@ -471,18 +465,17 @@ int QSqlField::precision() const
}
/*!
- Returns the field's default value (which may be NULL).
-
- \sa setDefaultValue(), metaType(), requiredStatus(), length(), precision(),
- isGenerated()
+ Sets the value of \l defaultValue.
*/
QVariant QSqlField::defaultValue() const
{
return d->def;
}
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
\internal
+ \deprecated [6.8] This internal value is no longer used.
Returns the type ID for the field.
@@ -493,13 +486,19 @@ int QSqlField::typeID() const
{
return d->tp;
}
+#endif
/*!
- Returns \c true if the field is generated; otherwise returns
- false.
+ \property QSqlField::generated
+ \since 6.8
- \sa setGenerated(), metaType(), requiredStatus(), length(), precision(),
- defaultValue()
+ This property holds the generated state. If \a generated is \c false,
+ no SQL will be generated for this field; otherwise, Qt classes such as
+ QSqlQueryModel and QSqlTableModel will generate SQL for this field.
+*/
+
+/*!
+ Returns the value of \l generated.
*/
bool QSqlField::isGenerated() const
{
@@ -530,8 +529,6 @@ QDebug operator<<(QDebug dbg, const QSqlField &f)
dbg << ", required: "
<< (f.requiredStatus() == QSqlField::Required ? "yes" : "no");
dbg << ", generated: " << (f.isGenerated() ? "yes" : "no");
- if (f.typeID() >= 0)
- dbg << ", typeID: " << f.typeID();
if (!f.defaultValue().isNull())
dbg << ", defaultValue: \"" << f.defaultValue() << '\"';
dbg << ", autoValue: " << f.isAutoValue()
@@ -541,16 +538,21 @@ QDebug operator<<(QDebug dbg, const QSqlField &f)
#endif
/*!
- Returns \c true if the value is auto-generated by the database,
- for example auto-increment primary key values.
+ \property QSqlField::autoValue
+ \since 6.8
+
+ If the value is auto-generated by the database,
+ for example auto-increment primary key values, this value is \c true.
\note When using the ODBC driver, due to limitations in the ODBC API,
the \c isAutoValue() field is only populated in a QSqlField resulting from a
QSqlRecord obtained by executing a \c SELECT query. It is \c false in a QSqlField
resulting from a QSqlRecord returned from QSqlDatabase::record() or
QSqlDatabase::primaryIndex().
+*/
- \sa setAutoValue()
+/*!
+ Returns the value of \l autoValue.
*/
bool QSqlField::isAutoValue() const
{
@@ -558,11 +560,8 @@ bool QSqlField::isAutoValue() const
}
/*!
- Marks the field as an auto-generated value if \a autoVal
- is true.
-
- \sa isAutoValue()
- */
+ Sets \l autoValue to \a autoVal.
+*/
void QSqlField::setAutoValue(bool autoVal)
{
detach();
@@ -570,24 +569,26 @@ void QSqlField::setAutoValue(bool autoVal)
}
/*!
- Sets the tableName of the field to \a table.
-
- \sa tableName()
+ Sets \l tableName to \a tableName.
*/
-void QSqlField::setTableName(const QString &table)
+void QSqlField::setTableName(const QString &tableName)
{
detach();
- d->table = table;
+ d->table = tableName;
}
/*!
- Returns the tableName of the field.
+ \property QSqlField::tableName
+ \since 6.8
+
+ This property holds 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()
+*/
+/*!
+ Returns the \l tableName.
*/
QString QSqlField::tableName() const
{
@@ -595,3 +596,5 @@ QString QSqlField::tableName() const
}
QT_END_NAMESPACE
+
+#include "moc_qsqlfield.cpp"
diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h
index 67aed772bd..451f70f3b6 100644
--- a/src/sql/kernel/qsqlfield.h
+++ b/src/sql/kernel/qsqlfield.h
@@ -5,6 +5,7 @@
#define QSQLFIELD_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
@@ -12,19 +13,38 @@ QT_BEGIN_NAMESPACE
class QSqlFieldPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlFieldPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlField
{
+ Q_GADGET
public:
enum RequiredStatus { Unknown = -1, Optional = 0, Required = 1 };
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue)
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString tableName READ tableName WRITE setTableName)
+ Q_PROPERTY(QMetaType metaType READ metaType WRITE setMetaType)
+ Q_PROPERTY(RequiredStatus requiredStatus READ requiredStatus WRITE setRequiredStatus)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(bool generated READ isGenerated WRITE setGenerated)
+ Q_PROPERTY(bool autoValue READ isAutoValue WRITE setAutoValue)
+ Q_PROPERTY(int length READ length WRITE setLength)
+ Q_PROPERTY(int precision READ precision WRITE setPrecision)
+
explicit QSqlField(const QString& fieldName = QString(), QMetaType type = QMetaType(), const QString &tableName = QString());
QSqlField(const QSqlField& other);
QSqlField& operator=(const QSqlField& other);
+ QSqlField(QSqlField &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSqlField)
+ ~QSqlField();
+
+ void swap(QSqlField &other) noexcept { val.swap(other.val); d.swap(other.d); }
+
bool operator==(const QSqlField& other) const;
inline bool operator!=(const QSqlField &other) const { return !operator==(other); }
- ~QSqlField();
void setValue(const QVariant& value);
inline QVariant value() const
@@ -62,7 +82,6 @@ public:
void setLength(int fieldLength);
void setPrecision(int precision);
void setDefaultValue(const QVariant &value);
- void setSqlType(int type);
void setGenerated(bool gen);
void setAutoValue(bool autoVal);
@@ -70,16 +89,24 @@ public:
int length() const;
int precision() const;
QVariant defaultValue() const;
- int typeID() const;
bool isGenerated() const;
bool isValid() const;
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("This internal value is no longer used.")
+ void setSqlType(int type);
+ QT_DEPRECATED_VERSION_X_6_8("This internal value is no longer used.")
+ int typeID() const;
+#endif
private:
void detach();
+ // ### Qt7: move to private class
QVariant val;
- QSqlFieldPrivate* d;
+ QExplicitlySharedDataPointer<QSqlFieldPrivate> d;
};
+Q_DECLARE_SHARED(QSqlField)
+
#ifndef QT_NO_DEBUG_STREAM
Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlField &);
#endif
diff --git a/src/sql/kernel/qsqlindex.cpp b/src/sql/kernel/qsqlindex.cpp
index 06aab34847..15ee489928 100644
--- a/src/sql/kernel/qsqlindex.cpp
+++ b/src/sql/kernel/qsqlindex.cpp
@@ -4,7 +4,6 @@
#include "qsqlindex.h"
#include "qsqlfield.h"
-#include "qstringlist.h"
QT_BEGIN_NAMESPACE
@@ -42,6 +41,25 @@ QSqlIndex::QSqlIndex(const QSqlIndex& other)
{
}
+/*! \fn QSqlIndex::QSqlIndex(QSqlIndex &&other)
+ Move-constructs a new QSqlIndex from \a other.
+
+ \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 6.6
+*/
+/*! \fn QSqlIndex& QSqlIndex::operator=(QSqlIndex &&other)
+ Move-assigns \a other to this QSqlIndex 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 6.6
+*/
+
/*!
Sets the index equal to \a other.
*/
@@ -55,6 +73,7 @@ QSqlIndex& QSqlIndex::operator=(const QSqlIndex& other)
return *this;
}
+
/*!
Destroys the object and frees any allocated resources.
*/
@@ -65,21 +84,23 @@ QSqlIndex::~QSqlIndex()
}
/*!
- Sets the name of the index to \a name.
+ \property QSqlIndex::name
+ \since 6.8
+ This property holds the name of the index.
+*/
+/*!
+ \fn QString QSqlIndex::name() const
+ Returns the \l name.
+*/
+/*!
+ Sets \l name to \a name.
*/
-
void QSqlIndex::setName(const QString& name)
{
nm = name;
}
/*!
- \fn QString QSqlIndex::name() const
-
- Returns the name of the index.
-*/
-
-/*!
Appends the field \a field to the list of indexed fields. The
field is appended with an ascending sort order.
*/
@@ -128,34 +149,18 @@ void QSqlIndex::setDescending(int i, bool desc)
sorts[i] = desc;
}
-/*! \internal
-
- Creates a string representing the field number \a i using prefix \a
- prefix. If \a verbose is true, ASC or DESC is included in the field
- description if the field is sorted in ASCending or DESCending order.
+/*!
+ \property QSqlIndex::cursorName
+ \since 6.8
+ This property holds the name of the cursor which the index
+ is associated with.
*/
-
-QString QSqlIndex::createField(int i, const QString& prefix, bool verbose) const
-{
- QString f;
- if (!prefix.isEmpty())
- f += prefix + u'.';
- f += field(i).name();
- if (verbose)
- f += u' ' + QString((isDescending(i) ? "DESC"_L1 : "ASC"_L1));
- return f;
-}
-
/*!
\fn QString QSqlIndex::cursorName() const
-
- Returns the name of the cursor which the index is associated with.
+ Returns the \l cursorName.
*/
-
-
/*!
- Sets the name of the cursor that the index is associated with to
- \a cursorName.
+ Sets \l cursorName to \a cursorName.
*/
void QSqlIndex::setCursorName(const QString& cursorName)
{
@@ -163,3 +168,5 @@ void QSqlIndex::setCursorName(const QString& cursorName)
}
QT_END_NAMESPACE
+
+#include "moc_qsqlindex.cpp"
diff --git a/src/sql/kernel/qsqlindex.h b/src/sql/kernel/qsqlindex.h
index 08ef14b614..3d5d95b373 100644
--- a/src/sql/kernel/qsqlindex.h
+++ b/src/sql/kernel/qsqlindex.h
@@ -7,18 +7,34 @@
#include <QtSql/qtsqlglobal.h>
#include <QtSql/qsqlrecord.h>
#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qstring.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
class Q_SQL_EXPORT QSqlIndex : public QSqlRecord
{
+ Q_GADGET
public:
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName)
+
explicit QSqlIndex(const QString &cursorName = QString(), const QString &name = QString());
QSqlIndex(const QSqlIndex &other);
+ QSqlIndex(QSqlIndex &&other) noexcept = default;
~QSqlIndex();
QSqlIndex &operator=(const QSqlIndex &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QSqlIndex)
+
+ void swap(QSqlIndex &other) noexcept {
+ QSqlRecord::swap(other);
+ cursor.swap(other.cursor);
+ nm.swap(other.nm);
+ sorts.swap(other.sorts);
+ };
+
void setCursorName(const QString &cursorName);
inline QString cursorName() const { return cursor; }
void setName(const QString& name);
@@ -31,12 +47,14 @@ public:
void setDescending(int i, bool desc);
private:
- QString createField(int i, const QString& prefix, bool verbose) const;
+ // ### Qt7: move to d-ptr
QString cursor;
QString nm;
QList<bool> sorts;
};
+Q_DECLARE_SHARED(QSqlIndex)
+
QT_END_NAMESPACE
#endif // QSQLINDEX_H
diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp
index fbae6ef27c..14a1116531 100644
--- a/src/sql/kernel/qsqlquery.cpp
+++ b/src/sql/kernel/qsqlquery.cpp
@@ -7,16 +7,21 @@
#include "qatomic.h"
#include "qdebug.h"
-#include "qelapsedtimer.h"
-#include "qmap.h"
+#include "qloggingcategory.h"
#include "qsqlrecord.h"
#include "qsqlresult.h"
#include "qsqldriver.h"
#include "qsqldatabase.h"
#include "private/qsqlnulldriver_p.h"
+#ifdef QT_DEBUG_SQL
+#include "qelapsedtimer.h"
+#endif
+
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcSqlQuery, "qt.sql.qsqlquery")
+
class QSqlQueryPrivate
{
public:
@@ -325,19 +330,26 @@ bool QSqlQuery::isNull(int field) const
/*!
\overload
+*/
+bool QSqlQuery::isNull(const QString &name) const
+{
+ return isNull(QStringView(name));
+}
+
+/*!
+ \overload
Returns \c true if there is no field with this \a name; otherwise
returns isNull(int index) for the corresponding field index.
This overload is less efficient than \l{QSqlQuery::}{isNull()}
*/
-
-bool QSqlQuery::isNull(const QString &name) const
+bool QSqlQuery::isNull(QStringView name) const
{
- int index = d->sqlResult->record().indexOf(name);
+ qsizetype index = d->sqlResult->record().indexOf(name);
if (index > -1)
return isNull(index);
- qWarning("QSqlQuery::isNull: unknown field name '%s'", qPrintable(name));
+ qCWarning(lcSqlQuery, "QSqlQuery::isNull: unknown field name '%ls'", qUtf16Printable(name.toString()));
return true;
}
@@ -373,7 +385,7 @@ bool QSqlQuery::exec(const QString& query)
t.start();
#endif
if (!driver()) {
- qWarning("QSqlQuery::exec: called before driver has been set up");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: called before driver has been set up");
return false;
}
if (d->ref.loadRelaxed() != 1) {
@@ -390,19 +402,20 @@ bool QSqlQuery::exec(const QString& query)
}
d->sqlResult->setQuery(query.trimmed());
if (!driver()->isOpen() || driver()->isOpenError()) {
- qWarning("QSqlQuery::exec: database not open");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: database not open");
return false;
}
if (query.isEmpty()) {
- qWarning("QSqlQuery::exec: empty query");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: empty query");
return false;
}
bool retval = d->sqlResult->reset(query);
#ifdef QT_DEBUG_SQL
- qDebug().nospace() << "Executed query (" << t.elapsed() << "ms, " << d->sqlResult->size()
- << " results, " << d->sqlResult->numRowsAffected()
- << " affected): " << d->sqlResult->lastQuery();
+ qCDebug(lcSqlQuery()).nospace() << "Executed query (" << t.elapsed() << "ms, "
+ << d->sqlResult->size()
+ << " results, " << d->sqlResult->numRowsAffected()
+ << " affected): " << d->sqlResult->lastQuery();
#endif
return retval;
}
@@ -430,25 +443,32 @@ QVariant QSqlQuery::value(int index) const
{
if (isActive() && isValid() && (index > -1))
return d->sqlResult->data(index);
- qWarning("QSqlQuery::value: not positioned on a valid record");
+ qCWarning(lcSqlQuery, "QSqlQuery::value: not positioned on a valid record");
return QVariant();
}
/*!
\overload
+*/
+QVariant QSqlQuery::value(const QString &name) const
+{
+ return value(QStringView(name));
+}
+
+/*!
+ \overload
Returns the value of the field called \a name in the current record.
If field \a name does not exist an invalid variant is returned.
This overload is less efficient than \l{QSqlQuery::}{value()}
*/
-
-QVariant QSqlQuery::value(const QString& name) const
+QVariant QSqlQuery::value(QStringView name) const
{
- int index = d->sqlResult->record().indexOf(name);
+ qsizetype index = d->sqlResult->record().indexOf(name);
if (index > -1)
return value(index);
- qWarning("QSqlQuery::value: unknown field name '%s'", qPrintable(name));
+ qCWarning(lcSqlQuery, "QSqlQuery::value: unknown field name '%ls'", qUtf16Printable(name.toString()));
return QVariant();
}
@@ -594,7 +614,7 @@ bool QSqlQuery::seek(int index, bool relative)
}
// let drivers optimize
if (isForwardOnly() && actualIdx < at()) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
if (actualIdx == (at() + 1) && at() != QSql::BeforeFirstRow) {
@@ -700,7 +720,7 @@ bool QSqlQuery::previous()
if (!isSelect() || !isActive())
return false;
if (isForwardOnly()) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
@@ -733,7 +753,7 @@ bool QSqlQuery::first()
if (!isSelect() || !isActive())
return false;
if (isForwardOnly() && at() > QSql::BeforeFirstRow) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
return d->sqlResult->fetchFirst();
@@ -848,10 +868,9 @@ bool QSqlQuery::isSelect() const
}
/*!
- Returns \c true if you can only scroll forward through a result set;
- otherwise returns \c false.
+ Returns \l forwardOnly.
- \sa setForwardOnly(), next()
+ \sa forwardOnly, next(), seek()
*/
bool QSqlQuery::isForwardOnly() const
{
@@ -859,7 +878,10 @@ bool QSqlQuery::isForwardOnly() const
}
/*!
- Sets forward only mode to \a forward. If \a forward is true, only
+ \property QSqlQuery::forwardOnly
+ \since 6.8
+
+ This property holds the forward only mode. If \a forward is true, only
next() and seek() with positive values, are allowed for navigating
the results.
@@ -888,7 +910,11 @@ bool QSqlQuery::isForwardOnly() const
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()
+ \sa next(), seek()
+*/
+/*!
+ Sets \l forwardOnly to \a forward.
+ \sa forwardOnly, next(), seek()
*/
void QSqlQuery::setForwardOnly(bool forward)
{
@@ -918,7 +944,7 @@ QSqlRecord QSqlQuery::record() const
QSqlRecord rec = d->sqlResult->record();
if (isValid()) {
- for (int i = 0; i < rec.count(); ++i)
+ for (qsizetype i = 0; i < rec.count(); ++i)
rec.setValue(i, value(i));
}
return rec;
@@ -974,19 +1000,19 @@ bool QSqlQuery::prepare(const QString& query)
d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
}
if (!driver()) {
- qWarning("QSqlQuery::prepare: no driver");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: no driver");
return false;
}
if (!driver()->isOpen() || driver()->isOpenError()) {
- qWarning("QSqlQuery::prepare: database not open");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: database not open");
return false;
}
if (query.isEmpty()) {
- qWarning("QSqlQuery::prepare: empty query");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: empty query");
return false;
}
#ifdef QT_DEBUG_SQL
- qDebug("\n QSqlQuery::prepare: %s", query.toLocal8Bit().constData());
+ qCDebug(lcSqlQuery, "\n QSqlQuery::prepare: %ls", qUtf16Printable(query));
#endif
return d->sqlResult->savePrepare(query);
}
@@ -1013,9 +1039,9 @@ bool QSqlQuery::exec()
bool retval = d->sqlResult->exec();
#ifdef QT_DEBUG_SQL
- qDebug().nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
- << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
- << " affected): " << d->sqlResult->lastQuery();
+ qCDebug(lcSqlQuery).nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
+ << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
+ << " affected): " << d->sqlResult->lastQuery();
#endif
return retval;
}
@@ -1027,8 +1053,6 @@ bool QSqlQuery::exec()
*/
/*!
- \since 4.2
-
Executes a previously prepared SQL query in a batch. All the bound
parameters have to be lists of variants. If the database doesn't
support batch executions, the driver will simulate it using
@@ -1047,8 +1071,8 @@ bool QSqlQuery::exec()
To bind NULL values, a null QVariant of the relevant type has to be
added to the bound QVariantList; for example, \c
- {QVariant(QMetaType::QString)} should be used if you are using
- strings.
+ {QVariant(QMetaType::fromType<QString>())} should be used if you are
+ using strings.
\note Every bound QVariantList must contain the same amount of
variants.
@@ -1085,7 +1109,7 @@ bool QSqlQuery::execBatch(BatchExecutionMode mode)
the result into.
To bind a NULL value, use a null QVariant; for example, use
- \c {QVariant(QMetaType::QString)} if you are binding a string.
+ \c {QVariant(QMetaType::fromType<QString>())} if you are binding a string.
\sa addBindValue(), prepare(), exec(), boundValue(), boundValues()
*/
@@ -1115,7 +1139,7 @@ void QSqlQuery::bindValue(int pos, const QVariant& val, QSql::ParamType paramTyp
overwritten with data from the database after the exec() call.
To bind a NULL value, use a null QVariant; for example, use \c
- {QVariant(QMetaType::QString)} if you are binding a string.
+ {QVariant(QMetaType::fromType<QString>())} if you are binding a string.
\sa bindValue(), prepare(), exec(), boundValue(), boundValues()
*/
@@ -1136,6 +1160,7 @@ QVariant QSqlQuery::boundValue(const QString& placeholder) const
/*!
Returns the value for the placeholder at position \a pos.
+ \sa boundValues()
*/
QVariant QSqlQuery::boundValue(int pos) const
{
@@ -1154,7 +1179,7 @@ QVariant QSqlQuery::boundValue(int pos) const
\snippet sqldatabase/sqldatabase.cpp 14
- \sa boundValue(), bindValue(), addBindValue()
+ \sa boundValue(), bindValue(), addBindValue(), boundValueNames()
*/
QVariantList QSqlQuery::boundValues() const
@@ -1164,6 +1189,36 @@ QVariantList QSqlQuery::boundValues() const
}
/*!
+ \since 6.6
+
+ Returns the names of all bound values.
+
+ The order of the list is in binding order, irrespective of whether
+ named or positional binding is used.
+
+ \sa boundValues(), boundValueName()
+*/
+QStringList QSqlQuery::boundValueNames() const
+{
+ return d->sqlResult->boundValueNames();
+}
+
+/*!
+ \since 6.6
+
+ Returns the bound value name at position \a pos.
+
+ The order of the list is in binding order, irrespective of whether
+ named or positional binding is used.
+
+ \sa boundValueNames()
+*/
+QString QSqlQuery::boundValueName(int pos) const
+{
+ return d->sqlResult->boundValueName(pos);
+}
+
+/*!
Returns the last query that was successfully executed.
In most cases this function returns the same string as lastQuery().
@@ -1189,7 +1244,7 @@ QString QSqlQuery::executedQuery() const
For MySQL databases the row's auto-increment field will be returned.
- \note For this function to work in PSQL, the table table must
+ \note For this function to work in PSQL, the table must
contain OIDs, which may not have been created by default. Check the
\c default_with_oids configuration variable to be sure.
@@ -1201,6 +1256,8 @@ QVariant QSqlQuery::lastInsertId() const
}
/*!
+ \property QSqlQuery::numericalPrecisionPolicy
+ \since 6.8
Instruct the database driver to return numerical values with a
precision specified by \a precisionPolicy.
@@ -1219,17 +1276,19 @@ QVariant QSqlQuery::lastInsertId() const
active query. Call \l{exec()}{exec(QString)} or prepare() in order
to activate the policy.
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlDriver::numericalPrecisionPolicy,
+ QSqlDatabase::numericalPrecisionPolicy
*/
+/*!
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
+ */
void QSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
d->sqlResult->setNumericalPrecisionPolicy(precisionPolicy);
}
/*!
- Returns the current precision policy.
-
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy()
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlQuery::numericalPrecisionPolicy() const
{
@@ -1237,8 +1296,41 @@ QSql::NumericalPrecisionPolicy QSqlQuery::numericalPrecisionPolicy() const
}
/*!
- \since 4.3.2
+ \property QSqlQuery::positionalBindingEnabled
+ \since 6.8
+ This property enables or disables the positional \l {Approaches to Binding Values}{binding}
+ for this query, depending on \a enable (default is \c true).
+ Disabling positional bindings is useful if the query itself contains a '?'
+ which must not be handled as a positional binding parameter but, for example,
+ as a JSON operator for a PostgreSQL database.
+
+ This property will have no effect when the database has native
+ support for positional bindings with question marks (see also
+ \l{QSqlDriver::PositionalPlaceholders}).
+*/
+
+/*!
+ Sets \l positionalBindingEnabled to \a enable.
+ \since 6.7
+ \sa positionalBindingEnabled
+*/
+void QSqlQuery::setPositionalBindingEnabled(bool enable)
+{
+ d->sqlResult->setPositionalBindingEnabled(enable);
+}
+
+/*!
+ Returns \l positionalBindingEnabled.
+ \since 6.7
+ \sa positionalBindingEnabled
+*/
+bool QSqlQuery::isPositionalBindingEnabled() const
+{
+ return d->sqlResult->isPositionalBindingEnabled();
+}
+
+/*!
Instruct the database driver that no more data will be fetched from
this query until it is re-executed. There is normally no need to
call this function, but it may be helpful in order to free resources
@@ -1260,8 +1352,6 @@ void QSqlQuery::finish()
}
/*!
- \since 4.4
-
Discards the current result set and navigates to the next if available.
Some databases are capable of returning multiple result sets for
@@ -1287,7 +1377,7 @@ void QSqlQuery::finish()
databases may have restrictions on which statements are allowed to
be used in a SQL batch.
- \sa QSqlDriver::hasFeature(), setForwardOnly(), next(), isSelect(),
+ \sa QSqlDriver::hasFeature(), forwardOnly, next(), isSelect(),
numRowsAffected(), isActive(), lastError()
*/
bool QSqlQuery::nextResult()
@@ -1298,3 +1388,5 @@ bool QSqlQuery::nextResult()
}
QT_END_NAMESPACE
+
+#include "moc_qsqlquery.cpp"
diff --git a/src/sql/kernel/qsqlquery.h b/src/sql/kernel/qsqlquery.h
index ad389fee7e..244b026205 100644
--- a/src/sql/kernel/qsqlquery.h
+++ b/src/sql/kernel/qsqlquery.h
@@ -9,6 +9,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -21,7 +22,12 @@ class QSqlQueryPrivate;
class Q_SQL_EXPORT QSqlQuery
{
+ Q_GADGET
public:
+ Q_PROPERTY(bool forwardOnly READ isForwardOnly WRITE setForwardOnly)
+ Q_PROPERTY(bool positionalBindingEnabled READ isPositionalBindingEnabled WRITE setPositionalBindingEnabled)
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
explicit QSqlQuery(QSqlResult *r);
explicit QSqlQuery(const QString& query = QString(), const QSqlDatabase &db = QSqlDatabase());
explicit QSqlQuery(const QSqlDatabase &db);
@@ -50,6 +56,7 @@ public:
bool isActive() const;
bool isNull(int field) const;
bool isNull(const QString &name) const;
+ bool isNull(QStringView name) const;
int at() const;
QString lastQuery() const;
int numRowsAffected() const;
@@ -64,11 +71,15 @@ public:
void setForwardOnly(bool forward);
bool exec(const QString& query);
QVariant value(int i) const;
- QVariant value(const QString& name) const;
+ QVariant value(const QString &name) const;
+ QVariant value(QStringView name) const;
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ void setPositionalBindingEnabled(bool enable);
+ bool isPositionalBindingEnabled() const;
+
bool seek(int i, bool relative = false);
bool next();
bool previous();
@@ -89,6 +100,8 @@ public:
QVariant boundValue(const QString& placeholder) const;
QVariant boundValue(int pos) const;
QVariantList boundValues() const;
+ QStringList boundValueNames() const;
+ QString boundValueName(int pos) const;
QString executedQuery() const;
QVariant lastInsertId() const;
void finish();
diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp
index 41fcd745cd..53b64c1464 100644
--- a/src/sql/kernel/qsqlrecord.cpp
+++ b/src/sql/kernel/qsqlrecord.cpp
@@ -8,42 +8,20 @@
#include "qlist.h"
#include "qsqlfield.h"
#include "qstring.h"
-#include "qstringlist.h"
QT_BEGIN_NAMESPACE
-class QSqlRecordPrivate
+class QSqlRecordPrivate : public QSharedData
{
public:
- QSqlRecordPrivate();
- QSqlRecordPrivate(const QSqlRecordPrivate &other);
-
- inline bool contains(int index) { return index >= 0 && index < fields.count(); }
- QString createField(int index, const QString &prefix) const;
+ inline bool contains(qsizetype index) const
+ {
+ return index >= 0 && index < fields.size();
+ }
QList<QSqlField> fields;
- QAtomicInt ref;
};
-
-QSqlRecordPrivate::QSqlRecordPrivate() : ref(1)
-{
-}
-
-QSqlRecordPrivate::QSqlRecordPrivate(const QSqlRecordPrivate &other): fields(other.fields), ref(1)
-{
-}
-
-/*! \internal
- Just for compat
-*/
-QString QSqlRecordPrivate::createField(int index, const QString &prefix) const
-{
- QString f;
- if (!prefix.isEmpty())
- f = prefix + u'.';
- f += fields.at(index).name();
- return f;
-}
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlRecordPrivate)
/*!
\class QSqlRecord
@@ -86,8 +64,8 @@ QString QSqlRecordPrivate::createField(int index, const QString &prefix) const
*/
QSqlRecord::QSqlRecord()
+ : d(new QSqlRecordPrivate)
{
- d = new QSqlRecordPrivate();
}
/*!
@@ -97,11 +75,39 @@ QSqlRecord::QSqlRecord()
of a record in \l{constant time}.
*/
-QSqlRecord::QSqlRecord(const QSqlRecord& other)
-{
- d = other.d;
- d->ref.ref();
-}
+QSqlRecord::QSqlRecord(const QSqlRecord &other)
+ = default;
+
+/*!
+ \fn QSqlRecord::QSqlRecord(QSqlRecord &&other)
+ \since 6.6
+
+ Move-constructs a new QSqlRecord from \a other.
+
+ \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.
+*/
+
+/*!
+ \fn QSqlRecord &QSqlRecord::operator=(QSqlRecord &&other)
+ \since 6.6
+
+ Move-assigns \a other to this QSqlRecord 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.
+*/
+
+/*!
+ \fn void QSqlRecord::swap(QSqlRecord &other)
+ \since 6.6
+
+ Swaps SQL record \a other with this SQL record. This operation is very fast
+ and never fails.
+*/
+
/*!
Sets the record equal to \a other.
@@ -110,21 +116,16 @@ QSqlRecord::QSqlRecord(const QSqlRecord& other)
of a record in \l{constant time}.
*/
-QSqlRecord& QSqlRecord::operator=(const QSqlRecord& other)
-{
- qAtomicAssign(d, other.d);
- return *this;
-}
+QSqlRecord& QSqlRecord::operator=(const QSqlRecord &other)
+ = default;
/*!
Destroys the object and frees any allocated resources.
*/
QSqlRecord::~QSqlRecord()
-{
- if (!d->ref.deref())
- delete d;
-}
+ = default;
+
/*!
\fn bool QSqlRecord::operator!=(const QSqlRecord &other) const
@@ -161,14 +162,21 @@ QVariant QSqlRecord::value(int index) const
/*!
\overload
+*/
+QVariant QSqlRecord::value(const QString &name) const
+{
+ return value(QStringView(name));
+}
+
+/*!
+ \overload
Returns the value of the field called \a name in the record. If
field \a name does not exist an invalid variant is returned.
- \sa indexOf()
+ \sa indexOf(), isNull()
*/
-
-QVariant QSqlRecord::value(const QString& name) const
+QVariant QSqlRecord::value(QStringView name) const
{
return value(indexOf(name));
}
@@ -186,15 +194,22 @@ QString QSqlRecord::fieldName(int index) const
}
/*!
+ \overload
+*/
+int QSqlRecord::indexOf(const QString &name) const
+{
+ return indexOf(QStringView(name));
+}
+
+/*!
Returns the position of the field called \a name within the
record, or -1 if it cannot be found. Field names are not
case-sensitive. If more than one field matches, the first one is
returned.
\sa fieldName()
-*/
-
-int QSqlRecord::indexOf(const QString& name) const
+ */
+int QSqlRecord::indexOf(QStringView name) const
{
QStringView tableName;
QStringView fieldName(name);
@@ -228,11 +243,23 @@ QSqlField QSqlRecord::field(int index) const
return d->fields.value(index);
}
-/*! \overload
- Returns the field called \a name.
+/*!
+ \overload
*/
QSqlField QSqlRecord::field(const QString &name) const
{
+ return field(QStringView(name));
+}
+
+/*!
+ \overload
+
+ Returns the field called \a name. If the field called
+ \a name is not found, function returns
+ a \l{default-constructed value}.
+ */
+QSqlField QSqlRecord::field(QStringView name) const
+{
return field(indexOf(name));
}
@@ -243,7 +270,7 @@ QSqlField QSqlRecord::field(const QString &name) const
\sa insert(), replace(), remove()
*/
-void QSqlRecord::append(const QSqlField& field)
+void QSqlRecord::append(const QSqlField &field)
{
detach();
d->fields.append(field);
@@ -254,7 +281,7 @@ void QSqlRecord::append(const QSqlField& field)
\sa append(), replace(), remove()
*/
-void QSqlRecord::insert(int pos, const QSqlField& field)
+void QSqlRecord::insert(int pos, const QSqlField &field)
{
detach();
d->fields.insert(pos, field);
@@ -267,7 +294,7 @@ void QSqlRecord::insert(int pos, const QSqlField& field)
\sa append(), insert(), remove()
*/
-void QSqlRecord::replace(int pos, const QSqlField& field)
+void QSqlRecord::replace(int pos, const QSqlField &field)
{
if (!d->contains(pos))
return;
@@ -318,11 +345,18 @@ bool QSqlRecord::isEmpty() const
/*!
+ \overload
+*/
+bool QSqlRecord::contains(const QString &name) const
+{
+ return contains(QStringView(name));
+}
+
+/*!
Returns \c true if there is a field in the record called \a name;
otherwise returns \c false.
*/
-
-bool QSqlRecord::contains(const QString& name) const
+bool QSqlRecord::contains(QStringView name) const
{
return indexOf(name) >= 0;
}
@@ -337,12 +371,18 @@ bool QSqlRecord::contains(const QString& name) const
void QSqlRecord::clearValues()
{
detach();
- int count = d->fields.count();
- for (int i = 0; i < count; ++i)
- d->fields[i].clear();
+ for (QSqlField &f : d->fields)
+ f.clear();
}
/*!
+ \overload
+*/
+void QSqlRecord::setGenerated(const QString &name, bool generated)
+{
+ setGenerated(QStringView(name), generated);
+}
+/*!
Sets the generated flag for the field called \a name to \a
generated. If the field does not exist, nothing happens. Only
fields that have \a generated set to true are included in the SQL
@@ -350,15 +390,12 @@ void QSqlRecord::clearValues()
\sa isGenerated()
*/
-
-void QSqlRecord::setGenerated(const QString& name, bool generated)
+void QSqlRecord::setGenerated(QStringView name, bool generated)
{
setGenerated(indexOf(name), generated);
}
/*!
- \overload
-
Sets the generated flag for the field \a index to \a generated.
\sa isGenerated()
@@ -373,10 +410,10 @@ void QSqlRecord::setGenerated(int index, bool generated)
}
/*!
- \overload
-
Returns \c true if the field \a index is null or if there is no field at
position \a index; otherwise returns \c false.
+
+ \sa setNull()
*/
bool QSqlRecord::isNull(int index) const
{
@@ -384,12 +421,22 @@ bool QSqlRecord::isNull(int index) const
}
/*!
+ \overload
+*/
+bool QSqlRecord::isNull(const QString &name) const
+{
+ return isNull(QStringView(name));
+}
+
+/*!
+ \overload
+
Returns \c true if the field called \a name is null or if there is no
field called \a name; otherwise returns \c false.
\sa setNull()
*/
-bool QSqlRecord::isNull(const QString& name) const
+bool QSqlRecord::isNull(QStringView name) const
{
return isNull(indexOf(name));
}
@@ -410,29 +457,45 @@ void QSqlRecord::setNull(int index)
/*!
\overload
+*/
+void QSqlRecord::setNull(const QString &name)
+{
+ setNull(QStringView(name));
+}
+
+/*!
+ \overload
Sets the value of the field called \a name to null. If the field
does not exist, nothing happens.
*/
-void QSqlRecord::setNull(const QString& name)
+void QSqlRecord::setNull(QStringView name)
{
setNull(indexOf(name));
}
+/*!
+ \overload
+*/
+bool QSqlRecord::isGenerated(const QString &name) const
+{
+ return isGenerated(QStringView(name));
+}
/*!
+ \overload
+
Returns \c true if the record has a field called \a name and this
field is to be generated (the default); otherwise returns \c false.
\sa setGenerated()
*/
-bool QSqlRecord::isGenerated(const QString& name) const
+bool QSqlRecord::isGenerated(QStringView name) const
{
return isGenerated(indexOf(name));
}
-/*! \overload
-
+/*!
Returns \c true if the record has a field at position \a index and this
field is to be generated (the default); otherwise returns \c false.
@@ -451,7 +514,7 @@ bool QSqlRecord::isGenerated(int index) const
int QSqlRecord::count() const
{
- return d->fields.count();
+ return d->fields.size();
}
/*!
@@ -461,7 +524,7 @@ int QSqlRecord::count() const
\sa setNull()
*/
-void QSqlRecord::setValue(int index, const QVariant& val)
+void QSqlRecord::setValue(int index, const QVariant &val)
{
if (!d->contains(index))
return;
@@ -469,15 +532,22 @@ void QSqlRecord::setValue(int index, const QVariant& val)
d->fields[index].setValue(val);
}
-
+/*!
+ \overload
+*/
+void QSqlRecord::setValue(const QString &name, const QVariant &val)
+{
+ setValue(QStringView(name), val);
+}
/*!
\overload
Sets the value of the field called \a name to \a val. If the field
does not exist, nothing happens.
-*/
-void QSqlRecord::setValue(const QString& name, const QVariant& val)
+ \sa setNull()
+*/
+void QSqlRecord::setValue(QStringView name, const QVariant &val)
{
setValue(indexOf(name), val);
}
@@ -487,7 +557,7 @@ void QSqlRecord::setValue(const QString& name, const QVariant& val)
*/
void QSqlRecord::detach()
{
- qAtomicDetach(d);
+ d.detach();
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/sql/kernel/qsqlrecord.h b/src/sql/kernel/qsqlrecord.h
index cb88f1c62e..8f653ba5e1 100644
--- a/src/sql/kernel/qsqlrecord.h
+++ b/src/sql/kernel/qsqlrecord.h
@@ -5,6 +5,7 @@
#define QSQLRECORD_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -13,46 +14,60 @@ QT_BEGIN_NAMESPACE
class QSqlField;
class QVariant;
class QSqlRecordPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlRecordPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlRecord
{
public:
QSqlRecord();
- QSqlRecord(const QSqlRecord& other);
- QSqlRecord& operator=(const QSqlRecord& other);
+ QSqlRecord(const QSqlRecord &other);
+ QSqlRecord(QSqlRecord &&other) noexcept = default;
+ QSqlRecord& operator=(const QSqlRecord &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSqlRecord)
~QSqlRecord();
+ void swap(QSqlRecord &other) noexcept { d.swap(other.d); }
+
bool operator==(const QSqlRecord &other) const;
inline bool operator!=(const QSqlRecord &other) const { return !operator==(other); }
QVariant value(int i) const;
- QVariant value(const QString& name) const;
- void setValue(int i, const QVariant& val);
- void setValue(const QString& name, const QVariant& val);
+ QVariant value(const QString &name) const;
+ QVariant value(QStringView name) const;
+ void setValue(int i, const QVariant &val);
+ void setValue(const QString &name, const QVariant &val);
+ void setValue(QStringView name, const QVariant &val);
void setNull(int i);
- void setNull(const QString& name);
+ void setNull(const QString &name);
+ void setNull(QStringView name);
bool isNull(int i) const;
- bool isNull(const QString& name) const;
+ bool isNull(const QString &name) const;
+ bool isNull(QStringView name) const;
int indexOf(const QString &name) const;
+ int indexOf(QStringView name) const;
QString fieldName(int i) const;
QSqlField field(int i) const;
QSqlField field(const QString &name) const;
+ QSqlField field(QStringView name) const;
bool isGenerated(int i) const;
- bool isGenerated(const QString& name) const;
- void setGenerated(const QString& name, bool generated);
+ bool isGenerated(const QString &name) const;
+ bool isGenerated(QStringView name) const;
+ void setGenerated(const QString &name, bool generated);
+ void setGenerated(QStringView name, bool generated);
void setGenerated(int i, bool generated);
- void append(const QSqlField& field);
- void replace(int pos, const QSqlField& field);
- void insert(int pos, const QSqlField& field);
+ void append(const QSqlField &field);
+ void replace(int pos, const QSqlField &field);
+ void insert(int pos, const QSqlField &field);
void remove(int pos);
bool isEmpty() const;
- bool contains(const QString& name) const;
+ bool contains(const QString &name) const;
+ bool contains(QStringView name) const;
void clear();
void clearValues();
int count() const;
@@ -60,9 +75,11 @@ public:
private:
void detach();
- QSqlRecordPrivate* d;
+ QExplicitlySharedDataPointer<QSqlRecordPrivate> d;
};
+Q_DECLARE_SHARED(QSqlRecord)
+
#ifndef QT_NO_DEBUG_STREAM
Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlRecord &);
#endif
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index b45f7b6790..59e9879cf0 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -3,9 +3,7 @@
#include "qsqlresult.h"
-#include "qhash.h"
#include "qlist.h"
-#include "qpointer.h"
#include "qsqldriver.h"
#include "qsqlerror.h"
#include "qsqlfield.h"
@@ -15,7 +13,6 @@
#include "qvariant.h"
#include "qdatetime.h"
#include "private/qsqldriver_p.h"
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -26,7 +23,7 @@ QString QSqlResultPrivate::holderAt(int index) const
return holders.size() > index ? holders.at(index).holderName : fieldSerial(index);
}
-QString QSqlResultPrivate::fieldSerial(int i) const
+QString QSqlResultPrivate::fieldSerial(qsizetype i) const
{
return QString(":%1"_L1).arg(i);
}
@@ -40,15 +37,18 @@ static bool qIsAlnum(QChar ch)
QString QSqlResultPrivate::positionalToNamedBinding(const QString &query) const
{
- int n = query.size();
+ if (!positionalBindingEnabled)
+ return query;
+
+ const qsizetype n = query.size();
QString result;
result.reserve(n * 5 / 4);
QChar closingQuote;
- int count = 0;
+ qsizetype count = 0;
bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL);
- for (int i = 0; i < n; ++i) {
+ for (qsizetype i = 0; i < n; ++i) {
QChar ch = query.at(i);
if (!closingQuote.isNull()) {
if (ch == closingQuote) {
@@ -87,14 +87,15 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
query.trimmed().startsWith("EXECUTE BLOCK"_L1, Qt::CaseInsensitive))
return query;
- int n = query.size();
+ const qsizetype n = query.size();
QString result;
result.reserve(n);
QChar closingQuote;
int count = 0;
- int i = 0;
+ qsizetype i = 0;
bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL);
+ const bool qmarkNotationSupported = (sqldriver->dbmsType() != QSqlDriver::PostgreSQL);
while (i < n) {
QChar ch = query.at(i);
@@ -118,10 +119,16 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
int pos = i + 2;
while (pos < n && qIsAlnum(query.at(pos)))
++pos;
+ // if question mark notation is not supported we have to use
+ // the native binding. fieldSerial() should be renamed
+ // to toNativeBinding() and used unconditionally here
+ if (qmarkNotationSupported)
+ result += u'?';
+ else
+ result += fieldSerial(count);
QString holder(query.mid(i, pos - i));
indexes[holder].append(count++);
holders.append(QHolder(holder, i));
- result += u'?';
i = pos;
} else {
if (ch == u'\'' || ch == u'"' || ch == u'`')
@@ -627,37 +634,31 @@ bool QSqlResult::exec()
// fake preparation - just replace the placeholders..
QString query = lastQuery();
if (d->binds == NamedBinding) {
- int i;
- QVariant val;
- QString holder;
- for (i = d->holders.count() - 1; i >= 0; --i) {
- holder = d->holders.at(i).holderName;
- val = d->values.value(d->indexes.value(holder).value(0,-1));
+ for (qsizetype i = d->holders.size() - 1; i >= 0; --i) {
+ const QString &holder = d->holders.at(i).holderName;
+ const QVariant val = d->values.value(d->indexes.value(holder).value(0,-1));
QSqlField f(""_L1, val.metaType());
if (QSqlResultPrivate::isVariantNull(val))
f.setValue(QVariant());
else
f.setValue(val);
query = query.replace(d->holders.at(i).holderPos,
- holder.length(), driver()->formatValue(f));
+ holder.size(), driver()->formatValue(f));
}
} else {
- QString val;
qsizetype i = 0;
- int idx = 0;
- for (idx = 0; idx < d->values.count(); ++idx) {
+ for (const QVariant &var : std::as_const(d->values)) {
i = query.indexOf(u'?', i);
if (i == -1)
continue;
- QVariant var = d->values.value(idx);
QSqlField f(""_L1, var.metaType());
if (QSqlResultPrivate::isVariantNull(var))
f.clear();
else
f.setValue(var);
- val = driver()->formatValue(f);
- query = query.replace(i, 1, driver()->formatValue(f));
- i += val.length();
+ const QString val = driver()->formatValue(f);
+ query = query.replace(i, 1, val);
+ i += val.size();
}
}
@@ -683,7 +684,7 @@ void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType param
QList<int> &indexes = d->indexes[d->fieldSerial(index)];
if (!indexes.contains(index))
indexes.append(index);
- if (d->values.count() <= index)
+ if (d->values.size() <= index)
d->values.resize(index + 1);
d->values[index] = val;
if (paramType != QSql::In || !d->types.isEmpty())
@@ -709,7 +710,7 @@ void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
// bindings - don't reset it
const QList<int> indexes = d->indexes.value(placeholder);
for (int idx : indexes) {
- if (d->values.count() <= idx)
+ if (d->values.size() <= idx)
d->values.resize(idx + 1);
d->values[idx] = val;
if (paramType != QSql::In || !d->types.isEmpty())
@@ -789,22 +790,37 @@ QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
int QSqlResult::boundValueCount() const
{
Q_D(const QSqlResult);
- return d->values.count();
+ return d->values.size();
}
/*!
- Returns a vector of the result's bound values for the current
+ Returns a list of the result's bound values for the current
record (row).
\sa boundValueCount()
*/
-QList<QVariant> &QSqlResult::boundValues() const
+QVariantList QSqlResult::boundValues(QT6_IMPL_NEW_OVERLOAD) const
{
Q_D(const QSqlResult);
- return const_cast<QSqlResultPrivate *>(d)->values;
+ return d->values;
}
/*!
+ \overload
+
+ Returns a mutable reference to the list of the result's bound values
+ for the current record (row).
+
+ \sa boundValueCount()
+*/
+QVariantList &QSqlResult::boundValues(QT6_IMPL_NEW_OVERLOAD)
+{
+ Q_D(QSqlResult);
+ return d->values;
+}
+
+
+/*!
Returns the binding syntax used by prepared queries.
*/
QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const
@@ -847,10 +863,24 @@ void QSqlResult::resetBindCount()
}
/*!
+ Returns the names of all bound values.
+
+ \sa boundValue(), boundValueName()
+ */
+QStringList QSqlResult::boundValueNames() const
+{
+ Q_D(const QSqlResult);
+ QList<QString> ret;
+ for (const QHolder &holder : std::as_const(d->holders))
+ ret.push_back(holder.holderName);
+ return ret;
+}
+
+/*!
Returns the name of the bound value at position \a index in the
current record (row).
- \sa boundValue()
+ \sa boundValue(), boundValueNames()
*/
QString QSqlResult::boundValueName(int index) const
{
@@ -916,8 +946,6 @@ void QSqlResult::virtual_hook(int, void *)
}
/*! \internal
- \since 4.2
-
Executes a prepared query in batch mode if the driver supports it,
otherwise emulates a batch execution using bindValue() and exec().
QSqlDriver::hasFeature() can be used to find out whether a driver
@@ -933,7 +961,7 @@ void QSqlResult::virtual_hook(int, void *)
contain equal amount of values (rows).
NULL values are passed in as typed QVariants, for example
- \c {QVariant(QMetaType::Int)} for an integer NULL value.
+ \c {QVariant(QMetaType::fromType<int>())} for an integer NULL value.
Example:
@@ -948,11 +976,13 @@ bool QSqlResult::execBatch(bool arrayBind)
Q_UNUSED(arrayBind);
Q_D(QSqlResult);
- QList<QVariant> values = d->values;
- if (values.count() == 0)
+ const QList<QVariant> values = d->values;
+ if (values.size() == 0)
return false;
- for (int i = 0; i < values.at(0).toList().count(); ++i) {
- for (int j = 0; j < values.count(); ++j)
+ const qsizetype batchCount = values.at(0).toList().size();
+ const qsizetype valueCount = values.size();
+ for (qsizetype i = 0; i < batchCount; ++i) {
+ for (qsizetype j = 0; j < valueCount; ++j)
bindValue(j, values.at(j).toList().at(i), QSql::In);
if (!exec())
return false;
@@ -983,6 +1013,23 @@ QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
}
/*! \internal
+ */
+void QSqlResult::setPositionalBindingEnabled(bool enable)
+{
+ Q_D(QSqlResult);
+ d->positionalBindingEnabled = enable;
+}
+
+/*! \internal
+ */
+bool QSqlResult::isPositionalBindingEnabled() const
+{
+ Q_D(const QSqlResult);
+ return d->positionalBindingEnabled;
+}
+
+
+/*! \internal
*/
bool QSqlResult::nextResult()
{
diff --git a/src/sql/kernel/qsqlresult.h b/src/sql/kernel/qsqlresult.h
index 2d157cbe87..4200bbde34 100644
--- a/src/sql/kernel/qsqlresult.h
+++ b/src/sql/kernel/qsqlresult.h
@@ -8,9 +8,6 @@
#include <QtCore/qvariant.h>
#include <QtCore/qcontainerfwd.h>
-// for testing:
-class tst_QSqlQuery;
-
QT_BEGIN_NAMESPACE
@@ -26,8 +23,6 @@ class Q_SQL_EXPORT QSqlResult
Q_DECLARE_PRIVATE(QSqlResult)
friend class QSqlQuery;
friend class QSqlTableModelPrivate;
- // for testing:
- friend class ::tst_QSqlQuery;
public:
virtual ~QSqlResult();
@@ -69,8 +64,14 @@ protected:
QSql::ParamType bindValueType(const QString& placeholder) const;
QSql::ParamType bindValueType(int pos) const;
int boundValueCount() const;
+#if QT_SQL_REMOVED_SINCE(6, 6)
QList<QVariant> &boundValues() const;
+#endif
+ QVariantList &boundValues(QT6_DECL_NEW_OVERLOAD);
+ QVariantList boundValues(QT6_DECL_NEW_OVERLOAD) const;
+
QString executedQuery() const;
+ QStringList boundValueNames() const;
QString boundValueName(int pos) const;
void clear();
bool hasOutValues() const;
@@ -96,6 +97,8 @@ protected:
virtual void detachFromResultSet();
virtual void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ void setPositionalBindingEnabled(bool enable);
+ bool isPositionalBindingEnabled() const;
virtual bool nextResult();
void resetBindCount(); // HACK
diff --git a/src/sql/kernel/qsqlresult_p.h b/src/sql/kernel/qsqlresult_p.h
index 7e84283b4f..6eebdaaba4 100644
--- a/src/sql/kernel/qsqlresult_p.h
+++ b/src/sql/kernel/qsqlresult_p.h
@@ -30,11 +30,11 @@ QT_BEGIN_NAMESPACE
inline Class##Private* drv_d_func() { return !sqldriver ? nullptr : reinterpret_cast<Class *>(static_cast<QSqlDriver*>(sqldriver))->d_func(); }
struct QHolder {
- QHolder(const QString &hldr = QString(), int index = -1): holderName(hldr), holderPos(index) { }
+ QHolder(const QString &hldr = QString(), qsizetype index = -1): holderName(hldr), holderPos(index) { }
bool operator==(const QHolder &h) const { return h.holderPos == holderPos && h.holderName == holderName; }
bool operator!=(const QHolder &h) const { return h.holderPos != holderPos || h.holderName != holderName; }
QString holderName;
- int holderPos;
+ qsizetype holderPos;
};
class Q_SQL_EXPORT QSqlResultPrivate
@@ -72,7 +72,7 @@ public:
clearIndex();
}
- virtual QString fieldSerial(int) const;
+ virtual QString fieldSerial(qsizetype) const;
QString positionalToNamedBinding(const QString &query) const;
QString namedToPositionalBinding(const QString &query);
QString holderAt(int index) const;
@@ -98,6 +98,7 @@ public:
bool active = false;
bool isSel = false;
bool forwardOnly = false;
+ bool positionalBindingEnabled = true;
static bool isVariantNull(const QVariant &variant);
};