summaryrefslogtreecommitdiffstats
path: root/src/sql
diff options
context:
space:
mode:
authorJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
committerJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
commit31a0358afb4fde998d1eeeaa80fc32e4420266c7 (patch)
tree938455353474196c1f49b0529b5b644e19c21f3e /src/sql
parent4c8a4058c359c8d163c643120426079fc80c8214 (diff)
parent69da8588d41bbf5ab785f5ad7c1fce76deefc7d0 (diff)
Merge remote-tracking branch 'gerrit/master' into containers
Conflicts: src/corelib/tools/qbytearray.h Change-Id: I03b1f3e05c9b7a45130887c522fcd9b7aa387129
Diffstat (limited to 'src/sql')
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp12
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp12
-rw-r--r--src/sql/drivers/sqlite2/qsql_sqlite2.cpp11
-rw-r--r--src/sql/drivers/tds/qsql_tds.cpp15
-rw-r--r--src/sql/kernel/qsqldatabase.cpp5
-rw-r--r--src/sql/models/qsqlquerymodel.h2
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp25
-rw-r--r--src/sql/models/qsqltablemodel.cpp327
-rw-r--r--src/sql/models/qsqltablemodel_p.h35
9 files changed, 213 insertions, 231 deletions
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index e3533581ba..ec31d54f0f 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -107,18 +107,10 @@
template <typename T>
inline void PQfreemem(T *t, int = 0) { free(t); }
-QT_BEGIN_NAMESPACE namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<PGconn*> {
- enum { Value = false };
-};
-} QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(PGconn*)
Q_DECLARE_METATYPE(PGconn*)
-QT_BEGIN_NAMESPACE namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<PGresult*> {
- enum { Value = false };
-};
-} QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(PGresult*)
Q_DECLARE_METATYPE(PGresult*)
QT_BEGIN_NAMESPACE
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp
index 962fc97dfc..d2dc5af070 100644
--- a/src/sql/drivers/sqlite/qsql_sqlite.cpp
+++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp
@@ -59,18 +59,10 @@
#include <sqlite3.h>
-QT_BEGIN_NAMESPACE namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<sqlite3*> {
- enum { Value = false };
-};
-} QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(sqlite3*)
Q_DECLARE_METATYPE(sqlite3*)
-QT_BEGIN_NAMESPACE namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<sqlite3_stmt*> {
- enum { Value = false };
-};
-} QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
Q_DECLARE_METATYPE(sqlite3_stmt*)
QT_BEGIN_NAMESPACE
diff --git a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
index 46127923bf..b42f82e800 100644
--- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
+++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
@@ -60,15 +60,10 @@
typedef struct sqlite_vm sqlite_vm;
-QT_BEGIN_NAMESPACE namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<sqlite_vm*> {
- enum { Value = false };
-};
-template <> struct IsPointerToTypeDerivedFromQObject<sqlite*> {
- enum { Value = false };
-};
-} QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(sqlite_vm*)
Q_DECLARE_METATYPE(sqlite_vm*)
+
+Q_DECLARE_OPAQUE_POINTER(sqlite*)
Q_DECLARE_METATYPE(sqlite*)
QT_BEGIN_NAMESPACE
diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp
index 2a97a3c392..b9414499d8 100644
--- a/src/sql/drivers/tds/qsql_tds.cpp
+++ b/src/sql/drivers/tds/qsql_tds.cpp
@@ -63,6 +63,9 @@
#include <stdlib.h>
+Q_DECLARE_OPAQUE_POINTER(LOGINREC*)
+Q_DECLARE_OPAQUE_POINTER(DBPROCESS*)
+
QT_BEGIN_NAMESPACE
#ifdef DBNTWIN32
@@ -127,18 +130,6 @@ QT_BEGIN_NAMESPACE
#define CS_PUBLIC
#endif
-namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<LOGINREC*> {
- enum { Value = false };
-};
-}
-
-namespace QtPrivate {
-template <> struct IsPointerToTypeDerivedFromQObject<DBPROCESS*> {
- enum { Value = false };
-};
-}
-
QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1)
{
return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo);
diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp
index d260588dd5..7b6a2b8c12 100644
--- a/src/sql/kernel/qsqldatabase.cpp
+++ b/src/sql/kernel/qsqldatabase.cpp
@@ -138,10 +138,7 @@ public:
driver(dr),
port(-1)
{
- if(driver)
- precisionPolicy = driver->numericalPrecisionPolicy();
- else
- precisionPolicy= QSql::LowPrecisionDouble;
+ precisionPolicy = QSql::LowPrecisionDouble;
}
QSqlDatabasePrivate(const QSqlDatabasePrivate &other);
~QSqlDatabasePrivate();
diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h
index 7db973b0d4..b5e1a7a746 100644
--- a/src/sql/models/qsqlquerymodel.h
+++ b/src/sql/models/qsqlquerymodel.h
@@ -92,7 +92,7 @@ public:
protected:
virtual void queryChange();
- QModelIndex indexInQuery(const QModelIndex &item) const;
+ virtual QModelIndex indexInQuery(const QModelIndex &item) const;
void setLastError(const QSqlError &error);
QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = 0);
};
diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp
index e12976ef24..8dd18ca1d0 100644
--- a/src/sql/models/qsqlrelationaltablemodel.cpp
+++ b/src/sql/models/qsqlrelationaltablemodel.cpp
@@ -268,7 +268,7 @@ public:
void clearCache();
void revertCachedRow(int row);
- void translateFieldNames(int row, QSqlRecord &values) const;
+ void translateFieldNames(QSqlRecord &values) const;
QSqlRelationalTableModel::JoinMode joinMode;
};
@@ -299,9 +299,7 @@ void QSqlRelationalTableModelPrivate::revertCachedRow(int row)
int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
{
- QString fieldname = name;
- if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName))
- fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
+ QString fieldname = strippedFieldName(name);
int idx = baseRec.indexOf(fieldname);
if (idx == -1) {
// If the name is an alias we can find it here.
@@ -440,9 +438,9 @@ QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) cons
//already have the correct display value.
if (d->strategy != OnFieldChange) {
const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
- if (row.op != QSqlTableModelPrivate::None && row.rec.isGenerated(index.column())) {
- if (d->strategy == OnManualSubmit || row.op != QSqlTableModelPrivate::Delete) {
- QVariant v = row.rec.value(index.column());
+ if (row.op() != QSqlTableModelPrivate::None && row.rec().isGenerated(index.column())) {
+ if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) {
+ QVariant v = row.rec().value(index.column());
if (v.isValid())
return relation.dictionary[v.toString()];
}
@@ -746,16 +744,13 @@ void QSqlRelationalTableModel::setTable(const QString &table)
/*! \internal
*/
-void QSqlRelationalTableModelPrivate::translateFieldNames(int row, QSqlRecord &values) const
+void QSqlRelationalTableModelPrivate::translateFieldNames(QSqlRecord &values) const
{
- Q_Q(const QSqlRelationalTableModel);
-
for (int i = 0; i < values.count(); ++i) {
- int realCol = q->indexInQuery(q->createIndex(row, i)).column();
- if (realCol != -1 && relations.value(realCol).isValid()) {
+ if (relations.value(i).isValid()) {
QVariant v = values.value(i);
bool gen = values.isGenerated(i);
- values.replace(i, baseRec.field(realCol));
+ values.replace(i, baseRec.field(i));
values.setValue(i, v);
values.setGenerated(i, gen);
}
@@ -770,7 +765,7 @@ bool QSqlRelationalTableModel::updateRowInTable(int row, const QSqlRecord &value
Q_D(QSqlRelationalTableModel);
QSqlRecord rec = values;
- d->translateFieldNames(row, rec);
+ d->translateFieldNames(rec);
return QSqlTableModel::updateRowInTable(row, rec);
}
@@ -783,7 +778,7 @@ bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values)
Q_D(QSqlRelationalTableModel);
QSqlRecord rec = values;
- d->translateFieldNames(0, rec);
+ d->translateFieldNames(rec);
return QSqlTableModel::insertRowIntoTable(rec);
}
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index ff32533440..932bbbfd6b 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -68,10 +68,30 @@ QSqlRecord QSqlTableModelPrivate::record(const QVector<QVariant> &values) const
int QSqlTableModelPrivate::nameToIndex(const QString &name) const
{
+ return rec.indexOf(strippedFieldName(name));
+}
+
+QString QSqlTableModelPrivate::strippedFieldName(const QString &name) const
+{
QString fieldname = name;
if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName))
fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
- return rec.indexOf(fieldname);
+ return fieldname;
+}
+
+int QSqlTableModelPrivate::insertCount(int maxRow) const
+{
+ int cnt = 0;
+ CacheMap::ConstIterator i = cache.constBegin();
+ const CacheMap::ConstIterator e = cache.constEnd();
+ for (;
+ i != e && (maxRow < 0 || i.key() <= maxRow);
+ ++i) {
+ if (i.value().op() == Insert)
+ ++cnt;
+ }
+
+ return cnt;
}
void QSqlTableModelPrivate::initRecordAndPrimaryIndex()
@@ -101,7 +121,12 @@ void QSqlTableModelPrivate::revertCachedRow(int row)
{
Q_Q(QSqlTableModel);
ModifiedRow r = cache.value(row);
- switch (r.op) {
+
+ // cannot revert a committed change
+ if (r.submitted())
+ return;
+
+ switch (r.op()) {
case QSqlTableModelPrivate::None:
Q_ASSERT_X(false, "QSqlTableModelPrivate::revertCachedRow()", "Invalid entry in cache map");
return;
@@ -174,23 +199,18 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
return true;
}
-QSqlRecord QSqlTableModelPrivate::primaryValues(int row)
+QSqlRecord QSqlTableModelPrivate::primaryValues(int row) const
{
- QSqlRecord record;
- if (!query.seek(row)) {
- error = query.lastError();
- return record;
- }
- if (primaryIndex.isEmpty()) {
- record = rec;
- for (int i = 0; i < record.count(); ++i)
- record.setValue(i, query.value(i));
- } else {
- record = primaryIndex;
- for (int i = 0; i < record.count(); ++i)
- record.setValue(i, query.value(rec.indexOf(record.fieldName(i))));
- }
- return record;
+ Q_Q(const QSqlTableModel);
+ if (cache.value(row).op() == Insert)
+ return QSqlRecord();
+
+ QSqlRecord values(primaryIndex.isEmpty() ? rec : primaryIndex);
+
+ for (int i = 0; i < values.count(); ++i)
+ values.setValue(i, q->QSqlQueryModel::data(createIndex(row, rec.indexOf(values.fieldName(i))), Qt::EditRole));
+
+ return values;
}
/*!
@@ -251,7 +271,9 @@ QSqlRecord QSqlTableModelPrivate::primaryValues(int row)
initiated in the given \a row of the currently active database
table. The \a record parameter can be written to (since it is a
reference), for example to populate some fields with default
- values.
+ values and set the generated flags of the fields. Do not try to
+ edit the record via other means such as setData() or setRecord()
+ while handling this signal.
*/
/*!
@@ -356,6 +378,12 @@ bool QSqlTableModel::select()
if (query.isEmpty())
return false;
+ // clear the submitted flags so revertAll can do its job
+ for (QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.begin();
+ it != d->cache.constEnd();
+ ++it)
+ it.value().setSubmitted(false);
+
revertAll();
QSqlQuery qu(query, d->db);
setQuery(qu);
@@ -377,38 +405,31 @@ QVariant QSqlTableModel::data(const QModelIndex &index, int role) const
if (!index.isValid() || (role != Qt::DisplayRole && role != Qt::EditRole))
return QVariant();
- // Problem.. we need to use QSQM::indexInQuery to handle inserted columns
- // but inserted rows we need to handle
- // and indexInQuery is not virtual (grrr) so any values we pass to QSQM need
- // to handle the insertedRows
- QModelIndex item = indexInQuery(index);
-
if (d->cache.contains(index.row())) {
const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
switch (d->strategy) {
case OnFieldChange:
case OnRowChange:
- if (row.op == QSqlTableModelPrivate::Insert) {
- if (item.column() < 0 || item.column() >= row.rec.count())
+ if (row.op() == QSqlTableModelPrivate::Insert) {
+ if (index.column() < 0 || index.column() >= row.rec().count())
return QVariant();
- return row.rec.value(item.column());
- } else if (row.op == QSqlTableModelPrivate::Update) {
- if (row.rec.isGenerated(item.column()))
- return row.rec.value(item.column());
+ return row.rec().value(index.column());
+ } else if (row.op() == QSqlTableModelPrivate::Update) {
+ if (row.rec().isGenerated(index.column()))
+ return row.rec().value(index.column());
}
break;
case OnManualSubmit:
- if (row.op == QSqlTableModelPrivate::Insert
- || (row.op != QSqlTableModelPrivate::None
- && row.rec.isGenerated(item.column())))
- return row.rec.value(item.column());
+ if (row.op() == QSqlTableModelPrivate::Insert
+ || (row.op() != QSqlTableModelPrivate::None
+ && row.rec().isGenerated(index.column())))
+ return row.rec().value(index.column());
break;
}
}
- // We need to handle row mapping here, but not column mapping
- return QSqlQueryModel::data(index.sibling(item.row(), index.column()), role);
+ return QSqlQueryModel::data(index, role);
}
/*!
@@ -419,7 +440,7 @@ QVariant QSqlTableModel::headerData(int section, Qt::Orientation orientation, in
Q_D(const QSqlTableModel);
if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
if (d->cache.contains(section)) {
- const QSqlTableModelPrivate::Op op = d->cache.value(section).op;
+ const QSqlTableModelPrivate::Op op = d->cache.value(section).op();
if (op == QSqlTableModelPrivate::Insert)
return QLatin1String("*");
else if (op == QSqlTableModelPrivate::Delete)
@@ -447,15 +468,15 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const
return false;
case OnRowChange: {
const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
- return row.op == QSqlTableModelPrivate::Update
- && row.rec.isGenerated(index.column());
+ return row.op() == QSqlTableModelPrivate::Update
+ && row.rec().isGenerated(index.column());
}
case OnManualSubmit: {
const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
- return row.op == QSqlTableModelPrivate::Insert
- || row.op == QSqlTableModelPrivate::Delete
- || (row.op == QSqlTableModelPrivate::Update
- && row.rec.isGenerated(index.column()));
+ return row.op() == QSqlTableModelPrivate::Insert
+ || row.op() == QSqlTableModelPrivate::Delete
+ || (row.op() == QSqlTableModelPrivate::Update
+ && row.rec().isGenerated(index.column()));
}
}
return false;
@@ -474,13 +495,16 @@ bool QSqlTableModel::isDirty(const QModelIndex &index) const
bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_D(QSqlTableModel);
+ if (d->busyInsertingRows)
+ return false;
+
if (role != Qt::EditRole)
return QSqlQueryModel::setData(index, value, role);
if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
return false;
- if (d->strategy == OnFieldChange && d->cache.value(index.row()).op != QSqlTableModelPrivate::Insert) {
+ if (d->strategy == OnFieldChange && d->cache.value(index.row()).op() != QSqlTableModelPrivate::Insert) {
d->cache.clear();
} else if (d->strategy == OnRowChange && !d->cache.isEmpty() && !d->cache.contains(index.row())) {
submit();
@@ -489,39 +513,18 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in
QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];
- if (row.op == QSqlTableModelPrivate::None) {
+ if (row.op() == QSqlTableModelPrivate::None) {
row = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
- d->rec,
- d->primaryValues(indexInQuery(index).row()));
+ d->rec);
}
row.setValue(index.column(), value);
+ emit dataChanged(index, index);
- bool isOk = true;
- if (d->strategy == OnFieldChange && row.op != QSqlTableModelPrivate::Insert) {
- // historical bug: bad style to call updateRowInTable.
- // Should call submit(), but maybe the author wanted to avoid
- // clearing the cache on failure.
- isOk = updateRowInTable(index.row(), row.rec);
- if (isOk)
- select();
- }
+ if (d->strategy == OnFieldChange && row.op() != QSqlTableModelPrivate::Insert)
+ return submit();
- // historical bug: dataChanged() is suppressed for OnFieldChange and OnRowChange
- // when operating on an "insert" record. This is to accomodate
- // applications that call setData() while handling primeInsert().
- // Otherwise dataChanged() would be emitted between beginInsert()
- // and endInsert().
- // The price of this workaround is that, although the view making
- // the change will already display the new value, other views connected
- // to the model probably will not.
- // It's not clear why OnManualSubmit is excluded from this workaround.
- // Calling setData() while handling primeInsert() is arguably very wrong anyway.
- // primeInsert() provides a ref to the record for settings values.
- if (d->strategy == OnManualSubmit || row.op != QSqlTableModelPrivate::Insert)
- emit dataChanged(index, index);
-
- return isOk;
+ return true;
}
/*!
@@ -558,7 +561,7 @@ bool QSqlTableModel::updateRowInTable(int row, const QSqlRecord &values)
QSqlRecord rec(values);
emit beforeUpdate(row, rec);
- const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
+ const QSqlRecord whereValues = d->primaryValues(row);
bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName,
rec, prepStatement);
@@ -625,7 +628,7 @@ bool QSqlTableModel::deleteRowFromTable(int row)
Q_D(QSqlTableModel);
emit beforeDelete(row);
- const QSqlRecord whereValues = d->strategy == OnManualSubmit ? d->cache[row].primaryValues : d->primaryValues(row);
+ const QSqlRecord whereValues = d->primaryValues(row);
bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries);
QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement,
d->tableName,
@@ -665,16 +668,18 @@ bool QSqlTableModel::submitAll()
{
Q_D(QSqlTableModel);
- for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
+ for (QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.begin();
it != d->cache.constEnd(); ++it) {
- switch (it.value().op) {
+ if (it.value().submitted())
+ continue;
+
+ switch (it.value().op()) {
case QSqlTableModelPrivate::Insert:
- if (!insertRowIntoTable(it.value().rec))
+ if (!insertRowIntoTable(it.value().rec()))
return false;
- d->bottom = d->bottom.sibling(d->bottom.row() + 1, d->bottom.column());
break;
case QSqlTableModelPrivate::Update:
- if (!updateRowInTable(it.key(), it.value().rec))
+ if (!updateRowInTable(it.key(), it.value().rec()))
return false;
break;
case QSqlTableModelPrivate::Delete:
@@ -685,6 +690,20 @@ bool QSqlTableModel::submitAll()
Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation");
break;
}
+ it.value().setSubmitted(true);
+ }
+
+ // all changes have been committed
+
+ // clean up inserted rows
+ QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.end();
+ while (it != d->cache.constBegin()) {
+ --it;
+ if (it.value().op() == QSqlTableModelPrivate::Insert) {
+ beginRemoveRows(QModelIndex(), it.key(), it.key());
+ it = d->cache.erase(it);
+ endRemoveRows();
+ }
}
d->clearCache();
return select();
@@ -969,13 +988,20 @@ bool QSqlTableModel::removeColumns(int column, int count, const QModelIndex &par
does not support hierarchical structures, \a parent must be
an invalid model index.
- Emits the beforeDelete() signal before a row is deleted. When
- the edit strategy is OnManualSubmit signal emission is delayed
- until submitAll() is called.
+ When the edit strategy is OnManualSubmit, deletion of rows from
+ the database is delayed until submitAll() is called; otherwise,
+ deletions are immediate.
+
+ Inserted but not yet submitted rows in the range to be removed
+ are immediately removed from the model.
- Returns true if all rows could be removed; otherwise returns
- false. Detailed error information can be retrieved using
- lastError().
+ Before a row is deleted from the database, the beforeDelete()
+ signal is emitted.
+
+ If row < 0 or row + count > rowCount(), no action is taken and
+ false is returned. Returns true if all rows could be removed;
+ otherwise returns false. Detailed database error information
+ can be retrieved using lastError().
\sa removeColumns(), insertRows()
*/
@@ -984,37 +1010,27 @@ bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
Q_D(QSqlTableModel);
if (parent.isValid() || row < 0 || count <= 0)
return false;
+ else if (row + count > rowCount())
+ return false;
+ else if (!count)
+ return true;
- int initialRowCount = rowCount();
-
- int i;
- for (i = 0; i < count && row + i < rowCount(); ++i) {
+ for (int i = 0; i < count; ++i) {
int idx = row + i;
- if (d->cache.value(idx).op == QSqlTableModelPrivate::Insert) {
+ if (d->cache.value(idx).op() == QSqlTableModelPrivate::Insert) {
revertRow(idx);
// Reverting a row means all the other cache entries have been adjusted downwards
// so fake this by adjusting row
--row;
} else {
- d->cache[idx] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete,
- QSqlRecord(),
- d->primaryValues(indexInQuery(createIndex(idx, 0)).row()));
+ d->cache[idx] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Delete);
if (d->strategy == OnManualSubmit)
emit headerDataChanged(Qt::Vertical, idx, idx);
}
}
- if (d->strategy != OnManualSubmit && i > 0)
- submit();
-
- // historical bug: emit beforeDelete for 1st row beyond end
- if (d->strategy != OnManualSubmit) {
- if (row + count > initialRowCount)
- emit beforeDelete(qMax(initialRowCount, row));
- }
-
- if (i < count)
- return false;
+ if (d->strategy != OnManualSubmit)
+ return submit();
return true;
}
@@ -1045,6 +1061,7 @@ bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
if (d->strategy != OnManualSubmit && count != 1)
return false;
+ d->busyInsertingRows = true;
beginInsertRows(parent, row, row + count - 1);
if (d->strategy != OnManualSubmit)
@@ -1063,19 +1080,22 @@ bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
for (int i = 0; i < count; ++i) {
d->cache[row + i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert,
d->rec);
- emit primeInsert(row + i, d->cache[row + i].rec);
+ emit primeInsert(row + i, d->cache[row + i].recRef());
}
endInsertRows();
+ d->busyInsertingRows = false;
return true;
}
/*!
- Inserts the \a record after \a row. If \a row is negative, the
- record will be appended to the end. Calls insertRows() and
+ Inserts the \a record at position \a row. If \a row is negative,
+ the record will be appended to the end. Calls insertRows() and
setRecord() internally.
- Returns true if the row could be inserted, otherwise false.
+ Only fields where the generated flag is true will be included.
+
+ Returns true if the record could be inserted, otherwise false.
\sa insertRows(), removeRows()
*/
@@ -1086,8 +1106,11 @@ bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record)
row = rowCount();
if (!insertRow(row, QModelIndex()))
return false;
- if (!setRecord(row, record))
+ if (!setRecord(row, record)) {
+ if (d->strategy == OnManualSubmit)
+ revertRow(row);
return false;
+ }
if (d->strategy == OnFieldChange || d->strategy == OnRowChange)
return submit();
return true;
@@ -1102,13 +1125,7 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const
if (parent.isValid())
return 0;
- int rc = QSqlQueryModel::rowCount();
- for (QSqlTableModelPrivate::CacheMap::ConstIterator it = d->cache.constBegin();
- it != d->cache.constEnd(); ++it) {
- if (it.value().op == QSqlTableModelPrivate::Insert)
- ++rc;
- }
- return rc;
+ return QSqlQueryModel::rowCount() + d->insertCount();
}
/*!
@@ -1126,15 +1143,11 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const
QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const
{
Q_D(const QSqlTableModel);
- const QModelIndex it = QSqlQueryModel::indexInQuery(item); // this adjusts columns only
- int rowOffset = 0;
- QSqlTableModelPrivate::CacheMap::ConstIterator i = d->cache.constBegin();
- while (i != d->cache.constEnd() && i.key() <= it.row()) {
- if (i.value().op == QSqlTableModelPrivate::Insert)
- ++rowOffset;
- ++i;
- }
- return createIndex(it.row() - rowOffset, it.column(), it.internalPointer());
+ if (d->cache.value(item.row()).op() == QSqlTableModelPrivate::Insert)
+ return QModelIndex();
+
+ const int rowOffset = d->insertCount(item.row());
+ return QSqlQueryModel::indexInQuery(createIndex(item.row() - rowOffset, item.column(), item.internalPointer()));
}
/*!
@@ -1192,8 +1205,10 @@ Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const
/*!
Sets the values at the specified \a row to the values of \a
- record. Returns true if all the values could be set; otherwise
- returns false.
+ record for fields where generated flag is true.
+
+ Returns true if all the values could be set; otherwise returns
+ false.
\sa record()
*/
@@ -1201,50 +1216,44 @@ bool QSqlTableModel::setRecord(int row, const QSqlRecord &record)
{
Q_D(QSqlTableModel);
Q_ASSERT_X(row >= 0, "QSqlTableModel::setRecord()", "Cannot set a record to a row less than 0");
+ if (d->busyInsertingRows)
+ return false;
+
if (row >= rowCount())
return false;
- if (d->strategy == OnFieldChange && d->cache.value(row).op != QSqlTableModelPrivate::Insert)
+ if (d->strategy == OnFieldChange && d->cache.value(row).op() != QSqlTableModelPrivate::Insert)
d->cache.clear();
else if (d->strategy == OnRowChange && !d->cache.isEmpty() && !d->cache.contains(row))
submit();
- QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
- if (mrow.op == QSqlTableModelPrivate::None)
- mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
- d->rec,
- d->primaryValues(indexInQuery(createIndex(row, 0)).row()));
-
- bool isOk = true;
+ // Check field names and remember mapping
+ typedef QMap<int, int> Map;
+ Map map;
for (int i = 0; i < record.count(); ++i) {
- int idx = d->nameToIndex(record.fieldName(i));
- if (idx == -1) {
- isOk = false;
- } else if (d->strategy != OnManualSubmit) {
- // historical bug: this could all be simple like OnManualSubmit, but isn't
- const QModelIndex cIndex = createIndex(row, idx);
- // historical bug: comparing EditRole with DisplayRole values here
- const QVariant oldValue = data(cIndex);
- const QVariant value = record.value(i);
- // historical bug: it's a bad idea to check for change here
- // historical bug: should test oldValue.isNull() != value.isNull()
- if (oldValue.isNull() || oldValue != value) {
- // historical bug: dataChanged() is suppressed for Insert. See also setData().
- mrow.setValue(idx, record.value(i));
- if (mrow.op != QSqlTableModelPrivate::Insert)
- emit dataChanged(cIndex, cIndex);
- }
- } else {
- mrow.setValue(idx, record.value(i));
+ if (record.isGenerated(i)) {
+ int idx = d->nameToIndex(record.fieldName(i));
+ if (idx == -1)
+ return false;
+ map[i] = idx;
}
}
- if (d->strategy == OnManualSubmit && isOk)
+ QSqlTableModelPrivate::ModifiedRow &mrow = d->cache[row];
+ if (mrow.op() == QSqlTableModelPrivate::None)
+ mrow = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Update,
+ d->rec);
+
+ Map::const_iterator i = map.constBegin();
+ const Map::const_iterator e = map.constEnd();
+ for ( ; i != e; ++i)
+ mrow.setValue(i.value(), record.value(i.key()));
+
+ if (columnCount())
emit dataChanged(createIndex(row, 0), createIndex(row, columnCount() - 1));
- else if (d->strategy == OnFieldChange)
- return submitAll();
- else if (d->strategy == OnManualSubmit)
- return isOk;
+
+ if (d->strategy == OnFieldChange)
+ return submit();
return true;
}
diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h
index 56fd839a0c..0ae6b53742 100644
--- a/src/sql/models/qsqltablemodel_p.h
+++ b/src/sql/models/qsqltablemodel_p.h
@@ -66,10 +66,11 @@ public:
QSqlTableModelPrivate()
: sortColumn(-1),
sortOrder(Qt::AscendingOrder),
- strategy(QSqlTableModel::OnRowChange)
+ strategy(QSqlTableModel::OnRowChange),
+ busyInsertingRows(false)
{}
void clear();
- QSqlRecord primaryValues(int index);
+ QSqlRecord primaryValues(int index) const;
virtual void clearCache();
QSqlRecord record(const QVector<QVariant> &values) const;
@@ -77,6 +78,8 @@ public:
const QSqlRecord &rec, const QSqlRecord &whereValues);
virtual void revertCachedRow(int row);
virtual int nameToIndex(const QString &name) const;
+ QString strippedFieldName(const QString &name) const;
+ int insertCount(int maxRow = -1) const;
void initRecordAndPrimaryIndex();
QSqlDatabase db;
@@ -85,6 +88,7 @@ public:
Qt::SortOrder sortOrder;
QSqlTableModel::EditStrategy strategy;
+ bool busyInsertingRows;
QSqlQuery editQuery;
QSqlIndex primaryIndex;
@@ -93,22 +97,29 @@ public:
enum Op { None, Insert, Update, Delete };
- struct ModifiedRow
+ class ModifiedRow
{
- inline ModifiedRow(Op o = None, const QSqlRecord &r = QSqlRecord(), const QSqlRecord &pVals = QSqlRecord())
- : op(o), rec(r), primaryValues(pVals)
+ public:
+ inline ModifiedRow(Op o = None, const QSqlRecord &r = QSqlRecord())
+ : m_op(o), m_rec(r), m_submitted(false)
{
- for (int i = rec.count() - 1; i >= 0; --i)
- rec.setGenerated(i, false);
+ for (int i = m_rec.count() - 1; i >= 0; --i)
+ m_rec.setGenerated(i, false);
}
+ inline Op op() const { return m_op; }
+ inline QSqlRecord rec() const { return m_rec; }
+ inline QSqlRecord& recRef() { return m_rec; }
inline void setValue(int c, const QVariant &v)
{
- rec.setValue(c, v);
- rec.setGenerated(c, true);
+ m_rec.setValue(c, v);
+ m_rec.setGenerated(c, true);
}
- Op op;
- QSqlRecord rec;
- QSqlRecord primaryValues;
+ inline bool submitted() const { return m_submitted; }
+ inline void setSubmitted(bool b) { m_submitted = b; }
+ private:
+ Op m_op;
+ QSqlRecord m_rec;
+ bool m_submitted;
};
typedef QMap<int, ModifiedRow> CacheMap;