QSqlTableModel::selectRow(): fix failure on uncached rows
authorMark Brand <mabrand@mabrand.nl>
Mon, 17 Sep 2012 12:22:29 +0000 (14:22 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 24 Sep 2012 19:27:51 +0000 (21:27 +0200)
This method was originally intended for refreshing rows after
submitting changes. It should also work for refreshing rows
that are unchanged (i.e., not cached), but did not because
constructing the primary values depended on the cache. As a
consequence, the WHERE clause for the query was not created.

Fixed by deriving primary values for uncached rows from the
query record. Note that the cache is still authoritative for rows
it holds. This is important because the prmary values there may
differ from the original query record due to changes to columns
of the primary key.

Includes new test.

Change-Id: I41cca2cbf26019d4b495ffa6d876e2b55ec57803
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Mark Brand <mabrand@mabrand.nl>
src/sql/models/qsqltablemodel.cpp
src/sql/models/qsqltablemodel_p.h
tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp

index ce830ce..fbd9207 100644 (file)
@@ -195,9 +195,27 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
     return true;
 }
 
+QSqlRecord QSqlTableModelPrivate::primaryValues(const QSqlRecord &rec, const QSqlRecord &pIndex)
+{
+    QSqlRecord pValues(pIndex);
+
+    for (int i = pValues.count() - 1; i >= 0; --i)
+        pValues.setValue(i, rec.value(pValues.fieldName(i)));
+
+    return pValues;
+}
+
 QSqlRecord QSqlTableModelPrivate::primaryValues(int row) const
 {
-    return cache.value(row).primaryValues(primaryIndex.isEmpty() ? rec : primaryIndex);
+    Q_Q(const QSqlTableModel);
+
+    const QSqlRecord &pIndex = primaryIndex.isEmpty() ? rec : primaryIndex;
+
+    ModifiedRow mr = cache.value(row);
+    if (mr.op() != None)
+        return mr.primaryValues(pIndex);
+    else
+        return primaryValues(q->QSqlQueryModel::record(row), pIndex);
 }
 
 /*!
index ccdc124..462ff96 100644 (file)
@@ -70,6 +70,7 @@ public:
           busyInsertingRows(false)
     {}
     void clear();
+    static QSqlRecord primaryValues(const QSqlRecord &rec, const QSqlRecord &pIndex);
     QSqlRecord primaryValues(int index) const;
     virtual void clearCache();
     QSqlRecord record(const QVector<QVariant> &values) const;
@@ -167,12 +168,7 @@ public:
             if (m_op == None || m_op == Insert)
                 return QSqlRecord();
 
-            QSqlRecord values(pi);
-
-            for (int i = values.count() - 1; i >= 0; --i)
-                values.setValue(i, m_db_values.value(values.fieldName(i)));
-
-            return values;
+            return QSqlTableModelPrivate::primaryValues(m_db_values, pi);
         }
     private:
         inline static void setGenerated(QSqlRecord& r, bool g)
index 7f67f74..cbc9cd5 100644 (file)
@@ -75,6 +75,8 @@ private slots:
 
     void select_data() { generic_data(); }
     void select();
+    void selectRow_data() { generic_data(); }
+    void selectRow();
     void insertColumns_data() { generic_data_with_strategies(); }
     void insertColumns();
     void submitAll_data() { generic_data(); }
@@ -311,6 +313,49 @@ void tst_QSqlTableModel::select()
     QCOMPARE(model.data(model.index(3, 3)), QVariant());
 }
 
+void tst_QSqlTableModel::selectRow()
+{
+    QFETCH(QString, dbName);
+    QSqlDatabase db = QSqlDatabase::database(dbName);
+    CHECK_DATABASE(db);
+
+    QString tbl = qTableName("pktest", __FILE__);
+    QSqlQuery q(db);
+    q.exec("DELETE FROM " + tbl);
+    q.exec("INSERT INTO " + tbl + " (id, a) VALUES (0, 'a')");
+    q.exec("INSERT INTO " + tbl + " (id, a) VALUES (1, 'b')");
+    q.exec("INSERT INTO " + tbl + " (id, a) VALUES (2, 'c')");
+
+    QSqlTableModel model(0, db);
+    model.setEditStrategy(QSqlTableModel::OnFieldChange);
+    model.setTable(tbl);
+    model.setSort(0, Qt::AscendingOrder);
+    QVERIFY_SQL(model, select());
+
+    QCOMPARE(model.rowCount(), 3);
+    QCOMPARE(model.columnCount(), 2);
+
+    QModelIndex idx = model.index(1, 1);
+
+    // Check if selectRow() refreshes an unchanged row.
+    // Row is not in cache yet.
+    q.exec("UPDATE " + tbl + " SET a = 'Qt' WHERE id = 1");
+    QCOMPARE(model.data(idx).toString(), QString("b"));
+    model.selectRow(1);
+    QCOMPARE(model.data(idx).toString(), QString("Qt"));
+
+    // Check if selectRow() refreshes a changed row.
+    // Row is already in the cache.
+    model.setData(idx, QString("b"));
+    QCOMPARE(model.data(idx).toString(), QString("b"));
+    q.exec("UPDATE " + tbl + " SET a = 'Qt' WHERE id = 1");
+    QCOMPARE(model.data(idx).toString(), QString("b"));
+    model.selectRow(1);
+    QCOMPARE(model.data(idx).toString(), QString("Qt"));
+
+    q.exec("DELETE FROM " + tbl);
+}
+
 void tst_QSqlTableModel::insertColumns()
 {
     // Just like the select test, with extra stuff