Qt 4.8
qsqlquerymodel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSql module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsqlquerymodel.h"
43 
44 #include <qdebug.h>
45 #include <qsqldriver.h>
46 #include <qsqlfield.h>
47 
48 #include "qsqlquerymodel_p.h"
49 
51 
52 #define QSQL_PREFETCH 255
53 
55 {
57 
58  if (atEnd || limit <= bottom.row() || bottom.column() == -1)
59  return;
60 
61  QModelIndex newBottom;
62  const int oldBottomRow = qMax(bottom.row(), 0);
63 
64  // try to seek directly
65  if (query.seek(limit)) {
66  newBottom = q->createIndex(limit, bottom.column());
67  } else {
68  // have to seek back to our old position for MS Access
69  int i = oldBottomRow;
70  if (query.seek(i)) {
71  while (query.next())
72  ++i;
73  newBottom = q->createIndex(i, bottom.column());
74  } else {
75  // empty or invalid query
76  newBottom = q->createIndex(-1, bottom.column());
77  }
78  atEnd = true; // this is the end.
79  }
80  if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) {
81  q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());
82  bottom = newBottom;
83  q->endInsertRows();
84  } else {
85  bottom = newBottom;
86  }
87 }
88 
90 {
91 }
92 
94 {
95  colOffsets.resize(size);
96  memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int));
97 }
98 
155 {
156 }
157 
161  : QAbstractTableModel(dd, parent)
162 {
163 }
164 
171 {
172 }
173 
193 {
195  if (parent.isValid())
196  return;
197  d->prefetch(qMax(d->bottom.row(), 0) + QSQL_PREFETCH);
198 }
199 
215 {
216  Q_D(const QSqlQueryModel);
217  return (!parent.isValid() && !d->atEnd);
218 }
219 
236 {
237  Q_D(const QSqlQueryModel);
238  return index.isValid() ? 0 : d->bottom.row() + 1;
239 }
240 
244 {
245  Q_D(const QSqlQueryModel);
246  return index.isValid() ? 0 : d->rec.count();
247 }
248 
257 QVariant QSqlQueryModel::data(const QModelIndex &item, int role) const
258 {
259  Q_D(const QSqlQueryModel);
260  if (!item.isValid())
261  return QVariant();
262 
263  QVariant v;
264  if (role & ~(Qt::DisplayRole | Qt::EditRole))
265  return v;
266 
267  if (!d->rec.isGenerated(item.column()))
268  return v;
269  QModelIndex dItem = indexInQuery(item);
270  if (dItem.row() > d->bottom.row())
271  const_cast<QSqlQueryModelPrivate *>(d)->prefetch(dItem.row());
272 
273  if (!d->query.seek(dItem.row())) {
274  d->error = d->query.lastError();
275  return v;
276  }
277 
278  return d->query.value(dItem.column());
279 }
280 
285 QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, int role) const
286 {
287  Q_D(const QSqlQueryModel);
288  if (orientation == Qt::Horizontal) {
289  QVariant val = d->headers.value(section).value(role);
290  if (role == Qt::DisplayRole && !val.isValid())
291  val = d->headers.value(section).value(Qt::EditRole);
292  if (val.isValid())
293  return val;
294 
295  // See if it's an inserted column (iiq.column() != -1)
296  QModelIndex dItem = indexInQuery(createIndex(0, section));
297 
298  if (role == Qt::DisplayRole && d->rec.count() > section && dItem.column() != -1)
299  return d->rec.fieldName(section);
300  }
301  return QAbstractItemModel::headerData(section, orientation, role);
302 }
303 
313 {
314  // do nothing
315 }
316 
330 {
332  QSqlRecord newRec = query.record();
333  bool columnsChanged = (newRec != d->rec);
334  bool hasQuerySize = query.driver()->hasFeature(QSqlDriver::QuerySize);
335  bool hasNewData = (newRec != QSqlRecord()) || !query.lastError().isValid();
336 
337  if (d->colOffsets.size() != newRec.count() || columnsChanged)
338  d->initColOffsets(newRec.count());
339 
340  bool mustClearModel = d->bottom.isValid();
341  if (mustClearModel) {
342  d->atEnd = true;
343  beginRemoveRows(QModelIndex(), 0, qMax(d->bottom.row(), 0));
344  d->bottom = QModelIndex();
345  }
346 
347  d->error = QSqlError();
348  d->query = query;
349  d->rec = newRec;
350 
351  if (mustClearModel)
352  endRemoveRows();
353 
354  d->atEnd = false;
355 
356  if (columnsChanged && hasNewData)
357  reset();
358 
359  if (!query.isActive() || query.isForwardOnly()) {
360  d->atEnd = true;
361  d->bottom = QModelIndex();
362  if (query.isForwardOnly())
363  d->error = QSqlError(QLatin1String("Forward-only queries "
364  "cannot be used in a data model"),
366  else
367  d->error = query.lastError();
368  return;
369  }
370  QModelIndex newBottom;
371  if (hasQuerySize && d->query.size() > 0) {
372  newBottom = createIndex(d->query.size() - 1, d->rec.count() - 1);
373  beginInsertRows(QModelIndex(), 0, qMax(0, newBottom.row()));
374  d->bottom = createIndex(d->query.size() - 1, columnsChanged ? 0 : d->rec.count() - 1);
375  d->atEnd = true;
376  endInsertRows();
377  } else {
378  newBottom = createIndex(-1, d->rec.count() - 1);
379  }
380  d->bottom = newBottom;
381 
382  queryChange();
383 
384  // fetchMore does the rowsInserted stuff for incremental models
385  fetchMore();
386 }
387 
406 {
407  setQuery(QSqlQuery(query, db));
408 }
409 
414 {
416  d->error = QSqlError();
417  d->atEnd = true;
418  d->query.clear();
419  d->rec.clear();
420  d->colOffsets.clear();
421  d->bottom = QModelIndex();
422  d->headers.clear();
423 }
424 
439 bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation,
440  const QVariant &value, int role)
441 {
443  if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section)
444  return false;
445 
446  if (d->headers.size() <= section)
447  d->headers.resize(qMax(section + 1, 16));
448  d->headers[section][role] = value;
449  emit headerDataChanged(orientation, section, section);
450  return true;
451 }
452 
459 {
460  Q_D(const QSqlQueryModel);
461  return d->query;
462 }
463 
471 {
472  Q_D(const QSqlQueryModel);
473  return d->error;
474 }
475 
483 {
485  d->error = error;
486 }
487 
499 {
500  Q_D(const QSqlQueryModel);
501  if (row < 0)
502  return d->rec;
503 
504  QSqlRecord rec = d->rec;
505  for (int i = 0; i < rec.count(); ++i)
506  rec.setValue(i, data(createIndex(row, i), Qt::EditRole));
507  return rec;
508 }
509 
524 {
525  Q_D(const QSqlQueryModel);
526  return d->rec;
527 }
528 
543 bool QSqlQueryModel::insertColumns(int column, int count, const QModelIndex &parent)
544 {
546  if (count <= 0 || parent.isValid() || column < 0 || column > d->rec.count())
547  return false;
548 
549  beginInsertColumns(parent, column, column + count - 1);
550  for (int c = 0; c < count; ++c) {
551  QSqlField field;
552  field.setReadOnly(true);
553  field.setGenerated(false);
554  d->rec.insert(column, field);
555  if (d->colOffsets.size() < d->rec.count()) {
556  int nVal = d->colOffsets.isEmpty() ? 0 : d->colOffsets[d->colOffsets.size() - 1];
557  d->colOffsets.append(nVal);
558  Q_ASSERT(d->colOffsets.size() >= d->rec.count());
559  }
560  for (int i = column + 1; i < d->colOffsets.count(); ++i)
561  ++d->colOffsets[i];
562  }
564  return true;
565 }
566 
578 bool QSqlQueryModel::removeColumns(int column, int count, const QModelIndex &parent)
579 {
581  if (count <= 0 || parent.isValid() || column < 0 || column >= d->rec.count())
582  return false;
583 
584  beginRemoveColumns(parent, column, column + count - 1);
585 
586  int i;
587  for (i = 0; i < count; ++i)
588  d->rec.remove(column);
589  for (i = column; i < d->colOffsets.count(); ++i)
590  d->colOffsets[i] -= count;
591 
593  return true;
594 }
595 
609 {
610  Q_D(const QSqlQueryModel);
611  if (item.column() < 0 || item.column() >= d->rec.count()
612  || !d->rec.isGenerated(item.column()))
613  return QModelIndex();
614  return createIndex(item.row(), item.column() - d->colOffsets[item.column()],
615  item.internalPointer());
616 }
617 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
The QSqlError class provides SQL database error information.
Definition: qsqlerror.h:53
QModelIndex indexInQuery(const QModelIndex &item) const
Returns the index of the value in the database result set for the given item in the model...
void resize(int size)
double d
Definition: qnumeric_p.h:62
void * internalPointer() const
Returns a void * pointer used by the model to associate the index with the internal data structure...
QSqlResult * q
Definition: qsqlresult.cpp:101
const QSqlDriver * driver() const
Returns the database driver associated with the query.
Definition: qsqlquery.cpp:441
unsigned char c[8]
Definition: qnumeric_p.h:62
QSqlError lastError() const
Returns information about the last error that occurred on the database.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void beginInsertColumns(const QModelIndex &parent, int first, int last)
Begins a column insertion operation.
int rowCount(const QModelIndex &parent=QModelIndex()) const
If the database supports returning the size of a query (see QSqlDriver::hasFeature()), the number of rows of the current query is returned.
virtual bool hasFeature(DriverFeature f) const =0
Returns true if the driver supports feature feature; otherwise returns false.
void setReadOnly(bool readOnly)
Sets the read only flag of the field&#39;s value to readOnly.
Definition: qsqlfield.cpp:358
#define error(msg)
QSqlRecord record() const
Returns a QSqlRecord containing the field information for the current query.
Definition: qsqlquery.cpp:858
bool canFetchMore(const QModelIndex &parent=QModelIndex()) const
Returns true if it is possible to read more rows from the database.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition: qsqlquery.h:63
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Returns the index of the data in row and column with parent.
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
Begins a column removal operation.
The QSqlDatabase class represents a connection to a database.
Definition: qsqldatabase.h:78
QModelIndex createIndex(int row, int column, void *data=0) const
Creates a model index for the given row and column with the internal pointer ptr. ...
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QSqlRecord class encapsulates a database record.
Definition: qsqlrecord.h:58
void endInsertRows()
Ends a row insertion operation.
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isActive() const
Returns true if the query is active.
Definition: qsqlquery.cpp:785
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const
Returns the value for the specified item and role.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
virtual void queryChange()
This virtual function is called whenever the query changes.
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Returns the data for the given role and section in the header with the specified orientation.
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
#define QSQL_PREFETCH
#define Q_Q(Class)
Definition: qglobal.h:2483
QVarLengthArray< int, 56 > colOffsets
void setGenerated(bool gen)
Sets the generated state.
Definition: qsqlfield.cpp:299
int columnCount(const QModelIndex &parent=QModelIndex()) const
Reimplemented Function
The QSqlQueryModel class provides a read-only data model for SQL result sets.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QSqlQuery query() const
Returns the QSqlQuery associated with this model.
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole)
Sets the caption for a horizontal header for the specified role to value.
int row() const
Returns the row this model index refers to.
#define emit
Definition: qobjectdefs.h:76
void initColOffsets(int size)
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex())
Inserts count columns into the model at position column.
void endRemoveRows()
Ends a row removal operation.
bool isValid() const
Returns true if this model index is valid; otherwise returns false.
void setQuery(const QSqlQuery &query)
Resets the model and sets the data provider to be the given query.
int count() const
Returns the number of fields in the record.
Definition: qsqlrecord.cpp:573
QSqlError lastError() const
Returns error information about the last error (if any) that occurred with this query.
Definition: qsqlquery.cpp:754
virtual void clear()
Clears the model and releases any acquired resource.
void headerDataChanged(Qt::Orientation orientation, int first, int last)
This signal is emitted whenever a header is changed.
void setLastError(const QSqlError &error)
Protected function which allows derived classes to set the value of the last error that occurred on t...
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Returns the header data for the given role in the section of the header with the specified orientatio...
void beginRemoveRows(const QModelIndex &parent, int first, int last)
Begins a row removal operation.
The QModelIndex class is used to locate data in a data model.
QSqlRecord record() const
Returns an empty record containing information about the fields of the current query.
void endInsertColumns()
Ends a column insertion operation.
bool isForwardOnly() const
Returns true if you can only scroll forward through a result set; otherwise returns false...
Definition: qsqlquery.cpp:806
QObject * parent
Definition: qobject.h:92
bool isValid() const
Returns true if an error is set, otherwise false.
Definition: qsqlerror.cpp:254
QSqlQueryModel(QObject *parent=0)
Creates an empty QSqlQueryModel with the given parent.
bool seek(int i, bool relative=false)
Retrieves the record at position index, if available, and positions the query on the retrieved record...
Definition: qsqlquery.cpp:502
void setValue(int i, const QVariant &val)
Sets the value of the field at position index to val.
Definition: qsqlrecord.cpp:585
The QSqlField class manipulates the fields in SQL database tables and views.
Definition: qsqlfield.h:56
virtual ~QSqlQueryModel()
Destroys the object and frees any allocated resources.
bool isValid() const
Returns true if the storage type of this variant is not QVariant::Invalid; otherwise returns false...
Definition: qvariant.h:485
Orientation
Definition: qnamespace.h:174
bool next()
Retrieves the next record in the result, if available, and positions the query on the retrieved recor...
Definition: qsqlquery.cpp:594
void fetchMore(const QModelIndex &parent=QModelIndex())
Fetches more rows from a database.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
Removes count columns from the model starting from position column.
The QAbstractTableModel class provides an abstract model that can be subclassed to create table model...
void reset()
Resets the model to its original state in any attached views.
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
int size() const
int column() const
Returns the column this model index refers to.
void endRemoveColumns()
Ends a column removal operation.