diff options
Diffstat (limited to 'src/sql')
-rw-r--r-- | src/sql/doc/snippets/code/doc_src_sql-driver.cpp | 5 | ||||
-rw-r--r-- | src/sql/doc/src/sql-driver.qdoc | 16 | ||||
-rw-r--r-- | src/sql/kernel/qsqldatabase.cpp | 1 | ||||
-rw-r--r-- | src/sql/kernel/qsqlerror.cpp | 34 | ||||
-rw-r--r-- | src/sql/kernel/qsqlerror.h | 7 | ||||
-rw-r--r-- | src/sql/kernel/qsqlfield.cpp | 42 | ||||
-rw-r--r-- | src/sql/kernel/qsqlfield.h | 5 | ||||
-rw-r--r-- | src/sql/kernel/qsqlrecord.cpp | 17 | ||||
-rw-r--r-- | src/sql/models/qsqlquerymodel.cpp | 24 | ||||
-rw-r--r-- | src/sql/models/qsqlquerymodel.h | 24 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel.cpp | 14 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel_p.h | 2 |
12 files changed, 162 insertions, 29 deletions
diff --git a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp index f25ad4f2b0..7983386642 100644 --- a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp +++ b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp @@ -90,3 +90,8 @@ qDebug() << q.value(0); // outputs the first RETURN/OUT value QSqlDatabase: QMYSQL driver not loaded QSqlDatabase: available drivers: QMYSQL //! [31] + + +//! [34] +column.contains(QRegularExpression("pattern")); +//! [34] diff --git a/src/sql/doc/src/sql-driver.qdoc b/src/sql/doc/src/sql-driver.qdoc index 4f3f2ce007..2811230106 100644 --- a/src/sql/doc/src/sql-driver.qdoc +++ b/src/sql/doc/src/sql-driver.qdoc @@ -568,6 +568,22 @@ \snippet code/doc_src_sql-driver.qdoc 23 + \section3 Enable REGEXP operator + + SQLite comes with a REGEXP operation. However the needed implementation must + be provided by the user. For convenience a default implementation can be + enabled by \l{QSqlDatabase::setConnectOptions()} {setting the connect + option} \c{QSQLITE_ENABLE_REGEXP} before \l{QSqlDatabase::open()} {the + database connection is opened}. Then a SQL statement like "column REGEXP + 'pattern'" basically expands to the Qt code + + \snippet code/doc_src_sql-driver.cpp 34 + + For better performance the regular expressions are cached internally. By + default the cache size is 25, but it can be changed through the option's + value. For example passing "\c{QSQLITE_ENABLE_REGEXP=10}" reduces the + cache size to 10. + \section3 QSQLITE File Format Compatibility SQLite minor releases sometimes break file format forward compatibility. diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 06c5f56d50..14374c7ca9 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -1186,6 +1186,7 @@ QSqlRecord QSqlDatabase::record(const QString& tablename) const \li QSQLITE_OPEN_READONLY \li QSQLITE_OPEN_URI \li QSQLITE_ENABLE_SHARED_CACHE + \li QSQLITE_ENABLE_REGEXP \endlist \li diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp index d1fc5d4585..50b10aab40 100644 --- a/src/sql/kernel/qsqlerror.cpp +++ b/src/sql/kernel/qsqlerror.cpp @@ -98,6 +98,34 @@ public: type \a type and the optional error number \a number. */ +/*! \fn QSqlError::QSqlError(QSqlError &&other) + Move-constructs a QSqlError instance, making it point at the same + object that \a other was pointing to. + + \note The moved-from object \a other is placed in a + partially-formed state, in which the only valid operations are + destruction and assignment of a new value. + + \since 5.10 +*/ + +/*! \fn QSqlError::operator=(QSqlError &&other) + Move-assigns \a other to this QSqlError instance. + + \note The moved-from object \a other is placed in a + partially-formed state, in which the only valid operations are + destruction and assignment of a new value. + + \since 5.10 +*/ + +/*! \fn QSqlError::swap(QSqlError &other) + Swaps error \a other with this error. This operation is very fast + and never fails. + + \since 5.10 +*/ + #if QT_DEPRECATED_SINCE(5, 3) QSqlError::QSqlError(const QString& driverText, const QString& databaseText, ErrorType type, int number) @@ -117,7 +145,6 @@ QSqlError::QSqlError(const QString& driverText, const QString& databaseText, Err driverText, the database-specific error text \a databaseText, the type \a type and the error code \a code. */ - QSqlError::QSqlError(const QString &driverText, const QString &databaseText, ErrorType type, const QString &code) { @@ -146,7 +173,10 @@ QSqlError::QSqlError(const QSqlError& other) QSqlError& QSqlError::operator=(const QSqlError& other) { - *d = *other.d; + if (d) + *d = *other.d; + else + d = new QSqlErrorPrivate(*other.d); return *this; } diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h index 0ccd32159d..6dac47a7fe 100644 --- a/src/sql/kernel/qsqlerror.h +++ b/src/sql/kernel/qsqlerror.h @@ -66,11 +66,16 @@ public: ErrorType type = NoError, const QString &errorCode = QString()); QSqlError(const QSqlError& other); + QSqlError(QSqlError &&other) Q_DECL_NOTHROW : d(other.d) { other.d = nullptr; } QSqlError& operator=(const QSqlError& other); + QSqlError &operator=(QSqlError &&other) Q_DECL_NOTHROW { swap(other); return *this; } + bool operator==(const QSqlError& other) const; bool operator!=(const QSqlError& other) const; ~QSqlError(); + void swap(QSqlError &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + QString driverText() const; QString databaseText() const; ErrorType type() const; @@ -102,6 +107,8 @@ private: }; }; +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QSqlError) + #ifndef QT_NO_DEBUG_STREAM Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlError &); #endif diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp index bb810b11df..59b992e803 100644 --- a/src/sql/kernel/qsqlfield.cpp +++ b/src/sql/kernel/qsqlfield.cpp @@ -47,9 +47,9 @@ class QSqlFieldPrivate { public: QSqlFieldPrivate(const QString &name, - QVariant::Type type) : + QVariant::Type type, const QString &tableName) : ref(1), nm(name), ro(false), type(type), req(QSqlField::Unknown), - len(-1), prec(-1), tp(-1), gen(true), autoval(false) + len(-1), prec(-1), tp(-1), gen(true), autoval(false), table(tableName) { } @@ -64,7 +64,8 @@ public: def(other.def), tp(other.tp), gen(other.gen), - autoval(other.autoval) + autoval(other.autoval), + table(other.table) {} bool operator==(const QSqlFieldPrivate& other) const @@ -77,7 +78,8 @@ public: && prec == other.prec && def == other.def && gen == other.gen - && autoval == other.autoval); + && autoval == other.autoval + && table == other.table); } QAtomicInt ref; @@ -91,6 +93,7 @@ public: int tp; uint gen: 1; uint autoval: 1; + QString table; }; @@ -153,14 +156,15 @@ public: /*! Constructs an empty field called \a fieldName of variant type \a - type. + type in \a table. \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(), setGenerated(), setReadOnly() */ -QSqlField::QSqlField(const QString& fieldName, QVariant::Type type) +QSqlField::QSqlField(const QString &fieldName, QVariant::Type type, + const QString &table) { - d = new QSqlFieldPrivate(fieldName, type); + d = new QSqlFieldPrivate(fieldName, type, table); val = QVariant(type); } @@ -518,6 +522,7 @@ QDebug operator<<(QDebug dbg, const QSqlField &f) QDebugStateSaver saver(dbg); dbg.nospace(); dbg << "QSqlField(" << f.name() << ", " << QMetaType::typeName(f.type()); + dbg << ", tableName: " << (f.tableName().isEmpty() ? QStringLiteral("(not specified)") : f.tableName()); if (f.length() >= 0) dbg << ", length: " << f.length(); if (f.precision() >= 0) @@ -565,4 +570,27 @@ void QSqlField::setAutoValue(bool autoVal) d->autoval = autoVal; } +/*! + Sets the tableName of the field to \a table. + + \sa tableName() +*/ + +void QSqlField::setTableName(const QString &table) +{ + detach(); + d->table = table; +} + +/*! + Returns the tableName of the field. + + \sa setTableName() +*/ + +QString QSqlField::tableName() const +{ + return d->table; +} + QT_END_NAMESPACE diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h index 0d8c51f801..30474735f4 100644 --- a/src/sql/kernel/qsqlfield.h +++ b/src/sql/kernel/qsqlfield.h @@ -55,7 +55,8 @@ public: enum RequiredStatus { Unknown = -1, Optional = 0, Required = 1 }; explicit QSqlField(const QString& fieldName = QString(), - QVariant::Type type = QVariant::Invalid); + QVariant::Type type = QVariant::Invalid, + const QString &tableName = QString()); QSqlField(const QSqlField& other); QSqlField& operator=(const QSqlField& other); @@ -68,6 +69,8 @@ public: { return val; } void setName(const QString& name); QString name() const; + void setTableName(const QString &tableName); + QString tableName() const; bool isNull() const; void setReadOnly(bool readOnly); bool isReadOnly() const; diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp index d5adff67a4..1c9ad5ec63 100644 --- a/src/sql/kernel/qsqlrecord.cpp +++ b/src/sql/kernel/qsqlrecord.cpp @@ -232,10 +232,23 @@ QString QSqlRecord::fieldName(int index) const int QSqlRecord::indexOf(const QString& name) const { - QString nm = name.toUpper(); + QString tableName; + QString fieldName = name; + const int idx = name.indexOf(QLatin1Char('.')); + if (idx != -1) { + tableName = name.left(idx); + fieldName = name.mid(idx + 1); + } for (int i = 0; i < count(); ++i) { - if (d->fields.at(i).name().toUpper() == nm) // TODO: case-insensitive comparison + // Check the passed in name first in case it is an alias using a dot. + // Then check if both the table and field match when there is a table name specified. + const auto currentField = d->fields.at(i); + const auto currentFieldName = currentField.name(); + if (currentFieldName.compare(name, Qt::CaseInsensitive) == 0 + || (idx != -1 && currentFieldName.compare(fieldName, Qt::CaseInsensitive) == 0 + && currentField.tableName().compare(tableName, Qt::CaseInsensitive) == 0)) { return i; + } } return -1; } diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index 864c5b9946..c0b1061c6b 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -212,6 +212,30 @@ bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const return (!parent.isValid() && !d->atEnd); } +/*! + \since 5.10 + \reimp + + Returns the model's role names. + + Qt defines only one role for the QSqlQueryModel: + + \table + \header + \li Qt Role + \li QML Role Name + \row + \li Qt::DisplayRole + \li display + \endtable +*/ +QHash<int, QByteArray> QSqlQueryModel::roleNames() const +{ + return QHash<int, QByteArray> { + { Qt::DisplayRole, QByteArrayLiteral("display") } + }; +} + /*! \internal */ void QSqlQueryModel::beginInsertRows(const QModelIndex &parent, int first, int last) diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h index f786f71300..869a5f030c 100644 --- a/src/sql/models/qsqlquerymodel.h +++ b/src/sql/models/qsqlquerymodel.h @@ -58,22 +58,22 @@ class Q_SQL_EXPORT QSqlQueryModel: public QAbstractTableModel Q_DECLARE_PRIVATE(QSqlQueryModel) public: - explicit QSqlQueryModel(QObject *parent = Q_NULLPTR); + explicit QSqlQueryModel(QObject *parent = nullptr); virtual ~QSqlQueryModel(); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; QSqlRecord record(int row) const; QSqlRecord record() const; - QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int role = Qt::DisplayRole) const override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, - int role = Qt::EditRole) Q_DECL_OVERRIDE; + int role = Qt::EditRole) override; - bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; + bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; + bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override; void setQuery(const QSqlQuery &query); void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase()); @@ -83,8 +83,10 @@ public: QSqlError lastError() const; - void fetchMore(const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE; - bool canFetchMore(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + void fetchMore(const QModelIndex &parent = QModelIndex()) override; + bool canFetchMore(const QModelIndex &parent = QModelIndex()) const override; + + QHash<int, QByteArray> roleNames() const override; protected: void beginInsertRows(const QModelIndex &parent, int first, int last); @@ -105,7 +107,7 @@ protected: virtual QModelIndex indexInQuery(const QModelIndex &item) const; void setLastError(const QSqlError &error); - QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = Q_NULLPTR); + QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = nullptr); }; QT_END_NAMESPACE diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index c0706ac22d..05feb87466 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -477,9 +477,9 @@ QVariant QSqlTableModel::data(const QModelIndex &index, int role) const if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole)) return QVariant(); - const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(index.row()); - if (mrow.op() != QSqlTableModelPrivate::None) - return mrow.rec().value(index.column()); + const auto it = d->cache.constFind(index.row()); + if (it != d->cache.constEnd() && it->op() != QSqlTableModelPrivate::None) + return it->rec().value(index.column()); return QSqlQueryModel::data(index, role); } @@ -532,7 +532,10 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const if (!index.isValid()) return false; - const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row()); + const auto it = d->cache.constFind(index.row()); + if (it == d->cache.constEnd()) + return false; + const QSqlTableModelPrivate::ModifiedRow &row = *it; if (row.submitted()) return false; @@ -1231,7 +1234,8 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const { Q_D(const QSqlTableModel); - if (d->cache.value(item.row()).insert()) + const auto it = d->cache.constFind(item.row()); + if (it != d->cache.constEnd() && it->insert()) return QModelIndex(); const int rowOffset = d->insertCount(item.row()); diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index 3b64cdfa47..490bb48a24 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -117,7 +117,7 @@ public: m_rec = m_db_values; setGenerated(m_rec, m_op == Delete); } - inline QSqlRecord rec() const { return m_rec; } + inline const QSqlRecord &rec() const { return m_rec; } inline QSqlRecord& recRef() { return m_rec; } inline void setValue(int c, const QVariant &v) { |