1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsqltablemodel.h"
5
6#include "qsqldriver.h"
7#include "qsqlerror.h"
8#include "qsqlfield.h"
9#include "qsqlindex.h"
10#include "qsqlquery.h"
11#include "qsqlrecord.h"
12#include "qsqlresult.h"
13
14#include "qsqltablemodel_p.h"
15
16#include <qdebug.h>
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22using SqlTm = QSqlTableModelSql;
23
24QSqlTableModelPrivate::~QSqlTableModelPrivate()
25{
26
27}
28
29/*! \internal
30 Populates our record with values.
31*/
32QSqlRecord QSqlTableModelPrivate::record(const QList<QVariant> &values) const
33{
34 QSqlRecord r = rec;
35 for (int i = 0; i < r.count() && i < values.size(); ++i)
36 r.setValue(i, val: values.at(i));
37 return r;
38}
39
40int QSqlTableModelPrivate::nameToIndex(const QString &name) const
41{
42 return rec.indexOf(name: strippedFieldName(name));
43}
44
45QString QSqlTableModelPrivate::strippedFieldName(const QString &name) const
46{
47 QString fieldname = name;
48 if (db.driver()->isIdentifierEscaped(identifier: fieldname, type: QSqlDriver::FieldName))
49 fieldname = db.driver()->stripDelimiters(identifier: fieldname, type: QSqlDriver::FieldName);
50 return fieldname;
51}
52
53int QSqlTableModelPrivate::insertCount(int maxRow) const
54{
55 int cnt = 0;
56 CacheMap::ConstIterator i = cache.constBegin();
57 const CacheMap::ConstIterator e = cache.constEnd();
58 for ( ; i != e && (maxRow < 0 || i.key() <= maxRow); ++i)
59 if (i.value().insert())
60 ++cnt;
61
62 return cnt;
63}
64
65void QSqlTableModelPrivate::initRecordAndPrimaryIndex()
66{
67 rec = db.record(tablename: tableName);
68 primaryIndex = db.primaryIndex(tablename: tableName);
69 initColOffsets(size: rec.count());
70}
71
72void QSqlTableModelPrivate::clear()
73{
74 sortColumn = -1;
75 sortOrder = Qt::AscendingOrder;
76 tableName.clear();
77 editQuery.clear();
78 cache.clear();
79 primaryIndex.clear();
80 rec.clear();
81 filter.clear();
82}
83
84void QSqlTableModelPrivate::clearCache()
85{
86 cache.clear();
87}
88
89void QSqlTableModelPrivate::revertCachedRow(int row)
90{
91 Q_Q(QSqlTableModel);
92 ModifiedRow r = cache.value(key: row);
93
94 switch (r.op()) {
95 case QSqlTableModelPrivate::None:
96 Q_ASSERT_X(false, "QSqlTableModelPrivate::revertCachedRow()", "Invalid entry in cache map");
97 return;
98 case QSqlTableModelPrivate::Update:
99 case QSqlTableModelPrivate::Delete:
100 if (!r.submitted()) {
101 cache[row].revert();
102 emit q->dataChanged(topLeft: q->createIndex(arow: row, acolumn: 0),
103 bottomRight: q->createIndex(arow: row, acolumn: q->columnCount() - 1));
104 }
105 break;
106 case QSqlTableModelPrivate::Insert: {
107 QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = cache.find(key: row);
108 if (it == cache.end())
109 return;
110 q->beginRemoveRows(parent: QModelIndex(), first: row, last: row);
111 it = cache.erase(it);
112 while (it != cache.end()) {
113 int oldKey = it.key();
114 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
115 cache.erase(it);
116 it = cache.insert(key: oldKey - 1, value: oldValue);
117 ++it;
118 }
119 q->endRemoveRows();
120 break; }
121 }
122}
123
124bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
125 const QSqlRecord &rec, const QSqlRecord &whereValues)
126{
127 if (stmt.isEmpty())
128 return false;
129
130 // lazy initialization of editQuery
131 if (editQuery.driver() != db.driver())
132 editQuery = QSqlQuery(db);
133
134 // workaround for In-Process databases - remove all read locks
135 // from the table to make sure the editQuery succeeds
136 if (db.driver()->hasFeature(f: QSqlDriver::SimpleLocking))
137 const_cast<QSqlResult *>(query.result())->detachFromResultSet();
138
139 if (prepStatement) {
140 if (editQuery.lastQuery() != stmt) {
141 if (!editQuery.prepare(query: stmt)) {
142 error = editQuery.lastError();
143 return false;
144 }
145 }
146 int i;
147 for (i = 0; i < rec.count(); ++i)
148 if (rec.isGenerated(i))
149 editQuery.addBindValue(val: rec.value(i));
150 for (i = 0; i < whereValues.count(); ++i)
151 if (whereValues.isGenerated(i) && !whereValues.isNull(i))
152 editQuery.addBindValue(val: whereValues.value(i));
153
154 if (!editQuery.exec()) {
155 error = editQuery.lastError();
156 return false;
157 }
158 } else {
159 if (!editQuery.exec(query: stmt)) {
160 error = editQuery.lastError();
161 return false;
162 }
163 }
164 return true;
165}
166
167/*!
168 \class QSqlTableModel
169 \brief The QSqlTableModel class provides an editable data model
170 for a single database table.
171
172 \ingroup database
173 \inmodule QtSql
174
175 QSqlTableModel is a high-level interface for reading and writing
176 database records from a single table. It is built on top of the
177 lower-level QSqlQuery and can be used to provide data to view
178 classes such as QTableView. For example:
179
180 \snippet sqldatabase/sqldatabase_snippet.cpp 24
181
182 We set the SQL table's name and the edit strategy, then we set up
183 the labels displayed in the view header. The edit strategy
184 dictates when the changes done by the user in the view are
185 actually applied to the database. The possible values are \l
186 OnFieldChange, \l OnRowChange, and \l OnManualSubmit.
187
188 QSqlTableModel can also be used to access a database
189 programmatically, without binding it to a view:
190
191 \snippet sqldatabase/sqldatabase.cpp 25
192
193 The code snippet above extracts the \c salary field from record 4 in
194 the result set of the query \c{SELECT * from employee}.
195
196 It is possible to set filters using setFilter(), or modify the
197 sort order using setSort(). At the end, you must call select() to
198 populate the model with data.
199
200 The \l{tablemodel} example illustrates how to use
201 QSqlTableModel as the data source for a QTableView.
202
203 QSqlTableModel provides no direct support for foreign keys. Use
204 the QSqlRelationalTableModel and QSqlRelationalDelegate if you
205 want to resolve foreign keys.
206
207 \sa QSqlRelationalTableModel, QSqlQuery, {Model/View Programming},
208 {Table Model Example}, {Cached SQL Table}
209*/
210
211/*!
212 \fn QSqlTableModel::beforeDelete(int row)
213
214 This signal is emitted by deleteRowFromTable() before the \a row
215 is deleted from the currently active database table.
216*/
217
218/*!
219 \fn void QSqlTableModel::primeInsert(int row, QSqlRecord &record)
220
221 This signal is emitted by insertRows(), when an insertion is
222 initiated in the given \a row of the currently active database
223 table. The \a record parameter can be written to (since it is a
224 reference), for example to populate some fields with default
225 values and set the generated flags of the fields. Do not try to
226 edit the record via other means such as setData() or setRecord()
227 while handling this signal.
228*/
229
230/*!
231 \fn QSqlTableModel::beforeInsert(QSqlRecord &record)
232
233 This signal is emitted by insertRowIntoTable() before a new row is
234 inserted into the currently active database table. The values that
235 are about to be inserted are stored in \a record and can be
236 modified before they will be inserted.
237*/
238
239/*!
240 \fn QSqlTableModel::beforeUpdate(int row, QSqlRecord &record)
241
242 This signal is emitted by updateRowInTable() before the \a row is
243 updated in the currently active database table with the values
244 from \a record.
245
246 Note that only values that are marked as generated will be updated.
247 The generated flag can be set with \l QSqlRecord::setGenerated()
248 and checked with \l QSqlRecord::isGenerated().
249
250 \sa QSqlRecord::isGenerated()
251*/
252
253/*!
254 Creates an empty QSqlTableModel and sets the parent to \a parent
255 and the database connection to \a db. If \a db is not valid, the
256 default database connection will be used.
257
258 The default edit strategy is \l OnRowChange.
259*/
260QSqlTableModel::QSqlTableModel(QObject *parent, const QSqlDatabase &db)
261 : QSqlQueryModel(*new QSqlTableModelPrivate, parent)
262{
263 Q_D(QSqlTableModel);
264 d->db = db.isValid() ? db : QSqlDatabase::database();
265}
266
267/*! \internal
268*/
269QSqlTableModel::QSqlTableModel(QSqlTableModelPrivate &dd, QObject *parent, const QSqlDatabase &db)
270 : QSqlQueryModel(dd, parent)
271{
272 Q_D(QSqlTableModel);
273 d->db = db.isValid() ? db : QSqlDatabase::database();
274}
275
276/*!
277 Destroys the object and frees any allocated resources.
278*/
279QSqlTableModel::~QSqlTableModel()
280{
281}
282
283/*!
284 Sets the database table on which the model operates to \a
285 tableName. Does not select data from the table, but fetches its
286 field information.
287
288 To populate the model with the table's data, call select().
289
290 Error information can be retrieved with \l lastError().
291
292 \sa select(), setFilter(), lastError()
293*/
294void QSqlTableModel::setTable(const QString &tableName)
295{
296 Q_D(QSqlTableModel);
297 clear();
298 d->tableName = tableName;
299 d->initRecordAndPrimaryIndex();
300
301 if (d->rec.count() == 0)
302 d->error = QSqlError("Unable to find table "_L1 + d->tableName, QString(),
303 QSqlError::StatementError);
304
305 // Remember the auto index column if there is one now.
306 // The record that will be obtained from the query after select lacks this feature.
307 d->autoColumn.clear();
308 for (int c = 0; c < d->rec.count(); ++c) {
309 if (d->rec.field(i: c).isAutoValue()) {
310 d->autoColumn = d->rec.fieldName(i: c);
311 break;
312 }
313 }
314}
315
316/*!
317 Returns the name of the currently selected table.
318*/
319QString QSqlTableModel::tableName() const
320{
321 Q_D(const QSqlTableModel);
322 return d->tableName;
323}
324
325/*!
326 Populates the model with data from the table that was set via setTable(), using the
327 specified filter and sort condition, and returns \c true if successful; otherwise
328 returns \c false.
329
330 \note Calling select() will revert any unsubmitted changes and remove any inserted columns.
331
332 \sa setTable(), setFilter(), selectStatement()
333*/
334bool QSqlTableModel::select()
335{
336 Q_D(QSqlTableModel);
337 const QString query = selectStatement();
338 if (query.isEmpty())
339 return false;
340
341 beginResetModel();
342
343 d->clearCache();
344
345 this->QSqlQueryModel::setQuery(query, db: d->db);
346
347 if (!d->query.isActive() || lastError().isValid()) {
348 // something went wrong - revert to non-select state
349 d->initRecordAndPrimaryIndex();
350 endResetModel();
351 return false;
352 }
353 endResetModel();
354 return true;
355}
356
357/*!
358 \since 5.0
359
360 Refreshes \a row in the model with values from the database table row matching
361 on primary key values. Without a primary key, all column values must match. If
362 no matching row is found, the model will show an empty row.
363
364 Returns \c true if successful; otherwise returns \c false.
365
366 \sa select()
367*/
368bool QSqlTableModel::selectRow(int row)
369{
370 Q_D(QSqlTableModel);
371
372 if (row < 0 || row >= rowCount())
373 return false;
374
375 const int table_sort_col = d->sortColumn;
376 d->sortColumn = -1;
377 const QString table_filter = d->filter;
378 d->filter = d->db.driver()->sqlStatement(type: QSqlDriver::WhereStatement,
379 tableName: d->tableName,
380 rec: primaryValues(row),
381 preparedStatement: false);
382 static const QString wh = SqlTm::where() + SqlTm::sp();
383 if (d->filter.startsWith(s: wh, cs: Qt::CaseInsensitive))
384 d->filter.remove(i: 0, len: wh.size());
385
386 QString stmt;
387
388 if (!d->filter.isEmpty())
389 stmt = selectStatement();
390
391 d->sortColumn = table_sort_col;
392 d->filter = table_filter;
393
394 if (stmt.isEmpty())
395 return false;
396
397 bool exists;
398 QSqlRecord newValues;
399
400 {
401 QSqlQuery q(d->db);
402 q.setForwardOnly(true);
403 if (!q.exec(query: stmt))
404 return false;
405
406 exists = q.next();
407 newValues = q.record();
408 }
409
410 bool needsAddingToCache = !exists || d->cache.contains(key: row);
411
412 if (!needsAddingToCache) {
413 const QSqlRecord curValues = record(row);
414 needsAddingToCache = curValues.count() != newValues.count();
415 if (!needsAddingToCache) {
416 // Look for changed values. Primary key fields are customarily first
417 // and probably change less often than other fields, so start at the end.
418 for (int f = curValues.count() - 1; f >= 0; --f) {
419 if (curValues.value(i: f) != newValues.value(i: f)) {
420 needsAddingToCache = true;
421 break;
422 }
423 }
424 }
425 }
426
427 if (needsAddingToCache) {
428 d->cache[row].refresh(exists, newvals: newValues);
429 emit headerDataChanged(orientation: Qt::Vertical, first: row, last: row);
430 emit dataChanged(topLeft: createIndex(arow: row, acolumn: 0), bottomRight: createIndex(arow: row, acolumn: columnCount() - 1));
431 }
432
433 return true;
434}
435
436/*!
437 \reimp
438*/
439QVariant QSqlTableModel::data(const QModelIndex &index, int role) const
440{
441 Q_D(const QSqlTableModel);
442 if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole))
443 return QVariant();
444
445 const auto it = d->cache.constFind(key: index.row());
446 if (it != d->cache.constEnd() && it->op() != QSqlTableModelPrivate::None)
447 return it->rec().value(i: index.column());
448
449 return QSqlQueryModel::data(item: index, role);
450}
451
452/*!
453 \reimp
454*/
455QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, int role) const
456{
457 Q_D(const QSqlTableModel);
458 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
459 const QSqlTableModelPrivate::Op op = d->cache.value(key: section).op();
460 if (op == QSqlTableModelPrivate::Insert)
461 return "*"_L1;
462 else if (op == QSqlTableModelPrivate::Delete)
463 return "!"_L1;
464 }
465 return QSqlQueryModel::headerData(section, orientation, role);
466}
467
468/*!
469 \overload
470 \since 5.0
471
472 Returns \c true if the model contains modified values that have not been
473 committed to the database, otherwise false.
474*/
475bool QSqlTableModel::isDirty() const
476{
477 Q_D(const QSqlTableModel);
478 QSqlTableModelPrivate::CacheMap::ConstIterator i = d->cache.constBegin();
479 const QSqlTableModelPrivate::CacheMap::ConstIterator e = d->cache.constEnd();
480 for (; i != e; ++i) {
481 if (!i.value().submitted())
482 return true;
483 }
484 return false;
485}
486
487/*!
488 Returns \c true if the value at the index \a index is dirty, otherwise false.
489 Dirty values are values that were modified in the model
490 but not yet written into the database.
491
492 If \a index is invalid or points to a non-existing row, false is returned.
493*/
494bool QSqlTableModel::isDirty(const QModelIndex &index) const
495{
496 Q_D(const QSqlTableModel);
497 if (!index.isValid())
498 return false;
499
500 const auto it = d->cache.constFind(key: index.row());
501 if (it == d->cache.constEnd())
502 return false;
503 const QSqlTableModelPrivate::ModifiedRow &row = *it;
504 if (row.submitted())
505 return false;
506
507 return row.op() == QSqlTableModelPrivate::Insert
508 || row.op() == QSqlTableModelPrivate::Delete
509 || (row.op() == QSqlTableModelPrivate::Update
510 && row.rec().isGenerated(i: index.column()));
511}
512
513/*!
514 Sets the data for the item \a index for the role \a role to \a
515 value.
516
517 For edit strategy OnFieldChange, an index may receive a change
518 only if no other index has a cached change. Changes are
519 submitted immediately. However, rows that have not yet been
520 inserted in the database may be freely changed and are not
521 submitted automatically. Submitted changes are not reverted upon
522 failure.
523
524 For OnRowChange, an index may receive a change only if no other
525 row has a cached change. Changes are not submitted automatically.
526
527 Returns \c true if \a value is equal to the current value. However,
528 the value will not be submitted to the database.
529
530 Returns \c true if the value could be set or false on error, for
531 example if \a index is out of bounds.
532
533 Returns \c false if the role is not Qt::EditRole. To set data
534 for roles other than EditRole, either use a custom proxy model
535 or subclass QSqlTableModel.
536
537 \sa editStrategy(), data(), submit(), submitAll(), revertRow()
538*/
539bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
540{
541 Q_D(QSqlTableModel);
542 if (d->busyInsertingRows)
543 return false;
544
545 if (role != Qt::EditRole)
546 return QSqlQueryModel::setData(index, value, role);
547
548 if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
549 return false;
550
551 if (!(flags(index) & Qt::ItemIsEditable))
552 return false;
553
554 const QVariant oldValue = QSqlTableModel::data(index, role);
555 if (value == oldValue
556 && value.isNull() == oldValue.isNull()
557 && d->cache.value(key: index.row()).op() != QSqlTableModelPrivate::Insert)
558 return true;
559
560 QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
561
562 if (row.op() == QSqlTableModelPrivate::None)
563 row = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
564 QSqlQueryModel::record(row: index.row()));
565
566 row.setValue(c: index.column(), v: value);
567 emit dataChanged(topLeft: index, bottomRight: index);
568
569 if (d->strategy == OnFieldChange && row.op() != QSqlTableModelPrivate::Insert)
570 return submit();
571
572 return true;
573}
574
575/*!
576 \reimp
577 */
578bool QSqlTableModel::clearItemData(const QModelIndex &index)
579{
580 return setData(index, value: QVariant(), role: Qt::EditRole);
581}
582
583/*!
584 Updates the given \a row in the currently active database table
585 with the specified \a values. Returns \c true if successful; otherwise
586 returns \c false.
587
588 This is a low-level method that operates directly on the database
589 and should not be called directly. Use setData() to update values.
590 The model will decide depending on its edit strategy when to modify
591 the database.
592
593 Note that only values that have the generated-flag set are updated.
594 The generated-flag can be set with QSqlRecord::setGenerated() and
595 tested with QSqlRecord::isGenerated().
596
597 \sa QSqlRecord::isGenerated(), setData()
598*/
599bool QSqlTableModel::updateRowInTable(int row, const QSqlRecord &values)
600{
601 Q_D(QSqlTableModel);
602 QSqlRecord rec(values);
603 emit beforeUpdate(row, record&: rec);
604
605 const QSqlRecord whereValues = primaryValues(row);
606 const bool prepStatement = d->db.driver()->hasFeature(f: QSqlDriver::PreparedQueries);
607 const QString stmt = d->db.driver()->sqlStatement(type: QSqlDriver::UpdateStatement, tableName: d->tableName,
608 rec, preparedStatement: prepStatement);
609 const QString where = d->db.driver()->sqlStatement(type: QSqlDriver::WhereStatement, tableName: d->tableName,
610 rec: whereValues, preparedStatement: prepStatement);
611
612 if (stmt.isEmpty() || where.isEmpty() || row < 0 || row >= rowCount()) {
613 d->error = QSqlError("No Fields to update"_L1, QString(), QSqlError::StatementError);
614 return false;
615 }
616
617 return d->exec(stmt: SqlTm::concat(a: stmt, b: where), prepStatement, rec, whereValues);
618}
619
620
621/*!
622 Inserts the values \a values into the currently active database table.
623
624 This is a low-level method that operates directly on the database
625 and should not be called directly. Use insertRow() and setData()
626 to insert values. The model will decide depending on its edit strategy
627 when to modify the database.
628
629 Returns \c true if the values could be inserted, otherwise false.
630 Error information can be retrieved with \l lastError().
631
632 \sa lastError(), insertRow(), insertRows()
633*/
634bool QSqlTableModel::insertRowIntoTable(const QSqlRecord &values)
635{
636 Q_D(QSqlTableModel);
637 QSqlRecord rec = values;
638 emit beforeInsert(record&: rec);
639
640 const bool prepStatement = d->db.driver()->hasFeature(f: QSqlDriver::PreparedQueries);
641 const QString stmt = d->db.driver()->sqlStatement(type: QSqlDriver::InsertStatement, tableName: d->tableName,
642 rec, preparedStatement: prepStatement);
643
644 if (stmt.isEmpty()) {
645 d->error = QSqlError("No Fields to update"_L1, QString(), QSqlError::StatementError);
646 return false;
647 }
648
649 return d->exec(stmt, prepStatement, rec, whereValues: QSqlRecord() /* no where values */);
650}
651
652/*!
653 Deletes the given \a row from the currently active database table.
654
655 This is a low-level method that operates directly on the database
656 and should not be called directly. Use removeRow() or removeRows()
657 to delete values. The model will decide depending on its edit strategy
658 when to modify the database.
659
660 Returns \c true if the row was deleted; otherwise returns \c false.
661
662 \sa removeRow(), removeRows()
663*/
664bool QSqlTableModel::deleteRowFromTable(int row)
665{
666 Q_D(QSqlTableModel);
667 emit beforeDelete(row);
668
669 const QSqlRecord whereValues = primaryValues(row);
670 const bool prepStatement = d->db.driver()->hasFeature(f: QSqlDriver::PreparedQueries);
671 const QString stmt = d->db.driver()->sqlStatement(type: QSqlDriver::DeleteStatement,
672 tableName: d->tableName,
673 rec: QSqlRecord(),
674 preparedStatement: prepStatement);
675 const QString where = d->db.driver()->sqlStatement(type: QSqlDriver::WhereStatement,
676 tableName: d->tableName,
677 rec: whereValues,
678 preparedStatement: prepStatement);
679
680 if (stmt.isEmpty() || where.isEmpty()) {
681 d->error = QSqlError("Unable to delete row"_L1, QString(), QSqlError::StatementError);
682 return false;
683 }
684
685 return d->exec(stmt: SqlTm::concat(a: stmt, b: where), prepStatement, rec: QSqlRecord() /* no new values */, whereValues);
686}
687
688/*!
689 Submits all pending changes and returns \c true on success.
690 Returns \c false on error, detailed error information can be
691 obtained with lastError().
692
693 In OnManualSubmit, on success the model will be repopulated.
694 Any views presenting it will lose their selections.
695
696 Note: In OnManualSubmit mode, already submitted changes won't
697 be cleared from the cache when submitAll() fails. This allows
698 transactions to be rolled back and resubmitted without
699 losing data.
700
701 \sa revertAll(), lastError()
702*/
703bool QSqlTableModel::submitAll()
704{
705 Q_D(QSqlTableModel);
706
707 bool success = true;
708
709 const auto cachedKeys = d->cache.keys();
710 for (int row : cachedKeys) {
711 // be sure cache *still* contains the row since overridden selectRow() could have called select()
712 QSqlTableModelPrivate::CacheMap::iterator it = d->cache.find(key: row);
713 if (it == d->cache.end())
714 continue;
715
716 QSqlTableModelPrivate::ModifiedRow &mrow = it.value();
717 if (mrow.submitted())
718 continue;
719
720 switch (mrow.op()) {
721 case QSqlTableModelPrivate::Insert:
722 success = insertRowIntoTable(values: mrow.rec());
723 break;
724 case QSqlTableModelPrivate::Update:
725 success = updateRowInTable(row, values: mrow.rec());
726 break;
727 case QSqlTableModelPrivate::Delete:
728 success = deleteRowFromTable(row);
729 break;
730 case QSqlTableModelPrivate::None:
731 Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
732 break;
733 }
734
735 if (success) {
736 if (d->strategy != OnManualSubmit && mrow.op() == QSqlTableModelPrivate::Insert) {
737 int c = mrow.rec().indexOf(name: d->autoColumn);
738 if (c != -1 && !mrow.rec().isGenerated(i: c))
739 mrow.setValue(c, v: d->editQuery.lastInsertId());
740 }
741 mrow.setSubmitted();
742 if (d->strategy != OnManualSubmit)
743 success = selectRow(row);
744 }
745
746 if (!success)
747 break;
748 }
749
750 if (success) {
751 if (d->strategy == OnManualSubmit)
752 success = select();
753 }
754
755 return success;
756}
757
758/*!
759 This reimplemented slot is called by the item delegates when the
760 user stopped editing the current row.
761
762 Submits the currently edited row if the model's strategy is set
763 to OnRowChange or OnFieldChange. Does nothing for the OnManualSubmit
764 strategy.
765
766 Use submitAll() to submit all pending changes for the
767 OnManualSubmit strategy.
768
769 Returns \c true on success; otherwise returns \c false. Use lastError()
770 to query detailed error information.
771
772 Does not automatically repopulate the model. Submitted rows are
773 refreshed from the database on success.
774
775 \sa revert(), revertRow(), submitAll(), revertAll(), lastError()
776*/
777bool QSqlTableModel::submit()
778{
779 Q_D(QSqlTableModel);
780 if (d->strategy == OnRowChange || d->strategy == OnFieldChange)
781 return submitAll();
782 return true;
783}
784
785/*!
786 This reimplemented slot is called by the item delegates when the
787 user canceled editing the current row.
788
789 Reverts the changes if the model's strategy is set to
790 OnRowChange or OnFieldChange. Does nothing for the OnManualSubmit
791 strategy.
792
793 Use revertAll() to revert all pending changes for the
794 OnManualSubmit strategy or revertRow() to revert a specific row.
795
796 \sa submit(), submitAll(), revertRow(), revertAll()
797*/
798void QSqlTableModel::revert()
799{
800 Q_D(QSqlTableModel);
801 if (d->strategy == OnRowChange || d->strategy == OnFieldChange)
802 revertAll();
803}
804
805/*!
806 \enum QSqlTableModel::EditStrategy
807
808 This enum type describes which strategy to choose when editing values in the database.
809
810 \value OnFieldChange All changes to the model will be applied immediately to the database.
811 \value OnRowChange Changes to a row will be applied when the user selects a different row.
812 \value OnManualSubmit All changes will be cached in the model until either submitAll()
813 or revertAll() is called.
814
815 Note: To prevent inserting only partly initialized rows into the database,
816 \c OnFieldChange will behave like \c OnRowChange for newly inserted rows.
817
818 \sa setEditStrategy()
819*/
820
821
822/*!
823 Sets the strategy for editing values in the database to \a
824 strategy.
825
826 This will revert any pending changes.
827
828 \sa editStrategy(), revertAll()
829*/
830void QSqlTableModel::setEditStrategy(EditStrategy strategy)
831{
832 Q_D(QSqlTableModel);
833 revertAll();
834 d->strategy = strategy;
835}
836
837/*!
838 Returns the current edit strategy.
839
840 \sa setEditStrategy()
841*/
842QSqlTableModel::EditStrategy QSqlTableModel::editStrategy() const
843{
844 Q_D(const QSqlTableModel);
845 return d->strategy;
846}
847
848/*!
849 Reverts all pending changes.
850
851 \sa revert(), revertRow(), submitAll()
852*/
853void QSqlTableModel::revertAll()
854{
855 Q_D(QSqlTableModel);
856
857 const QList<int> rows(d->cache.keys());
858 for (int i = rows.size() - 1; i >= 0; --i)
859 revertRow(row: rows.value(i));
860}
861
862/*!
863 Reverts all changes for the specified \a row.
864
865 \sa revert(), revertAll(), submit(), submitAll()
866*/
867void QSqlTableModel::revertRow(int row)
868{
869 if (row < 0)
870 return;
871
872 Q_D(QSqlTableModel);
873 d->revertCachedRow(row);
874}
875
876/*!
877 Returns the primary key for the current table, or an empty
878 QSqlIndex if the table is not set or has no primary key.
879
880 \sa setTable(), setPrimaryKey(), QSqlDatabase::primaryIndex()
881*/
882QSqlIndex QSqlTableModel::primaryKey() const
883{
884 Q_D(const QSqlTableModel);
885 return d->primaryIndex;
886}
887
888/*!
889 Protected method that allows subclasses to set the primary key to
890 \a key.
891
892 Normally, the primary index is set automatically whenever you
893 call setTable().
894
895 \sa primaryKey(), QSqlDatabase::primaryIndex()
896*/
897void QSqlTableModel::setPrimaryKey(const QSqlIndex &key)
898{
899 Q_D(QSqlTableModel);
900 d->primaryIndex = key;
901}
902
903/*!
904 Returns the model's database connection.
905*/
906QSqlDatabase QSqlTableModel::database() const
907{
908 Q_D(const QSqlTableModel);
909 return d->db;
910}
911
912/*!
913 Sorts the data by \a column with the sort order \a order.
914 This will immediately select data, use setSort()
915 to set a sort order without populating the model with data.
916
917 \sa setSort(), select(), orderByClause()
918*/
919void QSqlTableModel::sort(int column, Qt::SortOrder order)
920{
921 setSort(column, order);
922 select();
923}
924
925/*!
926 Sets the sort order for \a column to \a order. This does not
927 affect the current data, to refresh the data using the new
928 sort order, call select().
929
930 \sa select(), orderByClause()
931*/
932void QSqlTableModel::setSort(int column, Qt::SortOrder order)
933{
934 Q_D(QSqlTableModel);
935 d->sortColumn = column;
936 d->sortOrder = order;
937}
938
939/*!
940 Returns an SQL \c{ORDER BY} clause based on the currently set
941 sort order.
942
943 \sa setSort(), selectStatement()
944*/
945QString QSqlTableModel::orderByClause() const
946{
947 Q_D(const QSqlTableModel);
948 QSqlField f = d->rec.field(i: d->sortColumn);
949 if (!f.isValid())
950 return QString();
951
952 //we can safely escape the field because it would have been obtained from the database
953 //and have the correct case
954 QString field = d->db.driver()->escapeIdentifier(identifier: d->tableName, type: QSqlDriver::TableName)
955 + u'.'
956 + d->db.driver()->escapeIdentifier(identifier: f.name(), type: QSqlDriver::FieldName);
957 field = d->sortOrder == Qt::AscendingOrder ? SqlTm::asc(s: field) : SqlTm::desc(s: field);
958 return SqlTm::orderBy(s: field);
959}
960
961/*!
962 Returns the index of the field \a fieldName, or -1 if no corresponding field
963 exists in the model.
964*/
965int QSqlTableModel::fieldIndex(const QString &fieldName) const
966{
967 Q_D(const QSqlTableModel);
968 return d->rec.indexOf(name: fieldName);
969}
970
971/*!
972 Returns the SQL \c SELECT statement used internally to populate
973 the model. The statement includes the filter and the \c{ORDER BY}
974 clause.
975
976 \sa filter(), orderByClause()
977*/
978QString QSqlTableModel::selectStatement() const
979{
980 Q_D(const QSqlTableModel);
981 if (d->tableName.isEmpty()) {
982 d->error = QSqlError("No table name given"_L1, QString(), QSqlError::StatementError);
983 return QString();
984 }
985 if (d->rec.isEmpty()) {
986 d->error = QSqlError("Unable to find table "_L1 + d->tableName, QString(),
987 QSqlError::StatementError);
988 return QString();
989 }
990
991 const QString stmt = d->db.driver()->sqlStatement(type: QSqlDriver::SelectStatement,
992 tableName: d->tableName,
993 rec: d->rec,
994 preparedStatement: false);
995 if (stmt.isEmpty()) {
996 d->error = QSqlError("Unable to select fields from table "_L1 + d->tableName,
997 QString(), QSqlError::StatementError);
998 return stmt;
999 }
1000 return SqlTm::concat(a: SqlTm::concat(a: stmt, b: SqlTm::where(s: d->filter)), b: orderByClause());
1001}
1002
1003/*!
1004 Removes \a count columns from the \a parent model, starting at
1005 index \a column.
1006
1007 Returns if the columns were successfully removed; otherwise
1008 returns \c false.
1009
1010 \sa removeRows()
1011*/
1012bool QSqlTableModel::removeColumns(int column, int count, const QModelIndex &parent)
1013{
1014 Q_D(QSqlTableModel);
1015 if (parent.isValid() || column < 0 || column + count > d->rec.count())
1016 return false;
1017 for (int i = 0; i < count; ++i)
1018 d->rec.remove(pos: column);
1019 if (d->query.isActive())
1020 return select();
1021 return true;
1022}
1023
1024/*!
1025 Removes \a count rows starting at \a row. Since this model
1026 does not support hierarchical structures, \a parent must be
1027 an invalid model index.
1028
1029 When the edit strategy is OnManualSubmit, deletion of rows from
1030 the database is delayed until submitAll() is called.
1031
1032 For OnFieldChange and OnRowChange, only one row may be deleted
1033 at a time and only if no other row has a cached change. Deletions
1034 are submitted immediately to the database. The model retains a
1035 blank row for successfully deleted row until refreshed with select().
1036
1037 After failed deletion, the operation is not reverted in the model.
1038 The application may resubmit or revert.
1039
1040 Inserted but not yet successfully submitted rows in the range to be
1041 removed are immediately removed from the model.
1042
1043 Before a row is deleted from the database, the beforeDelete()
1044 signal is emitted.
1045
1046 If row < 0 or row + count > rowCount(), no action is taken and
1047 false is returned. Returns \c true if all rows could be removed;
1048 otherwise returns \c false. Detailed database error information
1049 can be retrieved using lastError().
1050
1051 \sa removeColumns(), insertRows()
1052*/
1053bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
1054{
1055 Q_D(QSqlTableModel);
1056 if (parent.isValid() || row < 0 || count <= 0 || row + count > rowCount())
1057 return false;
1058
1059 if (d->strategy != OnManualSubmit)
1060 if (count > 1 || (d->cache.value(key: row).submitted() && isDirty()))
1061 return false;
1062
1063 // Iterate backwards so we don't have to worry about removed rows causing
1064 // higher cache entries to shift downwards.
1065 for (int idx = row + count - 1; idx >= row; --idx) {
1066 QSqlTableModelPrivate::ModifiedRow& mrow = d->cache[idx];
1067 if (mrow.op() == QSqlTableModelPrivate::Insert) {
1068 revertRow(row: idx);
1069 } else {
1070 if (mrow.op() == QSqlTableModelPrivate::None)
1071 mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete,
1072 QSqlQueryModel::record(row: idx));
1073 else
1074 mrow.setOp(QSqlTableModelPrivate::Delete);
1075 if (d->strategy == OnManualSubmit)
1076 emit headerDataChanged(orientation: Qt::Vertical, first: idx, last: idx);
1077 }
1078 }
1079
1080 if (d->strategy != OnManualSubmit)
1081 return submit();
1082
1083 return true;
1084}
1085
1086/*!
1087 Inserts \a count empty rows at position \a row. Note that \a
1088 parent must be invalid, since this model does not support
1089 parent-child relations.
1090
1091 For edit strategies OnFieldChange and OnRowChange, only one row
1092 may be inserted at a time and the model may not contain other
1093 cached changes.
1094
1095 The primeInsert() signal will be emitted for each new row.
1096 Connect to it if you want to initialize the new row with default
1097 values.
1098
1099 Does not submit rows, regardless of edit strategy.
1100
1101 Returns \c false if the parameters are out of bounds or the row cannot be
1102 inserted; otherwise returns \c true.
1103
1104 \sa primeInsert(), insertRecord()
1105*/
1106bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
1107{
1108 Q_D(QSqlTableModel);
1109 if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
1110 return false;
1111
1112 if (d->strategy != OnManualSubmit)
1113 if (count != 1 || isDirty())
1114 return false;
1115
1116 d->busyInsertingRows = true;
1117 beginInsertRows(parent, first: row, last: row + count - 1);
1118
1119 if (d->strategy != OnManualSubmit)
1120 d->cache.empty();
1121
1122 if (!d->cache.isEmpty()) {
1123 QMap<int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = d->cache.end();
1124 while (it != d->cache.begin() && (--it).key() >= row) {
1125 int oldKey = it.key();
1126 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
1127 d->cache.erase(it);
1128 it = d->cache.insert(key: oldKey + count, value: oldValue);
1129 }
1130 }
1131
1132 for (int i = 0; i < count; ++i) {
1133 d->cache[row + i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert,
1134 d->rec);
1135 emit primeInsert(row: row + i, record&: d->cache[row + i].recRef());
1136 }
1137
1138 endInsertRows();
1139 d->busyInsertingRows = false;
1140 return true;
1141}
1142
1143/*!
1144 Inserts the \a record at position \a row. If \a row is negative,
1145 the record will be appended to the end. Calls insertRows() and
1146 setRecord() internally.
1147
1148 Returns \c true if the record could be inserted, otherwise false.
1149
1150 Changes are submitted immediately for OnFieldChange and
1151 OnRowChange. Failure does not leave a new row in the model.
1152
1153 \sa insertRows(), removeRows(), setRecord()
1154*/
1155bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record)
1156{
1157 if (row < 0)
1158 row = rowCount();
1159 if (!insertRow(arow: row, aparent: QModelIndex()))
1160 return false;
1161 if (!setRecord(row, record)) {
1162 revertRow(row);
1163 return false;
1164 }
1165 return true;
1166}
1167
1168/*! \reimp
1169*/
1170int QSqlTableModel::rowCount(const QModelIndex &parent) const
1171{
1172 Q_D(const QSqlTableModel);
1173
1174 if (parent.isValid())
1175 return 0;
1176
1177 return QSqlQueryModel::rowCount() + d->insertCount();
1178}
1179
1180/*!
1181 Returns the index of the value in the database result set for the
1182 given \a item in the model.
1183
1184 The return value is identical to \a item if no columns or rows
1185 have been inserted, removed, or moved around.
1186
1187 Returns an invalid model index if \a item is out of bounds or if
1188 \a item does not point to a value in the result set.
1189
1190 \sa QSqlQueryModel::indexInQuery()
1191*/
1192QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const
1193{
1194 Q_D(const QSqlTableModel);
1195 const auto it = d->cache.constFind(key: item.row());
1196 if (it != d->cache.constEnd() && it->insert())
1197 return QModelIndex();
1198
1199 const int rowOffset = d->insertCount(maxRow: item.row());
1200 return QSqlQueryModel::indexInQuery(item: createIndex(arow: item.row() - rowOffset, acolumn: item.column(), adata: item.internalPointer()));
1201}
1202
1203/*!
1204 Returns the currently set filter.
1205
1206 \sa setFilter(), select()
1207*/
1208QString QSqlTableModel::filter() const
1209{
1210 Q_D(const QSqlTableModel);
1211 return d->filter;
1212}
1213
1214/*!
1215 Sets the current filter to \a filter.
1216
1217 The filter is a SQL \c WHERE clause without the keyword \c WHERE
1218 (for example, \c{name='Josephine')}.
1219
1220 If the model is already populated with data from a database,
1221 the model re-selects it with the new filter. Otherwise, the filter
1222 will be applied the next time select() is called.
1223
1224 \sa filter(), select(), selectStatement(), orderByClause()
1225*/
1226void QSqlTableModel::setFilter(const QString &filter)
1227{
1228 Q_D(QSqlTableModel);
1229 d->filter = filter;
1230 if (d->query.isActive())
1231 select();
1232}
1233
1234/*! \reimp
1235*/
1236void QSqlTableModel::clear()
1237{
1238 Q_D(QSqlTableModel);
1239 beginResetModel();
1240 d->clear();
1241 QSqlQueryModel::clear();
1242 endResetModel();
1243}
1244
1245/*! \reimp
1246*/
1247Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const
1248{
1249 Q_D(const QSqlTableModel);
1250 if (index.internalPointer() || index.column() < 0 || index.column() >= d->rec.count()
1251 || index.row() < 0)
1252 return { };
1253
1254 bool editable = true;
1255
1256 if (d->rec.field(i: index.column()).isReadOnly()) {
1257 editable = false;
1258 }
1259 else {
1260 const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(key: index.row());
1261 if (mrow.op() == QSqlTableModelPrivate::Delete) {
1262 editable = false;
1263 }
1264 else if (d->strategy == OnFieldChange) {
1265 if (mrow.op() != QSqlTableModelPrivate::Insert)
1266 if (!isDirty(index) && isDirty())
1267 editable = false;
1268 }
1269 else if (d->strategy == OnRowChange) {
1270 if (mrow.submitted() && isDirty())
1271 editable = false;
1272 }
1273 }
1274
1275 if (!editable)
1276 return QSqlQueryModel::flags(index);
1277 else
1278 return QSqlQueryModel::flags(index) | Qt::ItemIsEditable;
1279}
1280
1281/*!
1282 This is an overloaded function.
1283
1284 It returns an empty record, having only the field names. This function can be used to
1285 retrieve the field names of a record.
1286
1287 \sa QSqlRecord::isEmpty()
1288*/
1289QSqlRecord QSqlTableModel::record() const
1290{
1291 return QSqlQueryModel::record();
1292}
1293
1294/*!
1295\since 5.0
1296 Returns the record at \a row in the model.
1297
1298 If \a row is the index of a valid row, the record
1299 will be populated with values from that row.
1300
1301 If the model is not initialized, an empty record will be
1302 returned.
1303
1304 \sa QSqlRecord::isEmpty()
1305*/
1306QSqlRecord QSqlTableModel::record(int row) const
1307{
1308 Q_D(const QSqlTableModel);
1309
1310 // the query gets the values from virtual data()
1311 QSqlRecord rec = QSqlQueryModel::record(row);
1312
1313 // get generated flags from the cache
1314 const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(key: row);
1315 if (mrow.op() != QSqlTableModelPrivate::None) {
1316 const QSqlRecord &crec = mrow.rec();
1317 for (int i = 0, cnt = rec.count(); i < cnt; ++i)
1318 rec.setGenerated(i, generated: crec.isGenerated(i));
1319 }
1320
1321 return rec;
1322}
1323
1324/*!
1325 Applies \a values to the \a row in the model. The source and
1326 target fields are mapped by field name, not by position in
1327 the record.
1328
1329 Note that the generated flags in \a values are preserved to
1330 determine whether the corresponding fields are used when changes
1331 are submitted to the database. By default, it is set to \c true
1332 for all fields in a QSqlRecord. You must set the flag to \c false
1333 using \l{QSqlRecord::}{setGenerated}(false) for any value in
1334 \a values, to save changes back to the database.
1335
1336 For edit strategies OnFieldChange and OnRowChange, a row may
1337 receive a change only if no other row has a cached change.
1338 Changes are submitted immediately. Submitted changes are not
1339 reverted upon failure.
1340
1341 Returns \c true if all the values could be set; otherwise returns
1342 false.
1343
1344 \sa record(), editStrategy()
1345*/
1346bool QSqlTableModel::setRecord(int row, const QSqlRecord &values)
1347{
1348 Q_D(QSqlTableModel);
1349 Q_ASSERT_X(row >= 0, "QSqlTableModel::setRecord()", "Cannot set a record to a row less than 0");
1350 if (d->busyInsertingRows)
1351 return false;
1352
1353 if (row >= rowCount())
1354 return false;
1355
1356 if (d->cache.value(key: row).op() == QSqlTableModelPrivate::Delete)
1357 return false;
1358
1359 if (d->strategy != OnManualSubmit && d->cache.value(key: row).submitted() && isDirty())
1360 return false;
1361
1362 // Check field names and remember mapping
1363 typedef QMap<int, int> Map;
1364 Map map;
1365 for (int i = 0; i < values.count(); ++i) {
1366 int idx = d->nameToIndex(name: values.fieldName(i));
1367 if (idx == -1)
1368 return false;
1369 map[i] = idx;
1370 }
1371
1372 QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
1373 if (mrow.op() == QSqlTableModelPrivate::None)
1374 mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
1375 QSqlQueryModel::record(row));
1376
1377 Map::const_iterator i = map.constBegin();
1378 const Map::const_iterator e = map.constEnd();
1379 for ( ; i != e; ++i) {
1380 // have to use virtual setData() here rather than mrow.setValue()
1381 EditStrategy strategy = d->strategy;
1382 d->strategy = OnManualSubmit;
1383 QModelIndex cIndex = createIndex(arow: row, acolumn: i.value());
1384 setData(index: cIndex, value: values.value(i: i.key()));
1385 d->strategy = strategy;
1386 // setData() sets generated to TRUE, but source record should prevail.
1387 if (!values.isGenerated(i: i.key()))
1388 mrow.recRef().setGenerated(i: i.value(), generated: false);
1389 }
1390
1391 if (d->strategy != OnManualSubmit)
1392 return submit();
1393
1394 return true;
1395}
1396
1397/*!
1398 \since 5.1
1399 Returns a record containing the fields represented in the primary key set to the values
1400 at \a row. If no primary key is defined, the returned record will contain all fields.
1401
1402 \sa primaryKey()
1403*/
1404QSqlRecord QSqlTableModel::primaryValues(int row) const
1405{
1406 Q_D(const QSqlTableModel);
1407
1408 const QSqlRecord &pIndex = d->primaryIndex.isEmpty() ? d->rec : d->primaryIndex;
1409
1410 QSqlTableModelPrivate::ModifiedRow mr = d->cache.value(key: row);
1411 if (mr.op() != QSqlTableModelPrivate::None)
1412 return mr.primaryValues(pi: pIndex);
1413 else
1414 return QSqlQueryModel::record(row).keyValues(keyFields: pIndex);
1415}
1416
1417QT_END_NAMESPACE
1418
1419#include "moc_qsqltablemodel.cpp"
1420

source code of qtbase/src/sql/models/qsqltablemodel.cpp