Fix some removeRows issues with QSqlTableModel.
[qt:qt.git] / tests / auto / qsqltablemodel / tst_qsqltablemodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include "../qsqldatabase/tst_databases.h"
45 #include <QtSql>
46
47 const QString test(qTableName("test", __FILE__)),
48                    test2(qTableName("test2", __FILE__)),
49                    test3(qTableName("test3", __FILE__));
50
51 //TESTED_CLASS=
52 //TESTED_FILES=
53
54 Q_DECLARE_METATYPE(QModelIndex)
55
56 class tst_QSqlTableModel : public QObject
57 {
58     Q_OBJECT
59
60 public:
61     tst_QSqlTableModel();
62     virtual ~tst_QSqlTableModel();
63
64
65     void dropTestTables();
66     void createTestTables();
67     void recreateTestTables();
68     void repopulateTestTables();
69
70     tst_Databases dbs;
71
72 public slots:
73     void initTestCase();
74     void cleanupTestCase();
75     void init();
76     void cleanup();
77 private slots:
78
79     void select_data() { generic_data(); }
80     void select();
81     void submitAll_data() { generic_data(); }
82     void submitAll();
83     void setRecord_data()  { generic_data(); }
84     void setRecord();
85     void insertRow_data() { generic_data(); }
86     void insertRow();
87     void insertRecord_data() { generic_data(); }
88     void insertRecord();
89     void insertMultiRecords_data() { generic_data(); }
90     void insertMultiRecords();
91     void removeRow_data() { generic_data(); }
92     void removeRow();
93     void removeRows_data() { generic_data(); }
94     void removeRows();
95     void removeInsertedRow_data() { generic_data_with_strategies(); }
96     void removeInsertedRow();
97     void removeInsertedRows_data() { generic_data(); }
98     void removeInsertedRows();
99     void setFilter_data() { generic_data(); }
100     void setFilter();
101     void setInvalidFilter_data() { generic_data(); }
102     void setInvalidFilter();
103
104     void emptyTable_data() { generic_data(); }
105     void emptyTable();
106     void tablesAndSchemas_data() { generic_data("QPSQL"); }
107     void tablesAndSchemas();
108     void whitespaceInIdentifiers_data() { generic_data(); }
109     void whitespaceInIdentifiers();
110     void primaryKeyOrder_data() { generic_data("QSQLITE"); }
111     void primaryKeyOrder();
112
113     void sqlite_bigTable_data() { generic_data("QSQLITE"); }
114     void sqlite_bigTable();
115
116     // bug specific tests
117     void insertRecordBeforeSelect_data() { generic_data(); }
118     void insertRecordBeforeSelect();
119     void submitAllOnInvalidTable_data() { generic_data(); }
120     void submitAllOnInvalidTable();
121     void insertRecordsInLoop_data() { generic_data(); }
122     void insertRecordsInLoop();
123     void sqlite_attachedDatabase_data() { generic_data("QSQLITE"); }
124     void sqlite_attachedDatabase(); // For task 130799
125     void tableModifyWithBlank_data() { generic_data(); }
126     void tableModifyWithBlank(); // For mail task
127
128     void removeColumnAndRow_data() { generic_data(); }
129     void removeColumnAndRow(); // task 256032
130
131     void insertBeforeDelete_data() { generic_data(); }
132     void insertBeforeDelete();
133 private:
134     void generic_data(const QString& engine=QString());
135 };
136
137 tst_QSqlTableModel::tst_QSqlTableModel()
138 {
139     qRegisterMetaType<QModelIndex>("QModelIndex");
140     dbs.open();
141 }
142
143 tst_QSqlTableModel::~tst_QSqlTableModel()
144 {
145 }
146
147 void tst_QSqlTableModel::dropTestTables()
148 {
149     for (int i = 0; i < dbs.dbNames.count(); ++i) {
150         QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i));
151         QSqlQuery q(db);
152         if(tst_Databases::isPostgreSQL(db))
153             QVERIFY_SQL( q, exec("set client_min_messages='warning'"));
154
155         QStringList tableNames;
156         tableNames << test
157                    << test2
158                    << test3
159                    << qTableName("test4", __FILE__)
160                    << qTableName("emptytable", __FILE__)
161                    << qTableName("bigtable", __FILE__)
162                    << qTableName("foo", __FILE__);
163         if (testWhiteSpaceNames(db.driverName()))
164             tableNames << qTableName("qtestw hitespace", db.driver());
165
166         tst_Databases::safeDropTables(db, tableNames);
167
168         if (db.driverName().startsWith("QPSQL")) {
169             q.exec("DROP SCHEMA " + qTableName("testschema", __FILE__) + " CASCADE");
170         }
171     }
172 }
173
174 void tst_QSqlTableModel::createTestTables()
175 {
176     for (int i = 0; i < dbs.dbNames.count(); ++i) {
177         QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i));
178         QSqlQuery q(db);
179
180         QVERIFY_SQL( q, exec("create table " + test + "(id int, name varchar(20), title int)"));
181
182         QVERIFY_SQL( q, exec("create table " + test2 + "(id int, title varchar(20))"));
183
184         QVERIFY_SQL( q, exec("create table " + test3 + "(id int, random varchar(20), randomtwo varchar(20))"));
185
186         if(!tst_Databases::isSqlServer(db))
187             QVERIFY_SQL( q, exec("create table " + qTableName("test4", __FILE__) + "(column1 varchar(50), column2 varchar(50), column3 varchar(50))"));
188         else
189             QVERIFY_SQL( q, exec("create table " + qTableName("test4", __FILE__) + "(column1 varchar(50), column2 varchar(50) NULL, column3 varchar(50))"));
190
191
192         QVERIFY_SQL( q, exec("create table " + qTableName("emptytable", __FILE__) + "(id int)"));
193
194         if (testWhiteSpaceNames(db.driverName())) {
195             QString qry = "create table " + qTableName("qtestw hitespace", db.driver()) + " ("+ db.driver()->escapeIdentifier("a field", QSqlDriver::FieldName) + " int)";
196             QVERIFY_SQL( q, exec(qry));
197         }
198     }
199 }
200
201 void tst_QSqlTableModel::repopulateTestTables()
202 {
203     for (int i = 0; i < dbs.dbNames.count(); ++i) {
204         QSqlDatabase db = QSqlDatabase::database(dbs.dbNames.at(i));
205         QSqlQuery q(db);
206
207         q.exec("delete from " + test);
208         QVERIFY_SQL( q, exec("insert into " + test + " values(1, 'harry', 1)"));
209         QVERIFY_SQL( q, exec("insert into " + test + " values(2, 'trond', 2)"));
210         QVERIFY_SQL( q, exec("insert into " + test + " values(3, 'vohi', 3)"));
211
212         q.exec("delete from " + test2);
213         QVERIFY_SQL( q, exec("insert into " + test2 + " values(1, 'herr')"));
214         QVERIFY_SQL( q, exec("insert into " + test2 + " values(2, 'mister')"));
215
216         q.exec("delete from " + test3);
217         QVERIFY_SQL( q, exec("insert into " + test3 + " values(1, 'foo', 'bar')"));
218         QVERIFY_SQL( q, exec("insert into " + test3 + " values(2, 'baz', 'joe')"));
219     }
220 }
221
222 void tst_QSqlTableModel::recreateTestTables()
223 {
224     dropTestTables();
225     createTestTables();
226     repopulateTestTables();
227 }
228
229 void tst_QSqlTableModel::generic_data(const QString &engine)
230 {
231     if ( dbs.fillTestTable(engine) == 0 ) {
232         if(engine.isEmpty())
233            QSKIP( "No database drivers are available in this Qt configuration", SkipAll );
234         else
235            QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration").arg(engine)).toLocal8Bit(), SkipAll );
236     }
237 }
238
239 void tst_QSqlTableModel::initTestCase()
240 {
241     recreateTestTables();
242 }
243
244 void tst_QSqlTableModel::cleanupTestCase()
245 {
246     dropTestTables();
247     dbs.close();
248 }
249
250 void tst_QSqlTableModel::init()
251 {
252 }
253
254 void tst_QSqlTableModel::cleanup()
255 {
256     repopulateTestTables();
257 }
258
259 void tst_QSqlTableModel::select()
260 {
261     QFETCH(QString, dbName);
262     QSqlDatabase db = QSqlDatabase::database(dbName);
263     CHECK_DATABASE(db);
264
265     QSqlTableModel model(0, db);
266     model.setTable(test);
267     model.setSort(0, Qt::AscendingOrder);
268     QVERIFY_SQL(model, select());
269
270     QCOMPARE(model.rowCount(), 3);
271     QCOMPARE(model.columnCount(), 3);
272
273     QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
274     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
275     QCOMPARE(model.data(model.index(0, 2)).toInt(), 1);
276     QCOMPARE(model.data(model.index(0, 3)), QVariant());
277
278     QCOMPARE(model.data(model.index(1, 0)).toInt(), 2);
279     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
280     QCOMPARE(model.data(model.index(1, 2)).toInt(), 2);
281     QCOMPARE(model.data(model.index(1, 3)), QVariant());
282
283     QCOMPARE(model.data(model.index(2, 0)).toInt(), 3);
284     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi"));
285     QCOMPARE(model.data(model.index(2, 2)).toInt(), 3);
286     QCOMPARE(model.data(model.index(2, 3)), QVariant());
287
288     QCOMPARE(model.data(model.index(3, 0)), QVariant());
289     QCOMPARE(model.data(model.index(3, 1)), QVariant());
290     QCOMPARE(model.data(model.index(3, 2)), QVariant());
291     QCOMPARE(model.data(model.index(3, 3)), QVariant());
292 }
293
294 void tst_QSqlTableModel::setRecord()
295 {
296     QFETCH(QString, dbName);
297     QSqlDatabase db = QSqlDatabase::database(dbName);
298     CHECK_DATABASE(db);
299
300     QList<QSqlTableModel::EditStrategy> policies = QList<QSqlTableModel::EditStrategy>() << QSqlTableModel::OnFieldChange << QSqlTableModel::OnRowChange << QSqlTableModel::OnManualSubmit;
301
302     QString Xsuffix;
303     foreach( QSqlTableModel::EditStrategy submitpolicy, policies) {
304
305         QSqlTableModel model(0, db);
306         model.setEditStrategy((QSqlTableModel::EditStrategy)submitpolicy);
307         model.setTable(test3);
308         model.setSort(0, Qt::AscendingOrder);
309         QVERIFY_SQL(model, select());
310
311         for (int i = 0; i < model.rowCount(); ++i) {
312             QSignalSpy spy(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
313
314             QSqlRecord rec = model.record(i);
315             rec.setValue(1, rec.value(1).toString() + 'X');
316             rec.setValue(2, rec.value(2).toString() + 'X');
317             QVERIFY(model.setRecord(i, rec));
318
319             if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnManualSubmit) {
320                 // setRecord should emit dataChanged() itself for manualSubmit
321                 QCOMPARE(spy.count(), 1);
322                 QCOMPARE(spy.at(0).count(), 2);
323                 QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(0)), model.index(i, 0));
324                 QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(1)), model.index(i, rec.count() - 1));
325                 QVERIFY(model.submitAll());
326             } else if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnRowChange && i == model.rowCount() -1)
327                 model.submit();
328             else {
329                 // dataChanged() is not emitted when submitAll() is called
330                 QCOMPARE(spy.count(), 2);
331                 QCOMPARE(spy.at(0).count(), 2);
332                 QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(0)), model.index(i, 1));
333                 QCOMPARE(qvariant_cast<QModelIndex>(spy.at(0).at(1)), model.index(i, 1));
334             }
335         }
336
337         Xsuffix.append('X');
338
339         QCOMPARE(model.data(model.index(0, 1)).toString(), QString("foo").append(Xsuffix));
340         QCOMPARE(model.data(model.index(0, 2)).toString(), QString("bar").append(Xsuffix));
341         QCOMPARE(model.data(model.index(1, 1)).toString(), QString("baz").append(Xsuffix));
342         QCOMPARE(model.data(model.index(1, 2)).toString(), QString("joe").append(Xsuffix));
343     }
344 }
345
346 void tst_QSqlTableModel::insertRow()
347 {
348     QFETCH(QString, dbName);
349     QSqlDatabase db = QSqlDatabase::database(dbName);
350     CHECK_DATABASE(db);
351
352     QSqlTableModel model(0, db);
353     model.setEditStrategy(QSqlTableModel::OnRowChange);
354     model.setTable(test);
355     model.setSort(0, Qt::AscendingOrder);
356     QVERIFY_SQL(model, select());
357
358     QVERIFY(model.insertRow(2));
359     QSqlRecord rec = model.record(1);
360     rec.setValue(0, 42);
361     rec.setValue(1, QString("vohi"));
362     QVERIFY(model.setRecord(2, rec));
363
364     QCOMPARE(model.data(model.index(2, 0)).toInt(), 42);
365     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi"));
366     QCOMPARE(model.data(model.index(2, 2)).toInt(), 2);
367
368     QVERIFY(model.submitAll());
369 }
370
371 void tst_QSqlTableModel::insertRecord()
372 {
373     QFETCH(QString, dbName);
374     QSqlDatabase db = QSqlDatabase::database(dbName);
375     CHECK_DATABASE(db);
376
377     QSqlTableModel model(0, db);
378     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
379     model.setTable(test);
380     model.setSort(0, Qt::AscendingOrder);
381     QVERIFY_SQL(model, select());
382
383     QSqlRecord rec = model.record();
384     rec.setValue(0, 42);
385     rec.setValue(1, QString("vohi"));
386     rec.setValue(2, 1);
387     QVERIFY(model.insertRecord(1, rec));
388     QCOMPARE(model.rowCount(), 4);
389
390     QCOMPARE(model.data(model.index(1, 0)).toInt(), 42);
391     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi"));
392     QCOMPARE(model.data(model.index(1, 2)).toInt(), 1);
393
394     model.revertAll();
395     model.setEditStrategy(QSqlTableModel::OnRowChange);
396
397     QVERIFY(model.insertRecord(-1, rec));
398
399     QCOMPARE(model.data(model.index(3, 0)).toInt(), 42);
400     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi"));
401     QCOMPARE(model.data(model.index(3, 2)).toInt(), 1);
402 }
403
404 void tst_QSqlTableModel::insertMultiRecords()
405 {
406     QFETCH(QString, dbName);
407     QSqlDatabase db = QSqlDatabase::database(dbName);
408     CHECK_DATABASE(db);
409
410     QSqlTableModel model(0, db);
411     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
412     model.setTable(test);
413     model.setSort(0, Qt::AscendingOrder);
414     QVERIFY_SQL(model, select());
415
416     QCOMPARE(model.rowCount(), 3);
417
418     QVERIFY(model.insertRow(2));
419
420     QCOMPARE(model.data(model.index(2, 0)), QVariant());
421     QCOMPARE(model.data(model.index(2, 1)), QVariant());
422     QCOMPARE(model.data(model.index(2, 2)), QVariant());
423
424     QVERIFY(model.insertRow(3));
425     QVERIFY(model.insertRow(0));
426
427     QCOMPARE(model.data(model.index(5, 0)).toInt(), 3);
428     QCOMPARE(model.data(model.index(5, 1)).toString(), QString("vohi"));
429     QCOMPARE(model.data(model.index(5, 2)).toInt(), 3);
430
431     QVERIFY(model.setData(model.index(0, 0), QVariant(42)));
432     QVERIFY(model.setData(model.index(3, 0), QVariant(43)));
433     QVERIFY(model.setData(model.index(4, 0), QVariant(44)));
434     QVERIFY(model.setData(model.index(4, 1), QVariant(QLatin1String("gunnar"))));
435     QVERIFY(model.setData(model.index(4, 2), QVariant(1)));
436
437     QVERIFY(model.submitAll());
438     model.clear();
439     model.setTable(test);
440     model.setSort(0, Qt::AscendingOrder);
441     QVERIFY_SQL(model, select());
442
443     QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
444     QCOMPARE(model.data(model.index(1, 0)).toInt(), 2);
445     QCOMPARE(model.data(model.index(2, 0)).toInt(), 3);
446     QCOMPARE(model.data(model.index(3, 0)).toInt(), 42);
447     QCOMPARE(model.data(model.index(4, 0)).toInt(), 43);
448     QCOMPARE(model.data(model.index(5, 0)).toInt(), 44);
449     QCOMPARE(model.data(model.index(5, 1)).toString(), QString("gunnar"));
450     QCOMPARE(model.data(model.index(5, 2)).toInt(), 1);
451 }
452
453 void tst_QSqlTableModel::submitAll()
454 {
455     QFETCH(QString, dbName);
456     QSqlDatabase db = QSqlDatabase::database(dbName);
457     CHECK_DATABASE(db);
458
459     QSqlTableModel model(0, db);
460     model.setTable(test);
461     model.setSort(0, Qt::AscendingOrder);
462     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
463     QVERIFY_SQL(model, select());
464
465     QVERIFY(model.setData(model.index(0, 1), "harry2", Qt::EditRole));
466     QVERIFY(model.setData(model.index(1, 1), "trond2", Qt::EditRole));
467
468     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry2"));
469     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond2"));
470
471     QVERIFY_SQL(model, submitAll());
472
473     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry2"));
474     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond2"));
475
476     QVERIFY(model.setData(model.index(0, 1), "harry", Qt::EditRole));
477     QVERIFY(model.setData(model.index(1, 1), "trond", Qt::EditRole));
478
479     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
480     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
481
482     QVERIFY_SQL(model, submitAll());
483
484     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
485     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
486 }
487
488 void tst_QSqlTableModel::removeRow()
489 {
490     QFETCH(QString, dbName);
491     QSqlDatabase db = QSqlDatabase::database(dbName);
492     CHECK_DATABASE(db);
493
494     QSqlTableModel model(0, db);
495     model.setTable(test);
496     model.setSort(0, Qt::AscendingOrder);
497     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
498     QVERIFY_SQL(model, select());
499     QCOMPARE(model.rowCount(), 3);
500
501     // headerDataChanged must be emitted by the model when the edit strategy is OnManualSubmit,
502     // when OnFieldChange or OnRowChange it's not needed because the model will re-select.
503     qRegisterMetaType<Qt::Orientation>("Qt::Orientation");
504     QSignalSpy headerDataChangedSpy(&model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)));
505
506     QVERIFY(model.removeRow(1));
507     QCOMPARE(headerDataChangedSpy.count(), 1);
508     QCOMPARE(*static_cast<const Qt::Orientation *>(headerDataChangedSpy.at(0).value(0).constData()), Qt::Vertical);
509     QCOMPARE(headerDataChangedSpy.at(0).at(1).toInt(), 1);
510     QCOMPARE(headerDataChangedSpy.at(0).at(2).toInt(), 1);
511     QVERIFY(model.submitAll());
512     QCOMPARE(model.rowCount(), 2);
513
514     QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
515     QCOMPARE(model.data(model.index(1, 0)).toInt(), 3);
516     model.clear();
517
518     recreateTestTables();
519
520     model.setTable(test);
521     model.setEditStrategy(QSqlTableModel::OnRowChange);
522     QVERIFY_SQL(model, select());
523     QCOMPARE(model.rowCount(), 3);
524
525     headerDataChangedSpy.clear();
526     QVERIFY(model.removeRow(1));
527     QCOMPARE(headerDataChangedSpy.count(), 0);
528     QCOMPARE(model.rowCount(), 2);
529
530     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
531     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi"));
532 }
533
534 void tst_QSqlTableModel::removeRows()
535 {
536     QFETCH(QString, dbName);
537     QSqlDatabase db = QSqlDatabase::database(dbName);
538     CHECK_DATABASE(db);
539
540     QSqlTableModel model(0, db);
541     model.setTable(test);
542     model.setSort(0, Qt::AscendingOrder);
543     model.setEditStrategy(QSqlTableModel::OnFieldChange);
544     QVERIFY_SQL(model, select());
545     QCOMPARE(model.rowCount(), 3);
546
547     QSignalSpy beforeDeleteSpy(&model, SIGNAL(beforeDelete(int)));
548
549     // Make sure wrong stuff is ok
550     QVERIFY(!model.removeRows(-1,1)); // negative start
551     QVERIFY(!model.removeRows(-1, 0)); // negative start, and zero count
552     QVERIFY(!model.removeRows(1, 0)); // zero count
553     QVERIFY(!model.removeRows(5, 1)); // past end (causes a beforeDelete to be emitted)
554     QVERIFY(!model.removeRows(1, 0, model.index(2, 0))); // can't pass a valid modelindex
555
556     QVERIFY_SQL(model, removeRows(0, 2));
557     QCOMPARE(beforeDeleteSpy.count(), 3);
558     QVERIFY(beforeDeleteSpy.at(0).at(0).toInt() == 5);
559     QVERIFY(beforeDeleteSpy.at(1).at(0).toInt() == 0);
560     QVERIFY(beforeDeleteSpy.at(2).at(0).toInt() == 1);
561     QCOMPARE(model.rowCount(), 1);
562     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("vohi"));
563     model.clear();
564
565     recreateTestTables();
566     model.setTable(test);
567     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
568     QVERIFY_SQL(model, select());
569     QCOMPARE(model.rowCount(), 3);
570     beforeDeleteSpy.clear();
571
572     // When the edit strategy is OnManualSubmit the beforeDelete() signal
573     // isn't emitted until submitAll() is called.
574
575     QVERIFY(!model.removeRows(-1,1)); // negative start
576     QVERIFY(!model.removeRows(-1, 0)); // negative start, and zero count
577     QVERIFY(!model.removeRows(1, 0)); // zero count
578     QVERIFY(!model.removeRows(5, 1)); // past end (DOESN'T cause a beforeDelete to be emitted)
579     QVERIFY(!model.removeRows(1, 0, model.index(2, 0))); // can't pass a valid modelindex
580
581     qRegisterMetaType<Qt::Orientation>("Qt::Orientation");
582     QSignalSpy headerDataChangedSpy(&model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)));
583     QVERIFY(model.removeRows(0, 2, QModelIndex()));
584     QCOMPARE(headerDataChangedSpy.count(), 2);
585     QCOMPARE(headerDataChangedSpy.at(0).at(1).toInt(), 0);
586     QCOMPARE(headerDataChangedSpy.at(0).at(2).toInt(), 0);
587     QCOMPARE(headerDataChangedSpy.at(1).at(1).toInt(), 1);
588     QCOMPARE(headerDataChangedSpy.at(1).at(2).toInt(), 1);
589     QCOMPARE(model.rowCount(), 3);
590     QVERIFY(beforeDeleteSpy.count() == 0);
591     QVERIFY(model.submitAll());
592     QVERIFY(beforeDeleteSpy.count() == 2);
593     QVERIFY(beforeDeleteSpy.at(0).at(0).toInt() == 0);
594     QVERIFY(beforeDeleteSpy.at(1).at(0).toInt() == 1);
595     QCOMPARE(model.rowCount(), 1);
596     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("vohi"));
597 }
598
599 void tst_QSqlTableModel::removeInsertedRow()
600 {
601     QFETCH(QString, dbName);
602     QFETCH(int, submitpolicy_i);
603     QSqlTableModel::EditStrategy submitpolicy = (QSqlTableModel::EditStrategy) submitpolicy_i;
604     QSqlDatabase db = QSqlDatabase::database(dbName);
605     CHECK_DATABASE(db);
606
607     QSqlTableModel model(0, db);
608     model.setTable(test);
609     model.setSort(0, Qt::AscendingOrder);
610
611     model.setEditStrategy(submitpolicy);
612     QVERIFY_SQL(model, select());
613     QCOMPARE(model.rowCount(), 3);
614
615     QVERIFY(model.insertRow(1));
616     QCOMPARE(model.rowCount(), 4);
617
618     QVERIFY(model.removeRow(1));
619     QCOMPARE(model.rowCount(), 3);
620
621     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
622     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
623     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi"));
624 }
625
626 void tst_QSqlTableModel::removeInsertedRows()
627 {
628     QFETCH(QString, dbName);
629     QSqlDatabase db = QSqlDatabase::database(dbName);
630     CHECK_DATABASE(db);
631
632     QSqlTableModel model(0, db);
633     model.setTable(test);
634     model.setSort(0, Qt::AscendingOrder);
635     model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise
636     QVERIFY_SQL(model, select());
637     QCOMPARE(model.rowCount(), 3);
638
639     // First put two empty rows, and remove them one by one
640     QVERIFY(model.insertRows(1, 2));
641     QCOMPARE(model.rowCount(), 5);
642     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
643     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
644     QCOMPARE(model.data(model.index(2, 1)).toString(), QString());
645     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond"));
646     QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi"));
647
648     QVERIFY(model.removeRow(1));
649     QCOMPARE(model.rowCount(), 4);
650
651     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
652     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
653     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("trond"));
654     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi"));
655
656     QVERIFY(model.removeRow(1));
657     QCOMPARE(model.rowCount(), 3);
658     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
659     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
660     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi"));
661
662     // Now put two empty rows, and remove them all at once
663     QVERIFY(model.insertRows(1, 2));
664     QCOMPARE(model.rowCount(), 5);
665     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
666     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
667     QCOMPARE(model.data(model.index(2, 1)).toString(), QString());
668     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond"));
669     QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi"));
670
671     QVERIFY(model.removeRows(1, 2));
672     QCOMPARE(model.rowCount(), 3);
673     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
674     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond"));
675     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi"));
676
677
678     // Now put two empty rows, and remove one good and two empty
679     QVERIFY(model.insertRows(1, 2));
680     QCOMPARE(model.rowCount(), 5);
681     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
682     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
683     QCOMPARE(model.data(model.index(2, 1)).toString(), QString());
684     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond"));
685     QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi"));
686
687     QVERIFY(model.removeRows(0, 3));
688     QVERIFY(model.submitAll()); // otherwise the remove of the real row doesn't work
689
690     QCOMPARE(model.rowCount(), 2);
691     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("trond"));
692     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi"));
693
694     // Reset back again
695     model.clear();
696     recreateTestTables();
697     model.setTable(test);
698     model.setSort(0, Qt::AscendingOrder);
699     model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise
700     QVERIFY_SQL(model, select());
701     QCOMPARE(model.rowCount(), 3);
702
703     // Now two empty and one good
704     QVERIFY(model.insertRows(1, 2));
705     QCOMPARE(model.rowCount(), 5);
706     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
707     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
708     QCOMPARE(model.data(model.index(2, 1)).toString(), QString());
709     QCOMPARE(model.data(model.index(3, 1)).toString(), QString("trond"));
710     QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi"));
711
712     QVERIFY(model.removeRows(1, 3));
713     QVERIFY(model.submitAll());
714     QCOMPARE(model.rowCount(), 2);
715     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
716     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi"));
717
718     // Reset back again
719     model.clear();
720     recreateTestTables();
721     model.setTable(test);
722     model.setSort(0, Qt::AscendingOrder);
723     model.setEditStrategy(QSqlTableModel::OnManualSubmit); // you can't insert more than one row otherwise
724     QVERIFY_SQL(model, select());
725     QCOMPARE(model.rowCount(), 3);
726
727     // one empty, one good, one empty
728     QVERIFY(model.insertRows(1, 1));
729     QVERIFY(model.insertRows(3, 1));
730     QCOMPARE(model.rowCount(), 5);
731     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
732     QCOMPARE(model.data(model.index(1, 1)).toString(), QString());
733     QCOMPARE(model.data(model.index(2, 1)).toString(), QString("trond"));
734     QCOMPARE(model.data(model.index(3, 1)).toString(), QString());
735     QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi"));
736
737     QVERIFY(model.removeRows(1, 3));
738     QVERIFY(model.submitAll());
739     QCOMPARE(model.rowCount(), 2);
740     QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry"));
741     QCOMPARE(model.data(model.index(1, 1)).toString(), QString("vohi"));
742 }
743
744 void tst_QSqlTableModel::emptyTable()
745 {
746     QFETCH(QString, dbName);
747     QSqlDatabase db = QSqlDatabase::database(dbName);
748     CHECK_DATABASE(db);
749
750     QSqlTableModel model(0, db);
751     QCOMPARE(model.rowCount(), 0);
752     QCOMPARE(model.columnCount(), 0);
753
754     model.setTable(qTableName("emptytable", __FILE__));
755     QCOMPARE(model.rowCount(), 0);
756     QCOMPARE(model.columnCount(), 1);
757
758     QVERIFY_SQL(model, select());
759     QCOMPARE(model.rowCount(), 0);
760     QCOMPARE(model.columnCount(), 1);
761 }
762
763 void tst_QSqlTableModel::tablesAndSchemas()
764 {
765     QFETCH(QString, dbName);
766     QSqlDatabase db = QSqlDatabase::database(dbName);
767     CHECK_DATABASE(db);
768
769     QSqlQuery q(db);
770     q.exec("DROP SCHEMA " + qTableName("testschema", __FILE__) + " CASCADE");
771     QVERIFY_SQL( q, exec("create schema " + qTableName("testschema", __FILE__)));
772     QString tableName = qTableName("testschema", __FILE__) + '.' + qTableName("testtable", __FILE__);
773     QVERIFY_SQL( q, exec("create table " + tableName + "(id int)"));
774     QVERIFY_SQL( q, exec("insert into " + tableName + " values(1)"));
775     QVERIFY_SQL( q, exec("insert into " + tableName + " values(2)"));
776
777     QSqlTableModel model(0, db);
778     model.setTable(tableName);
779     QVERIFY_SQL(model, select());
780     QCOMPARE(model.rowCount(), 2);
781     QCOMPARE(model.columnCount(), 1);
782 }
783
784 void tst_QSqlTableModel::whitespaceInIdentifiers()
785 {
786     QFETCH(QString, dbName);
787     QSqlDatabase db = QSqlDatabase::database(dbName);
788     CHECK_DATABASE(db);
789
790     if (!testWhiteSpaceNames(db.driverName()))
791         QSKIP("DBMS doesn't support whitespaces in identifiers", SkipSingle);
792
793     QString tableName = qTableName("qtestw hitespace", db.driver());
794
795     QSqlTableModel model(0, db);
796     model.setTable(tableName);
797     QVERIFY_SQL(model, select());
798 }
799
800 void tst_QSqlTableModel::primaryKeyOrder()
801 {
802     QFETCH(QString, dbName);
803     QSqlDatabase db = QSqlDatabase::database(dbName);
804     CHECK_DATABASE(db);
805
806     QSqlQuery q(db);
807
808     if(tst_Databases::isPostgreSQL(db))
809         QVERIFY_SQL( q, exec("set client_min_messages='warning'"));
810
811     QVERIFY_SQL( q, exec("create table "+qTableName("foo", __FILE__)+"(a varchar(20), id int not null primary key, b varchar(20))"));
812
813     QSqlTableModel model(0, db);
814     model.setTable(qTableName("foo", __FILE__));
815
816     QSqlIndex pk = model.primaryKey();
817     QCOMPARE(pk.count(), 1);
818     QCOMPARE(pk.fieldName(0), QLatin1String("id"));
819
820     QVERIFY(model.insertRow(0));
821     QVERIFY(model.setData(model.index(0, 0), "hello"));
822     QVERIFY(model.setData(model.index(0, 1), 42));
823     QVERIFY(model.setData(model.index(0, 2), "blah"));
824     QVERIFY_SQL(model, submitAll());
825
826     QVERIFY(model.setData(model.index(0, 1), 43));
827     QVERIFY_SQL(model, submitAll());
828
829     QCOMPARE(model.data(model.index(0, 1)).toInt(), 43);
830 }
831
832 void tst_QSqlTableModel::setInvalidFilter()
833 {
834     QFETCH(QString, dbName);
835     QSqlDatabase db = QSqlDatabase::database(dbName);
836     CHECK_DATABASE(db);
837
838     // set an invalid filter, make sure it fails
839     QSqlTableModel model(0, db);
840     model.setTable(test);
841     model.setFilter("blahfahsel");
842
843     QCOMPARE(model.filter(), QString("blahfahsel"));
844     QVERIFY(!model.select());
845
846     // set a valid filter later, make sure if passes
847     model.setFilter("id = 1");
848     QVERIFY_SQL(model, select());
849 }
850
851 void tst_QSqlTableModel::setFilter()
852 {
853     QFETCH(QString, dbName);
854     QSqlDatabase db = QSqlDatabase::database(dbName);
855     CHECK_DATABASE(db);
856
857     QSqlTableModel model(0, db);
858     model.setTable(test);
859     model.setFilter("id = 1");
860     QCOMPARE(model.filter(), QString("id = 1"));
861     QVERIFY_SQL(model, select());
862
863     QCOMPARE(model.rowCount(), 1);
864     QCOMPARE(model.data(model.index(0, 0)).toInt(), 1);
865
866     QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
867     QSignalSpy rowsAboutToBeRemovedSpy(&model,
868             SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
869     QSignalSpy rowsInsertedSpy(&model, SIGNAL(rowsInserted(QModelIndex,int,int)));
870     QSignalSpy rowsAboutToBeInsertedSpy(&model,
871             SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
872     model.setFilter("id = 2");
873
874     // check the signals
875     QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1);
876     QCOMPARE(rowsRemovedSpy.count(), 1);
877     QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1);
878     QCOMPARE(rowsInsertedSpy.count(), 1);
879     QList<QVariant> args = rowsAboutToBeRemovedSpy.takeFirst();
880     QCOMPARE(args.count(), 3);
881     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), QModelIndex());
882     QCOMPARE(args.at(1).toInt(), 0);
883     QCOMPARE(args.at(2).toInt(), 0);
884     args = rowsRemovedSpy.takeFirst();
885     QCOMPARE(args.count(), 3);
886     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), QModelIndex());
887     QCOMPARE(args.at(1).toInt(), 0);
888     QCOMPARE(args.at(2).toInt(), 0);
889     args = rowsInsertedSpy.takeFirst();
890     QCOMPARE(args.count(), 3);
891     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), QModelIndex());
892     QCOMPARE(args.at(1).toInt(), 0);
893     QCOMPARE(args.at(2).toInt(), 0);
894     args = rowsAboutToBeInsertedSpy.takeFirst();
895     QCOMPARE(args.count(), 3);
896     QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), QModelIndex());
897     QCOMPARE(args.at(1).toInt(), 0);
898     QCOMPARE(args.at(2).toInt(), 0);
899
900     QCOMPARE(model.rowCount(), 1);
901     QCOMPARE(model.data(model.index(0, 0)).toInt(), 2);
902 }
903
904 void tst_QSqlTableModel::sqlite_bigTable()
905 {
906     QFETCH(QString, dbName);
907     QSqlDatabase db = QSqlDatabase::database(dbName);
908     CHECK_DATABASE(db);
909     const QString bigtable(qTableName("bigtable", __FILE__));
910
911     bool hasTransactions = db.driver()->hasFeature(QSqlDriver::Transactions);
912     if (hasTransactions) QVERIFY(db.transaction());
913     QSqlQuery q(db);
914     QVERIFY_SQL( q, exec("create table "+bigtable+"(id int primary key, name varchar)"));
915     QVERIFY_SQL( q, prepare("insert into "+bigtable+"(id, name) values (?, ?)"));
916     QTime startTime;
917     startTime.start();
918     for (int i = 0; i < 10000; ++i) {
919         q.addBindValue(i);
920         q.addBindValue(QString::number(i));
921         if(i%1000 == 0 && startTime.elapsed() > 5000)
922             qDebug() << i << "records written";
923         QVERIFY_SQL( q, exec());
924     }
925     q.clear();
926     if (hasTransactions) QVERIFY(db.commit());
927
928     QSqlTableModel model(0, db);
929     model.setTable(bigtable);
930     QVERIFY_SQL(model, select());
931
932     QSqlRecord rec = model.record();
933     rec.setValue("id", 424242);
934     rec.setValue("name", "Guillaume");
935     QVERIFY_SQL(model, insertRecord(-1, rec));
936
937     model.clear();
938 }
939
940 // For task 118547: couldn't insert records unless select()
941 // had first been called.
942 void tst_QSqlTableModel::insertRecordBeforeSelect()
943 {
944     QFETCH(QString, dbName);
945     QSqlDatabase db = QSqlDatabase::database(dbName);
946     CHECK_DATABASE(db);
947
948     QSqlTableModel model(0, db);
949     model.setTable(test);
950     QCOMPARE(model.lastError().type(), QSqlError::NoError);
951
952     QSqlRecord buffer = model.record();
953     buffer.setValue("id", 13);
954     buffer.setValue("name", QString("The Lion King"));
955     buffer.setValue("title", 0);
956     QVERIFY_SQL(model, insertRecord(-1, buffer));
957
958     buffer.setValue("id", 26);
959     buffer.setValue("name", QString("T. Leary"));
960     buffer.setValue("title", 0);
961     QVERIFY_SQL(model, insertRecord(1, buffer));
962
963     int rowCount = model.rowCount();
964     model.clear();
965     QCOMPARE(model.rowCount(), 0);
966
967     QSqlTableModel model2(0, db);
968     model2.setTable(test);
969     QVERIFY_SQL(model2, select());
970     QCOMPARE(model2.rowCount(), rowCount);
971 }
972
973 // For task 118547: set errors if table doesn't exist and if records
974 // are inserted and submitted on a non-existing table.
975 void tst_QSqlTableModel::submitAllOnInvalidTable()
976 {
977     QFETCH(QString, dbName);
978     QSqlDatabase db = QSqlDatabase::database(dbName);
979     CHECK_DATABASE(db);
980
981     QSqlTableModel model(0, db);
982     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
983
984     // setTable returns a void, so the error can only be caught by
985     // manually checking lastError(). ### Qt5: This should be changed!
986     model.setTable(qTableName("invalidTable", __FILE__));
987     QCOMPARE(model.lastError().type(), QSqlError::StatementError);
988
989     // This will give us an empty record which is expected behavior
990     QSqlRecord buffer = model.record();
991     buffer.setValue("bogus", 1000);
992     buffer.setValue("bogus2", QString("I will go nowhere!"));
993
994     // Inserting the record into the *model* will work (OnManualSubmit)
995     QVERIFY_SQL(model, insertRecord(-1, buffer));
996
997     // The submit and select shall fail because the table doesn't exist
998     QEXPECT_FAIL("", "The table doesn't exist: submitAll() shall fail",
999         Continue);
1000     QVERIFY_SQL(model, submitAll());
1001     QEXPECT_FAIL("", "The table doesn't exist: select() shall fail",
1002         Continue);
1003     QVERIFY_SQL(model, select());
1004 }
1005
1006 // For task 147575: the rowsRemoved signal emitted from the model was lying
1007 void tst_QSqlTableModel::insertRecordsInLoop()
1008 {
1009     QFETCH(QString, dbName);
1010     QSqlDatabase db = QSqlDatabase::database(dbName);
1011     CHECK_DATABASE(db);
1012
1013     QSqlTableModel model(0, db);
1014     model.setTable(test);
1015     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
1016     model.select();
1017
1018     QSqlRecord record = model.record();
1019     record.setValue(0, 10);
1020     record.setValue(1, "Testman");
1021     record.setValue(2, 1);
1022
1023     QSignalSpy spyRowsRemoved(&model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
1024     QSignalSpy spyRowsInserted(&model, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
1025     for (int i = 0; i < 10; i++) {
1026         QVERIFY(model.insertRecord(model.rowCount(), record));
1027         QCOMPARE(spyRowsInserted.at(i).at(1).toInt(), i+3); // The table already contains three rows
1028         QCOMPARE(spyRowsInserted.at(i).at(2).toInt(), i+3);
1029     }
1030     model.submitAll(); // submitAll() calls select() which clears and repopulates the table
1031
1032     int firstRowIndex = 0, lastRowIndex = 12;
1033     QCOMPARE(spyRowsRemoved.count(), 1);
1034     QCOMPARE(spyRowsRemoved.at(0).at(1).toInt(), firstRowIndex);
1035     QCOMPARE(spyRowsRemoved.at(0).at(2).toInt(), lastRowIndex);
1036
1037     QCOMPARE(spyRowsInserted.at(10).at(1).toInt(), firstRowIndex);
1038     QCOMPARE(spyRowsInserted.at(10).at(2).toInt(), lastRowIndex);
1039     QCOMPARE(spyRowsInserted.count(), 11);
1040
1041     QCOMPARE(model.rowCount(), 13);
1042     QCOMPARE(model.columnCount(), 3);
1043 }
1044
1045 void tst_QSqlTableModel::sqlite_attachedDatabase()
1046 {
1047     QFETCH(QString, dbName);
1048     QSqlDatabase db = QSqlDatabase::database(dbName);
1049     CHECK_DATABASE(db);
1050     if(db.databaseName() == ":memory:")
1051         QSKIP(":memory: database, skipping test", SkipSingle);
1052
1053     QSqlDatabase attachedDb = QSqlDatabase::cloneDatabase(db, db.driverName() + QLatin1String("attached"));
1054     attachedDb.setDatabaseName(db.databaseName()+QLatin1String("attached.dat"));
1055     QVERIFY_SQL(attachedDb, open());
1056     QSqlQuery q(attachedDb);
1057     tst_Databases::safeDropTables(attachedDb, QStringList() << "atest" << "atest2");
1058     QVERIFY_SQL( q, exec("CREATE TABLE atest(id int, text varchar(20))"));
1059     QVERIFY_SQL( q, exec("CREATE TABLE atest2(id int, text varchar(20))"));
1060     QVERIFY_SQL( q, exec("INSERT INTO atest VALUES(1, 'attached-atest')"));
1061     QVERIFY_SQL( q, exec("INSERT INTO atest2 VALUES(2, 'attached-atest2')"));
1062
1063     QSqlQuery q2(db);
1064     tst_Databases::safeDropTable(db, "atest");
1065     QVERIFY_SQL(q2, exec("CREATE TABLE atest(id int, text varchar(20))"));
1066     QVERIFY_SQL(q2, exec("INSERT INTO atest VALUES(3, 'main')"));
1067     QVERIFY_SQL(q2, exec("ATTACH DATABASE \""+attachedDb.databaseName()+"\" as adb"));
1068
1069     // This should query the table in the attached database (schema supplied)
1070     QSqlTableModel model(0, db);
1071     model.setTable("adb.atest");
1072     QVERIFY_SQL(model, select());
1073     QCOMPARE(model.rowCount(), 1);
1074     QCOMPARE(model.data(model.index(0, 0), Qt::DisplayRole).toInt(), 1);
1075     QCOMPARE(model.data(model.index(0, 1), Qt::DisplayRole).toString(), QLatin1String("attached-atest"));
1076
1077     // This should query the table in the attached database (unique tablename)
1078     model.setTable("atest2");
1079     QVERIFY_SQL(model, select());
1080     QCOMPARE(model.rowCount(), 1);
1081     QCOMPARE(model.data(model.index(0, 0), Qt::DisplayRole).toInt(), 2);
1082     QCOMPARE(model.data(model.index(0, 1), Qt::DisplayRole).toString(), QLatin1String("attached-atest2"));
1083
1084     // This should query the table in the main database (tables in main db has 1st priority)
1085     model.setTable("atest");
1086     QVERIFY_SQL(model, select());
1087     QCOMPARE(model.rowCount(), 1);
1088     QCOMPARE(model.data(model.index(0, 0), Qt::DisplayRole).toInt(), 3);
1089     QCOMPARE(model.data(model.index(0, 1), Qt::DisplayRole).toString(), QLatin1String("main"));
1090 }
1091
1092
1093 void tst_QSqlTableModel::tableModifyWithBlank()
1094 {
1095     QFETCH(QString, dbName);
1096     QSqlDatabase db = QSqlDatabase::database(dbName);
1097     CHECK_DATABASE(db);
1098
1099     QSqlTableModel model(0, db);
1100     model.setTable(qTableName("test4", __FILE__));
1101     model.select();
1102
1103     //generate a time stamp for the test. Add one second to the current time to make sure
1104     //it is different than the QSqlQuery test.
1105     QString timeString=QDateTime::currentDateTime().addSecs(1).toString(Qt::ISODate);
1106
1107     //insert a new row, with column0 being the timestamp.
1108     //Should be equivalent to QSqlQuery INSERT INTO... command)
1109     QVERIFY_SQL(model, insertRow(0));
1110     QVERIFY_SQL(model, setData(model.index(0,0),timeString));
1111     QVERIFY_SQL(model, submitAll());
1112
1113     //set a filter on the table so the only record we get is the one we just made
1114     //I could just do another setData command, but I want to make sure the TableModel
1115     //matches exactly what is stored in the database
1116     model.setFilter("column1='"+timeString+"'"); //filter to get just the newly entered row
1117     QVERIFY_SQL(model, select());
1118
1119     //Make sure we only get one record, and that it is the one we just made
1120     QCOMPARE(model.rowCount(), 1); //verify only one entry
1121     QCOMPARE(model.record(0).value(0).toString(), timeString); //verify correct record
1122
1123     //At this point we know that the intial value (timestamp) was succsefully stored in the database
1124     //Attempt to modify the data in the new record
1125     //equivalent to query.exec("update test set column3="... command in direct test
1126     //set the data in the first column to "col1ModelData"
1127     QVERIFY_SQL(model, setData(model.index(0,1), "col1ModelData"));
1128
1129     //do a quick check to make sure that the setData command properly set the value in the model
1130     QCOMPARE(model.record(0).value(1).toString(), QLatin1String("col1ModelData"));
1131
1132     //submit the changed data to the database
1133     //This is where I have been getting errors.
1134     QVERIFY_SQL(model, submitAll());
1135
1136     //make sure the model has the most current data for our record
1137     QVERIFY_SQL(model, select());
1138
1139     //verify that our new record was the only record returned
1140     QCOMPARE(model.rowCount(), 1);
1141
1142     //And that the record returned is, in fact, our test record.
1143     QCOMPARE(model.record(0).value(0).toString(), timeString);
1144
1145     //Make sure the value of the first column matches what we set it to previously.
1146     QCOMPARE(model.record(0).value(1).toString(), QLatin1String("col1ModelData"));
1147 }
1148
1149 void tst_QSqlTableModel::removeColumnAndRow()
1150 {
1151     QFETCH(QString, dbName);
1152     QSqlDatabase db = QSqlDatabase::database(dbName);
1153     CHECK_DATABASE(db);
1154
1155     QSqlTableModel model(0, db);
1156     model.setTable(test);
1157     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
1158     QVERIFY_SQL(model, select());
1159     QCOMPARE(model.rowCount(), 3);
1160     QCOMPARE(model.columnCount(), 3);
1161
1162     QVERIFY(model.removeColumn(0));
1163     QVERIFY(model.removeRow(0));
1164     QVERIFY(model.submitAll());
1165     QCOMPARE(model.rowCount(), 2);
1166     QCOMPARE(model.columnCount(), 2);
1167
1168     // check with another table because the model has been modified
1169     // but not the sql table
1170     QSqlTableModel model2(0, db);
1171     model2.setTable(test);
1172     QVERIFY_SQL(model2, select());
1173     QCOMPARE(model2.rowCount(), 2);
1174     QCOMPARE(model2.columnCount(), 3);
1175 }
1176
1177 void tst_QSqlTableModel::insertBeforeDelete()
1178 {
1179     QFETCH(QString, dbName);
1180     QSqlDatabase db = QSqlDatabase::database(dbName);
1181     CHECK_DATABASE(db);
1182
1183     QSqlQuery q(db);
1184     QVERIFY_SQL( q, exec("insert into " + test + " values(9, 'andrew', 9)"));
1185     QVERIFY_SQL( q, exec("insert into " + test + " values(10, 'justin', 10)"));
1186
1187     QSqlTableModel model(0, db);
1188     model.setTable(test);
1189     model.setEditStrategy(QSqlTableModel::OnManualSubmit);
1190     QVERIFY_SQL(model, select());
1191
1192     QSqlRecord rec = model.record();
1193     rec.setValue(0, 4);
1194     rec.setValue(1, QString("bill"));
1195     rec.setValue(2, 4);
1196     QVERIFY_SQL(model, insertRecord(4, rec));
1197
1198     QVERIFY_SQL(model, removeRow(5));
1199     QVERIFY_SQL(model, submitAll());
1200     QCOMPARE(model.rowCount(), 5);
1201 }
1202
1203 QTEST_MAIN(tst_QSqlTableModel)
1204 #include "tst_qsqltablemodel.moc"