41QString QSqlTableModelPrivate::strippedFieldName(
const QString &name)
const
43 QString fieldname = name;
44 if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName))
45 fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
85void QSqlTableModelPrivate::revertCachedRow(
int row)
88 ModifiedRow r = cache.value(row);
91 case QSqlTableModelPrivate::None:
92 Q_ASSERT_X(
false,
"QSqlTableModelPrivate::revertCachedRow()",
"Invalid entry in cache map");
94 case QSqlTableModelPrivate::Update:
95 case QSqlTableModelPrivate::Delete:
98 emit q->dataChanged(q->createIndex(row, 0),
99 q->createIndex(row, q->columnCount() - 1));
102 case QSqlTableModelPrivate::Insert: {
103 QMap<
int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = cache.find(row);
104 if (it == cache.end())
106 q->beginRemoveRows(QModelIndex(), row, row);
107 it = cache.erase(it);
108 while (it != cache.end()) {
109 int oldKey = it.key();
110 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
112 it = cache.insert(oldKey - 1, oldValue);
120bool QSqlTableModelPrivate::exec(
const QString &stmt,
bool prepStatement,
121 const QSqlRecord &rec,
const QSqlRecord &whereValues)
127 if (editQuery.driver() != db.driver())
128 editQuery = QSqlQuery(db);
132 if (db.driver()->hasFeature(QSqlDriver::SimpleLocking))
133 const_cast<QSqlResult *>(query.result())->detachFromResultSet();
136 if (editQuery.lastQuery() != stmt) {
137 if (!editQuery.prepare(stmt)) {
138 error = editQuery.lastError();
142 for (
int i = 0; i < rec.count(); ++i)
143 if (rec.isGenerated(i))
144 editQuery.addBindValue(rec.value(i));
145 for (
int i = 0; i < whereValues.count(); ++i)
146 if (whereValues.isGenerated(i) && !whereValues.isNull(i))
147 editQuery.addBindValue(whereValues.value(i));
149 if (!editQuery.exec()) {
150 error = editQuery.lastError();
154 if (!editQuery.exec(stmt)) {
155 error = editQuery.lastError();
264QSqlTableModel::QSqlTableModel(QSqlTableModelPrivate &dd, QObject *parent,
const QSqlDatabase &db)
265 : QSqlQueryModel(dd, parent)
268 d->db = db.isValid() ? db : QSqlDatabase::database();
289void QSqlTableModel::setTable(
const QString &tableName)
293 d->tableName = tableName;
294 d->initRecordAndPrimaryIndex();
296 if (d->rec.count() == 0)
297 d->error = QSqlError(
"Unable to find table "_L1 + d->tableName, QString(),
298 QSqlError::StatementError);
302 d->autoColumn.clear();
303 for (
int c = 0; c < d->rec.count(); ++c) {
304 if (d->rec.field(c).isAutoValue()) {
305 d->autoColumn = d->rec.fieldName(c);
329bool QSqlTableModel::select()
332 const QString query = selectStatement();
340 this->QSqlQueryModel::setQuery(query, d->db);
342 if (!d->query.isActive() || lastError().isValid()) {
344 d->initRecordAndPrimaryIndex();
363bool QSqlTableModel::selectRow(
int row)
367 if (row < 0 || row >= rowCount())
370 const int table_sort_col = d->sortColumn;
372 const QString table_filter = d->filter;
373 d->filter = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement,
377 static const QString wh = SqlTm::where() + SqlTm::sp();
378 if (d->filter.startsWith(wh, Qt::CaseInsensitive))
379 d->filter.remove(0, wh.size());
383 if (!d->filter.isEmpty())
384 stmt = selectStatement();
386 d->sortColumn = table_sort_col;
387 d->filter = table_filter;
393 QSqlRecord newValues;
397 q.setForwardOnly(
true);
402 newValues = q.record();
405 bool needsAddingToCache = !exists || d->cache.contains(row);
407 if (!needsAddingToCache) {
408 const QSqlRecord curValues = record(row);
409 needsAddingToCache = curValues.count() != newValues.count();
410 if (!needsAddingToCache) {
413 for (
int f = curValues.count() - 1; f >= 0; --f) {
414 if (curValues.value(f) != newValues.value(f)) {
415 needsAddingToCache =
true;
422 if (needsAddingToCache) {
423 d->cache[row].refresh(exists, newValues);
424 emit headerDataChanged(Qt::Vertical, row, row);
425 emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
434QVariant QSqlTableModel::data(
const QModelIndex &index,
int role)
const
436 Q_D(
const QSqlTableModel);
437 if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole))
440 const auto it = d->cache.constFind(index.row());
441 if (it != d->cache.constEnd() && it->op() != QSqlTableModelPrivate::None)
442 return it->rec().value(index.column());
444 return QSqlQueryModel::data(index, role);
450QVariant QSqlTableModel::headerData(
int section, Qt::Orientation orientation,
int role)
const
452 Q_D(
const QSqlTableModel);
453 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
454 const QSqlTableModelPrivate::Op op = d->cache.value(section).op();
455 if (op == QSqlTableModelPrivate::Insert)
457 else if (op == QSqlTableModelPrivate::Delete)
460 return QSqlQueryModel::headerData(section, orientation, role);
487bool QSqlTableModel::isDirty(
const QModelIndex &index)
const
489 Q_D(
const QSqlTableModel);
490 if (!index.isValid())
493 const auto it = d->cache.constFind(index.row());
494 if (it == d->cache.constEnd())
496 const QSqlTableModelPrivate::ModifiedRow &row = *it;
500 return row.op() == QSqlTableModelPrivate::Insert
501 || row.op() == QSqlTableModelPrivate::Delete
502 || (row.op() == QSqlTableModelPrivate::Update
503 && row.rec().isGenerated(index.column()));
532bool QSqlTableModel::setData(
const QModelIndex &index,
const QVariant &value,
int role)
535 if (d->busyInsertingRows)
538 if (role != Qt::EditRole)
539 return QSqlQueryModel::setData(index, value, role);
541 if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
544 if (!(flags(index) & Qt::ItemIsEditable))
547 const QVariant oldValue = QSqlTableModel::data(index, role);
548 if (value == oldValue
549 && value.isNull() == oldValue.isNull()
550 && d->cache.value(index.row()).op() != QSqlTableModelPrivate::Insert)
553 QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
555 if (row.op() == QSqlTableModelPrivate::None)
556 row = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
557 QSqlQueryModel::record(index.row()));
559 row.setValue(index.column(), value);
560 emit dataChanged(index, index);
562 if (d->strategy == OnFieldChange && row.op() != QSqlTableModelPrivate::Insert)
592bool QSqlTableModel::updateRowInTable(
int row,
const QSqlRecord &values)
595 QSqlRecord rec(values);
596 emit beforeUpdate(row, rec);
598 const QSqlRecord whereValues = primaryValues(row);
599 const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
600 const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName,
602 const QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, d->tableName,
603 whereValues, prepStatement);
605 if (stmt.isEmpty() || where.isEmpty() || row < 0 || row >= rowCount()) {
606 d->error = QSqlError(
"No Fields to update"_L1, QString(), QSqlError::StatementError);
610 return d->exec(SqlTm::concat(stmt, where), prepStatement, rec, whereValues);
627bool QSqlTableModel::insertRowIntoTable(
const QSqlRecord &values)
630 QSqlRecord rec = values;
631 emit beforeInsert(rec);
633 const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
634 const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::InsertStatement, d->tableName,
637 if (stmt.isEmpty()) {
638 d->error = QSqlError(
"No Fields to update"_L1, QString(), QSqlError::StatementError);
642 return d->exec(stmt, prepStatement, rec, QSqlRecord() );
657bool QSqlTableModel::deleteRowFromTable(
int row)
660 emit beforeDelete(row);
662 const QSqlRecord whereValues = primaryValues(row);
663 const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
664 const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement,
668 const QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement,
673 if (stmt.isEmpty() || where.isEmpty()) {
674 d->error = QSqlError(
"Unable to delete row"_L1, QString(), QSqlError::StatementError);
678 return d->exec(SqlTm::concat(stmt, where), prepStatement, QSqlRecord() , whereValues);
696bool QSqlTableModel::submitAll()
702 const auto cachedKeys = d->cache.keys();
703 for (
int row : cachedKeys) {
705 QSqlTableModelPrivate::CacheMap::iterator it = d->cache.find(row);
706 if (it == d->cache.end())
709 QSqlTableModelPrivate::ModifiedRow &mrow = it.value();
710 if (mrow.submitted())
714 case QSqlTableModelPrivate::Insert:
715 success = insertRowIntoTable(mrow.rec());
717 case QSqlTableModelPrivate::Update:
718 success = updateRowInTable(row, mrow.rec());
720 case QSqlTableModelPrivate::Delete:
721 success = deleteRowFromTable(row);
723 case QSqlTableModelPrivate::None:
724 Q_ASSERT_X(
false,
"QSqlTableModel::submitAll()",
"Invalid cache operation");
729 if (d->strategy != OnManualSubmit && mrow.op() == QSqlTableModelPrivate::Insert) {
730 int c = mrow.rec().indexOf(d->autoColumn);
731 if (c != -1 && !mrow.rec().isGenerated(c))
732 mrow.setValue(c, d->editQuery.lastInsertId());
735 if (d->strategy != OnManualSubmit)
736 success = selectRow(row);
744 if (d->strategy == OnManualSubmit)
938QString QSqlTableModel::orderByClause()
const
940 Q_D(
const QSqlTableModel);
941 QSqlField f = d->rec.field(d->sortColumn);
947 QString field = d->db.driver()->escapeIdentifier(d->tableName, QSqlDriver::TableName)
949 + d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
950 field = d->sortOrder == Qt::AscendingOrder ? SqlTm::asc(field) : SqlTm::desc(field);
951 return SqlTm::orderBy(field);
971QString QSqlTableModel::selectStatement()
const
973 Q_D(
const QSqlTableModel);
974 if (d->tableName.isEmpty()) {
975 d->error = QSqlError(
"No table name given"_L1, QString(), QSqlError::StatementError);
978 if (d->rec.isEmpty()) {
979 d->error = QSqlError(
"Unable to find table "_L1 + d->tableName, QString(),
980 QSqlError::StatementError);
984 const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::SelectStatement,
988 if (stmt.isEmpty()) {
989 d->error = QSqlError(
"Unable to select fields from table "_L1 + d->tableName,
990 QString(), QSqlError::StatementError);
993 return SqlTm::concat(SqlTm::concat(stmt, SqlTm::where(d->filter)), orderByClause());
1046bool QSqlTableModel::removeRows(
int row,
int count,
const QModelIndex &parent)
1048 Q_D(QSqlTableModel);
1049 if (parent.isValid() || row < 0 || count <= 0 || row + count > rowCount())
1052 if (d->strategy != OnManualSubmit)
1053 if (count > 1 || (d->cache.value(row).submitted() && isDirty()))
1058 for (
int idx = row + count - 1; idx >= row; --idx) {
1059 QSqlTableModelPrivate::ModifiedRow& mrow = d->cache[idx];
1060 if (mrow.op() == QSqlTableModelPrivate::Insert) {
1063 if (mrow.op() == QSqlTableModelPrivate::None)
1064 mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete,
1065 QSqlQueryModel::record(idx));
1067 mrow.setOp(QSqlTableModelPrivate::Delete);
1068 if (d->strategy == OnManualSubmit)
1069 emit headerDataChanged(Qt::Vertical, idx, idx);
1073 if (d->strategy != OnManualSubmit)
1099bool QSqlTableModel::insertRows(
int row,
int count,
const QModelIndex &parent)
1101 Q_D(QSqlTableModel);
1102 if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
1105 if (d->strategy != OnManualSubmit)
1106 if (count != 1 || isDirty())
1109 d->busyInsertingRows =
true;
1110 beginInsertRows(parent, row, row + count - 1);
1112 if (!d->cache.isEmpty()) {
1113 QMap<
int, QSqlTableModelPrivate::ModifiedRow>::Iterator it = d->cache.end();
1114 while (it != d->cache.begin() && (--it).key() >= row) {
1115 int oldKey = it.key();
1116 const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
1118 it = d->cache.insert(oldKey + count, oldValue);
1122 for (
int i = 0; i < count; ++i) {
1123 d->cache[row + i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert,
1125 emit primeInsert(row + i, d->cache[row + i].recRef());
1129 d->busyInsertingRows =
false;
1182QModelIndex QSqlTableModel::indexInQuery(
const QModelIndex &item)
const
1184 Q_D(
const QSqlTableModel);
1185 const auto it = d->cache.constFind(item.row());
1186 if (it != d->cache.constEnd() && it->insert())
1187 return QModelIndex();
1189 const int rowOffset = d->insertCount(item.row());
1190 return QSqlQueryModel::indexInQuery(createIndex(item.row() - rowOffset, item.column(), item.internalPointer()));
1237Qt::ItemFlags QSqlTableModel::flags(
const QModelIndex &index)
const
1239 Q_D(
const QSqlTableModel);
1240 if (index.internalPointer() || index.column() < 0 || index.column() >= d->rec.count()
1244 bool editable =
true;
1246 if (d->rec.field(index.column()).isReadOnly()) {
1250 const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(index.row());
1251 if (mrow.op() == QSqlTableModelPrivate::Delete) {
1254 else if (d->strategy == OnFieldChange) {
1255 if (mrow.op() != QSqlTableModelPrivate::Insert)
1256 if (!isDirty(index) && isDirty())
1259 else if (d->strategy == OnRowChange) {
1260 if (mrow.submitted() && isDirty())
1266 return QSqlQueryModel::flags(index);
1268 return QSqlQueryModel::flags(index) | Qt::ItemIsEditable;
1296QSqlRecord QSqlTableModel::record(
int row)
const
1298 Q_D(
const QSqlTableModel);
1301 QSqlRecord rec = QSqlQueryModel::record(row);
1304 const QSqlTableModelPrivate::ModifiedRow mrow = d->cache.value(row);
1305 if (mrow.op() != QSqlTableModelPrivate::None) {
1306 const QSqlRecord &crec = mrow.rec();
1307 for (
int i = 0, cnt = rec.count(); i < cnt; ++i)
1308 rec.setGenerated(i, crec.isGenerated(i));
1336bool QSqlTableModel::setRecord(
int row,
const QSqlRecord &values)
1338 Q_D(QSqlTableModel);
1339 Q_ASSERT_X(row >= 0,
"QSqlTableModel::setRecord()",
"Cannot set a record to a row less than 0");
1340 if (d->busyInsertingRows)
1343 if (row >= rowCount())
1346 if (d->cache.value(row).op() == QSqlTableModelPrivate::Delete)
1349 if (d->strategy != OnManualSubmit && d->cache.value(row).submitted() && isDirty())
1354 for (
int i = 0; i < values.count(); ++i) {
1355 int idx = d->nameToIndex(values.fieldName(i));
1361 QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
1362 if (mrow.op() == QSqlTableModelPrivate::None)
1363 mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
1364 QSqlQueryModel::record(row));
1366 for (
const auto i : map.asKeyValueRange()) {
1368 EditStrategy strategy = d->strategy;
1369 d->strategy = OnManualSubmit;
1370 QModelIndex cIndex = createIndex(row, i.second);
1371 setData(cIndex, values.value(i.first));
1372 d->strategy = strategy;
1374 if (!values.isGenerated(i.first))
1375 mrow.recRef().setGenerated(i.second,
false);
1378 if (d->strategy != OnManualSubmit)
1391QSqlRecord QSqlTableModel::primaryValues(
int row)
const
1393 Q_D(
const QSqlTableModel);
1395 const QSqlRecord &pIndex = d->primaryIndex.isEmpty() ? d->rec : d->primaryIndex;
1397 QSqlTableModelPrivate::ModifiedRow mr = d->cache.value(row);
1398 if (mr.op() != QSqlTableModelPrivate::None)
1399 return mr.primaryValues(pIndex);
1401 return QSqlQueryModel::record(row).keyValues(pIndex);