QSqlTableModel::setData(): fix non-change detection

Commit 10ff9de91b introduced the
optimization of ignoring non-changes, but it overshot the mark.
It neglected to consider that QVariant's equality operator does not
compare the null flag. It also failed to consider that setData() has
a useful side effect of setting the generated flag in a column of a
pending INSERT. This is important when the application actually wants
a NULL to be inserted into the column.

Task-number: QTBUG-29217
Change-Id: I1368f7acc21eebfeb5a8d23746fc38f6f30fd395
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Mark Brand <mabrand@mabrand.nl>
This commit is contained in:
Mark Brand 2013-01-30 00:39:53 +01:00 committed by The Qt Project
parent a694b9f8d2
commit 33c212b7d2
2 changed files with 77 additions and 1 deletions

View File

@ -587,7 +587,10 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in
if (!(flags(index) & Qt::ItemIsEditable))
return false;
if (QSqlTableModel::data(index, role) == value)
const QVariant oldValue = QSqlTableModel::data(index, role);
if (value == oldValue
&& value.isNull() == oldValue.isNull()
&& d->cache.value(index.row()).op() != QSqlTableModelPrivate::Insert)
return true;
QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];

View File

@ -83,6 +83,8 @@ private slots:
void insertColumns();
void submitAll_data() { generic_data(); }
void submitAll();
void setData_data() { generic_data(); }
void setData();
void setRecord_data() { generic_data(); }
void setRecord();
void setRecordReimpl_data() { generic_data(); }
@ -501,6 +503,77 @@ void tst_QSqlTableModel::insertColumns()
QCOMPARE(model.data(model.index(3, 5)), QVariant());
}
void tst_QSqlTableModel::setData()
{
QFETCH(QString, dbName);
QSqlDatabase db = QSqlDatabase::database(dbName);
CHECK_DATABASE(db);
QSqlTableModel model(0, db);
model.setEditStrategy(QSqlTableModel::OnManualSubmit);
model.setTable(test);
model.setSort(0, Qt::AscendingOrder);
QVERIFY_SQL(model, select());
// initial state
QModelIndex idx = model.index(0, 0);
QVariant val = model.data(idx);
QVERIFY(val == int(1));
QVERIFY(!val.isNull());
QFAIL_SQL(model, isDirty());
// change 1 to 0
idx = model.index(0, 0);
QVERIFY_SQL(model, setData(idx, int(0)));
val = model.data(idx);
QVERIFY(val == int(0));
QVERIFY(!val.isNull());
QVERIFY_SQL(model, isDirty(idx));
QVERIFY_SQL(model, submitAll());
// change 0 to NULL
idx = model.index(0, 0);
QVERIFY_SQL(model, setData(idx, QVariant(QVariant::Int)));
val = model.data(idx);
QVERIFY(val == QVariant(QVariant::Int));
QVERIFY(val.isNull());
QVERIFY_SQL(model, isDirty(idx));
QVERIFY_SQL(model, submitAll());
// change NULL to 0
idx = model.index(0, 0);
QVERIFY_SQL(model, setData(idx, int(0)));
val = model.data(idx);
QVERIFY(val == int(0));
QVERIFY(!val.isNull());
QVERIFY_SQL(model, isDirty(idx));
QVERIFY_SQL(model, submitAll());
// ignore unchanged 0 to 0
idx = model.index(0, 0);
QVERIFY_SQL(model, setData(idx, int(0)));
val = model.data(idx);
QVERIFY(val == int(0));
QVERIFY(!val.isNull());
QFAIL_SQL(model, isDirty(idx));
// pending INSERT
QVERIFY_SQL(model, insertRow(0));
// initial state
idx = model.index(0, 0);
QSqlRecord rec = model.record(0);
QVERIFY(rec.value(0) == QVariant(QVariant::Int));
QVERIFY(rec.isNull(0));
QVERIFY(!rec.isGenerated(0));
// unchanged value, but causes column to be included in INSERT
QVERIFY_SQL(model, setData(idx, QVariant(QVariant::Int)));
rec = model.record(0);
QVERIFY(rec.value(0) == QVariant(QVariant::Int));
QVERIFY(rec.isNull(0));
QVERIFY(rec.isGenerated(0));
QVERIFY_SQL(model, submitAll());
}
void tst_QSqlTableModel::setRecord()
{
QFETCH(QString, dbName);