summaryrefslogtreecommitdiffstats
path: root/src/sql/models/qsqlrelationaltablemodel.cpp
diff options
context:
space:
mode:
authorChristian Ehrlicher <[email protected]>2024-07-21 18:39:40 +0200
committerChristian Ehrlicher <[email protected]>2024-07-22 21:08:32 +0200
commitc0aabbd8a0c5a01c2048bcaf36525570a8e0bb35 (patch)
tree279f9816f7fa35e737ccf7989595443e5542e2e0 /src/sql/models/qsqlrelationaltablemodel.cpp
parentf4dc5fdf56545626174625729a5bf65a2c30437c (diff)
SQL/QSqlRelationTableModel: don't crash with more than one relation
When more than one relation is used, an internal container might be resized which can lead to a reallocation. Since the internal data structure holds a pointer to an element of this container, this pointer is invalidated after the reallocation. Therefore store a QSharedPointer instead. Pick-to: 6.8 6.7 6.5 Fixes: QTBUG-60674 Change-Id: I18c6157c7328be201f8b89a7ca12f423a86d9b71 Reviewed-by: Axel Spoerl <[email protected]>
Diffstat (limited to 'src/sql/models/qsqlrelationaltablemodel.cpp')
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp65
1 files changed, 35 insertions, 30 deletions
diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp
index 12185147784..d892be070e7 100644
--- a/src/sql/models/qsqlrelationaltablemodel.cpp
+++ b/src/sql/models/qsqlrelationaltablemodel.cpp
@@ -103,7 +103,8 @@ class QRelatedTableModel;
struct QRelation
{
public:
- QRelation(): model(nullptr), m_parent(nullptr), m_dictInitialized(false) {}
+ Q_DISABLE_COPY(QRelation) // QRelatedTableModel stores a pointer to this class
+ QRelation() = default;
void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation);
void populateModel();
@@ -116,18 +117,18 @@ struct QRelation
bool isValid() const;
QSqlRelation rel;
- QRelatedTableModel *model;
+ QRelatedTableModel *model = nullptr;
QHash<QString, QVariant> dictionary;//maps keys to display values
private:
- QSqlRelationalTableModel *m_parent;
- bool m_dictInitialized;
+ QSqlRelationalTableModel *m_parent = nullptr;
+ bool m_dictInitialized = false;
};
class QRelatedTableModel : public QSqlTableModel
{
public:
- QRelatedTableModel(QRelation *rel, QObject *parent = nullptr, const QSqlDatabase &db = QSqlDatabase());
+ QRelatedTableModel(QRelation *rel, QObject *parent, const QSqlDatabase &db);
bool select() override;
private:
bool firstSelect;
@@ -241,7 +242,7 @@ public:
QString fullyQualifiedFieldName(const QString &tableName, const QString &fieldName) const;
int nameToIndex(const QString &name) const override;
- mutable QList<QRelation> relations;
+ QList<QSharedPointer<QRelation>> relations;
QSqlRecord baseRec; // the record without relations
void clearChanges();
void clearCache() override;
@@ -254,7 +255,7 @@ public:
void QSqlRelationalTableModelPrivate::clearChanges()
{
for (auto &rel : relations)
- rel.clear();
+ rel->clear();
}
void QSqlRelationalTableModelPrivate::revertCachedRow(int row)
@@ -276,7 +277,7 @@ int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
void QSqlRelationalTableModelPrivate::clearCache()
{
for (auto &rel : relations)
- rel.clearDictionary();
+ rel->clearDictionary();
QSqlTableModelPrivate::clearCache();
}
@@ -394,10 +395,10 @@ QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) cons
Q_D(const QSqlRelationalTableModel);
if (role == Qt::DisplayRole && index.column() >= 0 && index.column() < d->relations.size() &&
- d->relations.value(index.column()).isValid()) {
- QRelation &relation = d->relations[index.column()];
- if (!relation.isDictionaryInitialized())
- relation.populateDictionary();
+ d->relations.at(index.column())->isValid()) {
+ auto relation = d->relations.at(index.column());
+ if (!relation->isDictionaryInitialized())
+ relation->populateDictionary();
//only perform a dictionary lookup for the display value
//when the value at index has been changed or added.
@@ -409,7 +410,7 @@ QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) cons
if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) {
QVariant v = row.rec().value(index.column());
if (v.isValid())
- return relation.dictionary[v.toString()];
+ return relation->dictionary[v.toString()];
}
}
}
@@ -437,11 +438,11 @@ bool QSqlRelationalTableModel::setData(const QModelIndex &index, const QVariant
{
Q_D(QSqlRelationalTableModel);
if ( role == Qt::EditRole && index.column() > 0 && index.column() < d->relations.size()
- && d->relations.value(index.column()).isValid()) {
- QRelation &relation = d->relations[index.column()];
- if (!relation.isDictionaryInitialized())
- relation.populateDictionary();
- if (!relation.dictionary.contains(value.toString()))
+ && d->relations.at(index.column())->isValid()) {
+ auto relation = d->relations.at(index.column());
+ if (!relation->isDictionaryInitialized())
+ relation->populateDictionary();
+ if (!relation->dictionary.contains(value.toString()))
return false;
}
return QSqlTableModel::setData(index, value, role);
@@ -470,9 +471,13 @@ void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relat
Q_D(QSqlRelationalTableModel);
if (column < 0)
return;
- if (d->relations.size() <= column)
+ if (d->relations.size() <= column) {
+ const auto oldSize = d->relations.size();
d->relations.resize(column + 1);
- d->relations[column].init(this, relation);
+ for (auto i = oldSize; i < d->relations.size(); ++i)
+ d->relations[i] = QSharedPointer<QRelation>::create();
+ }
+ d->relations.at(column)->init(this, relation);
}
/*!
@@ -484,7 +489,7 @@ void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relat
QSqlRelation QSqlRelationalTableModel::relation(int column) const
{
Q_D(const QSqlRelationalTableModel);
- return d->relations.value(column).rel;
+ return d->relations.value(column) ? d->relations.at(column)->rel : QSqlRelation();
}
QString QSqlRelationalTableModelPrivate::fullyQualifiedFieldName(const QString &tableName,
@@ -513,7 +518,7 @@ QString QSqlRelationalTableModel::selectStatement() const
QHash<QString, int> fieldNames;
QStringList fieldList;
for (int i = 0; i < d->baseRec.count(); ++i) {
- QSqlRelation relation = d->relations.value(i).rel;
+ QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
QString name;
if (relation.isValid()) {
// Count the display column name, not the original foreign key
@@ -540,7 +545,7 @@ QString QSqlRelationalTableModel::selectStatement() const
QString conditions;
QString from = SqlrTm::from(tableName());
for (int i = 0; i < d->baseRec.count(); ++i) {
- QSqlRelation relation = d->relations.value(i).rel;
+ QSqlRelation relation = d->relations.value(i) ? d->relations.at(i)->rel : QSqlRelation();
const QString tableField = d->fullyQualifiedFieldName(tableName(), d->db.driver()->escapeIdentifier(d->baseRec.fieldName(i), QSqlDriver::FieldName));
if (relation.isValid()) {
const QString relTableAlias = SqlrTm::relTablePrefix(i);
@@ -605,13 +610,13 @@ QSqlTableModel *QSqlRelationalTableModel::relationModel(int column) const
if (column < 0 || column >= d->relations.size())
return nullptr;
- QRelation &relation = const_cast<QSqlRelationalTableModelPrivate *>(d)->relations[column];
- if (!relation.isValid())
+ auto relation = d->relations.at(column);
+ if (!relation || !relation->isValid())
return nullptr;
- if (!relation.model)
- relation.populateModel();
- return relation.model;
+ if (!relation->model)
+ relation->populateModel();
+ return relation->model;
}
/*!
@@ -682,7 +687,7 @@ void QSqlRelationalTableModel::setTable(const QString &table)
void QSqlRelationalTableModelPrivate::translateFieldNames(QSqlRecord &values) const
{
for (int i = 0; i < values.count(); ++i) {
- if (relations.value(i).isValid()) {
+ if (relations.value(i) && relations.at(i)->isValid()) {
QVariant v = values.value(i);
bool gen = values.isGenerated(i);
values.replace(i, baseRec.field(i));
@@ -725,7 +730,7 @@ QString QSqlRelationalTableModel::orderByClause() const
{
Q_D(const QSqlRelationalTableModel);
- const QSqlRelation rel = d->relations.value(d->sortColumn).rel;
+ const QSqlRelation rel = d->relations.value(d->sortColumn) ? d->relations.at(d->sortColumn)->rel : QSqlRelation();
if (!rel.isValid())
return QSqlTableModel::orderByClause();