Update some documentation about what happens with select()/setQuery().
[qt:qt.git] / src / sql / models / qsqlquerymodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtSql module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsqlquerymodel.h"
43
44 #include <qdebug.h>
45 #include <qsqldriver.h>
46 #include <qsqlfield.h>
47
48 #include "qsqlquerymodel_p.h"
49
50 QT_BEGIN_NAMESPACE
51
52 #define QSQL_PREFETCH 255
53
54 void QSqlQueryModelPrivate::prefetch(int limit)
55 {
56     Q_Q(QSqlQueryModel);
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
89 QSqlQueryModelPrivate::~QSqlQueryModelPrivate()
90 {
91 }
92
93 void QSqlQueryModelPrivate::initColOffsets(int size)
94 {
95     colOffsets.resize(size);
96     memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int));
97 }
98
99 /*!
100     \class QSqlQueryModel
101     \brief The QSqlQueryModel class provides a read-only data model for SQL
102     result sets.
103
104     \ingroup database
105     \inmodule QtSql
106
107     QSqlQueryModel is a high-level interface for executing SQL
108     statements and traversing the result set. It is built on top of
109     the lower-level QSqlQuery and can be used to provide data to
110     view classes such as QTableView. For example:
111
112     \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 16
113
114     We set the model's query, then we set up the labels displayed in
115     the view header.
116
117     QSqlQueryModel can also be used to access a database
118     programmatically, without binding it to a view:
119
120     \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 21
121
122     The code snippet above extracts the \c salary field from record 4 in
123     the result set of the query \c{SELECT * from employee}. Assuming
124     that \c salary is column 2, we can rewrite the last line as follows:
125
126     \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 22
127
128     The model is read-only by default. To make it read-write, you
129     must subclass it and reimplement setData() and flags(). Another
130     option is to use QSqlTableModel, which provides a read-write
131     model based on a single database table.
132
133     The \l{sql/querymodel} example illustrates how to use
134     QSqlQueryModel to display the result of a query. It also shows
135     how to subclass QSqlQueryModel to customize the contents of the
136     data before showing it to the user, and how to create a
137     read-write model based on QSqlQueryModel.
138
139     If the database doesn't return the amount of selected rows in
140     a query, the model will fetch rows incrementally.
141     See fetchMore() for more information.
142
143     \sa QSqlTableModel, QSqlRelationalTableModel, QSqlQuery,
144         {Model/View Programming}, {Query Model Example}
145 */
146
147 /*!
148     Creates an empty QSqlQueryModel with the given \a parent.
149  */
150 QSqlQueryModel::QSqlQueryModel(QObject *parent)
151     : QAbstractTableModel(*new QSqlQueryModelPrivate, parent)
152 {
153 }
154
155 /*! \internal
156  */
157 QSqlQueryModel::QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent)
158     : QAbstractTableModel(dd, parent)
159 {
160 }
161
162 /*!
163     Destroys the object and frees any allocated resources.
164
165     \sa clear()
166 */
167 QSqlQueryModel::~QSqlQueryModel()
168 {
169 }
170
171 /*!
172     \since 4.1
173
174     Fetches more rows from a database.
175     This only affects databases that don't report back the size of a query
176     (see QSqlDriver::hasFeature()).
177
178     To force fetching of the entire database, you can use the following:
179
180     \snippet doc/src/snippets/code/src_sql_models_qsqlquerymodel.cpp 0
181
182     \a parent should always be an invalid QModelIndex.
183
184     \sa canFetchMore()
185 */
186 void QSqlQueryModel::fetchMore(const QModelIndex &parent)
187 {
188     Q_D(QSqlQueryModel);
189     if (parent.isValid())
190         return;
191     d->prefetch(qMax(d->bottom.row(), 0) + QSQL_PREFETCH);
192 }
193
194 /*!
195     \since 4.1
196
197     Returns true if it is possible to read more rows from the database.
198     This only affects databases that don't report back the size of a query
199     (see QSqlDriver::hasFeature()).
200
201     \a parent should always be an invalid QModelIndex.
202
203     \sa fetchMore()
204  */
205 bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const
206 {
207     Q_D(const QSqlQueryModel);
208     return (!parent.isValid() && !d->atEnd);
209 }
210
211 /*! \fn int QSqlQueryModel::rowCount(const QModelIndex &parent) const
212     \since 4.1
213
214     If the database supports returning the size of a query
215     (see QSqlDriver::hasFeature()), the amount of rows of the current
216     query is returned. Otherwise, returns the amount of rows
217     currently cached on the client.
218
219     \a parent should always be an invalid QModelIndex.
220
221     \sa canFetchMore(), QSqlDriver::hasFeature()
222  */
223 int QSqlQueryModel::rowCount(const QModelIndex &index) const
224 {
225     Q_D(const QSqlQueryModel);
226     return index.isValid() ? 0 : d->bottom.row() + 1;
227 }
228
229 /*! \reimp
230  */
231 int QSqlQueryModel::columnCount(const QModelIndex &index) const
232 {
233     Q_D(const QSqlQueryModel);
234     return index.isValid() ? 0 : d->rec.count();
235 }
236
237 /*!
238     Returns the value for the specified \a item and \a role.
239
240     If \a item is out of bounds or if an error occurred, an invalid
241     QVariant is returned.
242
243     \sa lastError()
244 */
245 QVariant QSqlQueryModel::data(const QModelIndex &item, int role) const
246 {
247     Q_D(const QSqlQueryModel);
248     if (!item.isValid())
249         return QVariant();
250
251     QVariant v;
252     if (role & ~(Qt::DisplayRole | Qt::EditRole))
253         return v;
254
255     if (!d->rec.isGenerated(item.column()))
256         return v;
257     QModelIndex dItem = indexInQuery(item);
258     if (dItem.row() > d->bottom.row())
259         const_cast<QSqlQueryModelPrivate *>(d)->prefetch(dItem.row());
260
261     if (!d->query.seek(dItem.row())) {
262         d->error = d->query.lastError();
263         return v;
264     }
265
266     return d->query.value(dItem.column());
267 }
268
269 /*!
270     Returns the header data for the given \a role in the \a section
271     of the header with the specified \a orientation.
272 */
273 QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, int role) const
274 {
275     Q_D(const QSqlQueryModel);
276     if (orientation == Qt::Horizontal) {
277         QVariant val = d->headers.value(section).value(role);
278         if (role == Qt::DisplayRole && !val.isValid())
279             val = d->headers.value(section).value(Qt::EditRole);
280         if (val.isValid())
281             return val;
282
283         // See if it's an inserted column (iiq.column() != -1)
284         QModelIndex dItem = indexInQuery(createIndex(0, section));
285
286         if (role == Qt::DisplayRole && d->rec.count() > section && dItem.column() != -1)
287             return d->rec.fieldName(section);
288     }
289     return QAbstractItemModel::headerData(section, orientation, role);
290 }
291
292 /*!
293     This virtual function is called whenever the query changes. The
294     default implementation does nothing.
295
296     query() returns the new query.
297
298     \sa query(), setQuery()
299  */
300 void QSqlQueryModel::queryChange()
301 {
302     // do nothing
303 }
304
305 /*!
306     Resets the model and sets the data provider to be the given \a
307     query. Note that the query must be active and must not be
308     isForwardOnly().
309
310     lastError() can be used to retrieve verbose information if there
311     was an error setting the query.
312
313     \note Calling setQuery() will remove any inserted columns.
314
315     \sa query(), QSqlQuery::isActive(), QSqlQuery::setForwardOnly(), lastError()
316 */
317 void QSqlQueryModel::setQuery(const QSqlQuery &query)
318 {
319     Q_D(QSqlQueryModel);
320     QSqlRecord newRec = query.record();
321     bool columnsChanged = (newRec != d->rec);
322     bool hasQuerySize = query.driver()->hasFeature(QSqlDriver::QuerySize);
323     bool hasNewData = (newRec != QSqlRecord()) || !query.lastError().isValid();
324
325     if (d->colOffsets.size() != newRec.count() || columnsChanged)
326         d->initColOffsets(newRec.count());
327
328     bool mustClearModel = d->bottom.isValid();
329     if (mustClearModel) {
330         d->atEnd = true;
331         beginRemoveRows(QModelIndex(), 0, qMax(d->bottom.row(), 0));
332         d->bottom = QModelIndex();
333     }
334
335     d->error = QSqlError();
336     d->query = query;
337     d->rec = newRec;
338
339     if (mustClearModel)
340         endRemoveRows();
341
342     d->atEnd = false;
343
344     if (columnsChanged && hasNewData)
345         reset();
346
347     if (!query.isActive() || query.isForwardOnly()) {
348         d->atEnd = true;
349         d->bottom = QModelIndex();
350         if (query.isForwardOnly())
351             d->error = QSqlError(QLatin1String("Forward-only queries "
352                                                "cannot be used in a data model"),
353                                  QString(), QSqlError::ConnectionError);
354         else
355             d->error = query.lastError();
356         return;
357     }
358     QModelIndex newBottom;
359     if (hasQuerySize && d->query.size() > 0) {
360         newBottom = createIndex(d->query.size() - 1, d->rec.count() - 1);
361         beginInsertRows(QModelIndex(), 0, qMax(0, newBottom.row()));
362         d->bottom = createIndex(d->query.size() - 1, columnsChanged ? 0 : d->rec.count() - 1);
363         d->atEnd = true;
364         endInsertRows();
365     } else {
366         newBottom = createIndex(-1, d->rec.count() - 1);
367     }
368     d->bottom = newBottom;
369
370     queryChange();
371
372     // fetchMore does the rowsInserted stuff for incremental models
373     fetchMore();
374 }
375
376 /*! \overload
377
378     Executes the query \a query for the given database connection \a
379     db. If no database is specified, the default connection is used.
380
381     lastError() can be used to retrieve verbose information if there
382     was an error setting the query.
383
384     Example:
385     \snippet doc/src/snippets/code/src_sql_models_qsqlquerymodel.cpp 1
386
387     \sa query(), queryChange(), lastError()
388 */
389 void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db)
390 {
391     setQuery(QSqlQuery(query, db));
392 }
393
394 /*!
395     Clears the model and releases any acquired resource.
396 */
397 void QSqlQueryModel::clear()
398 {
399     Q_D(QSqlQueryModel);
400     d->error = QSqlError();
401     d->atEnd = true;
402     d->query.clear();
403     d->rec.clear();
404     d->colOffsets.clear();
405     d->bottom = QModelIndex();
406     d->headers.clear();
407 }
408
409 /*!
410     Sets the caption for a horizontal header for the specified \a role to
411     \a value. This is useful if the model is used to
412     display data in a view (e.g., QTableView).
413
414     Returns true if \a orientation is Qt::Horizontal and
415     the \a section refers to a valid section; otherwise returns
416     false.
417
418     Note that this function cannot be used to modify values in the
419     database since the model is read-only.
420
421     \sa data()
422  */
423 bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation,
424                                    const QVariant &value, int role)
425 {
426     Q_D(QSqlQueryModel);
427     if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section)
428         return false;
429
430     if (d->headers.size() <= section)
431         d->headers.resize(qMax(section + 1, 16));
432     d->headers[section][role] = value;
433     emit headerDataChanged(orientation, section, section);
434     return true;
435 }
436
437 /*!
438     Returns the QSqlQuery associated with this model.
439
440     \sa setQuery()
441 */
442 QSqlQuery QSqlQueryModel::query() const
443 {
444     Q_D(const QSqlQueryModel);
445     return d->query;
446 }
447
448 /*!
449     Returns information about the last error that occurred on the
450     database.
451
452     \sa query()
453 */
454 QSqlError QSqlQueryModel::lastError() const
455 {
456     Q_D(const QSqlQueryModel);
457     return d->error;
458 }
459
460 /*!
461    Protected function which allows derived classes to set the value of
462    the last error that occurred on the database to \a error.
463
464    \sa lastError()
465 */
466 void QSqlQueryModel::setLastError(const QSqlError &error)
467 {
468     Q_D(QSqlQueryModel);
469     d->error = error;
470 }
471
472 /*!
473     Returns the record containing information about the fields of the
474     current query. If \a row is the index of a valid row, the record
475     will be populated with values from that row.
476
477     If the model is not initialized, an empty record will be
478     returned.
479
480     \sa QSqlRecord::isEmpty()
481 */
482 QSqlRecord QSqlQueryModel::record(int row) const
483 {
484     Q_D(const QSqlQueryModel);
485     if (row < 0)
486         return d->rec;
487
488     QSqlRecord rec = d->rec;
489     for (int i = 0; i < rec.count(); ++i)
490         rec.setValue(i, data(createIndex(row, i), Qt::EditRole));
491     return rec;
492 }
493
494 /*! \overload
495
496     Returns an empty record containing information about the fields
497     of the current query.
498
499     If the model is not initialized, an empty record will be
500     returned.
501
502     \sa QSqlRecord::isEmpty()
503  */
504 QSqlRecord QSqlQueryModel::record() const
505 {
506     Q_D(const QSqlQueryModel);
507     return d->rec;
508 }
509
510 /*!
511     Inserts \a count columns into the model at position \a column. The
512     \a parent parameter must always be an invalid QModelIndex, since
513     the model does not support parent-child relationships.
514
515     Returns true if \a column is within bounds; otherwise returns false.
516
517     By default, inserted columns are empty. To fill them with data,
518     reimplement data() and handle any inserted column separately:
519
520     \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 23
521
522     \sa removeColumns()
523 */
524 bool QSqlQueryModel::insertColumns(int column, int count, const QModelIndex &parent)
525 {
526     Q_D(QSqlQueryModel);
527     if (count <= 0 || parent.isValid() || column < 0 || column > d->rec.count())
528         return false;
529
530     beginInsertColumns(parent, column, column + count - 1);
531     for (int c = 0; c < count; ++c) {
532         QSqlField field;
533         field.setReadOnly(true);
534         field.setGenerated(false);
535         d->rec.insert(column, field);
536         if (d->colOffsets.size() < d->rec.count()) {
537             int nVal = d->colOffsets.isEmpty() ? 0 : d->colOffsets[d->colOffsets.size() - 1];
538             d->colOffsets.append(nVal);
539             Q_ASSERT(d->colOffsets.size() >= d->rec.count());
540         }
541         for (int i = column + 1; i < d->colOffsets.count(); ++i)
542             ++d->colOffsets[i];
543     }
544     endInsertColumns();
545     return true;
546 }
547
548 /*!
549     Removes \a count columns from the model starting from position \a
550     column. The \a parent parameter must always be an invalid
551     QModelIndex, since the model does not support parent-child
552     relationships.
553
554     Removing columns effectively hides them. It does not affect the
555     underlying QSqlQuery.
556
557     Returns true if the columns were removed; otherwise returns false.
558  */
559 bool QSqlQueryModel::removeColumns(int column, int count, const QModelIndex &parent)
560 {
561     Q_D(QSqlQueryModel);
562     if (count <= 0 || parent.isValid() || column < 0 || column >= d->rec.count())
563         return false;
564
565     beginRemoveColumns(parent, column, column + count - 1);
566
567     int i;
568     for (i = 0; i < count; ++i)
569         d->rec.remove(column);
570     for (i = column; i < d->colOffsets.count(); ++i)
571         d->colOffsets[i] -= count;
572
573     endRemoveColumns();
574     return true;
575 }
576
577 /*!
578     Returns the index of the value in the database result set for the
579     given \a item in the model.
580
581     The return value is identical to \a item if no columns or rows
582     have been inserted, removed, or moved around.
583
584     Returns an invalid model index if \a item is out of bounds or if
585     \a item does not point to a value in the result set.
586
587     \sa QSqlTableModel::indexInQuery(), insertColumns(), removeColumns()
588 */
589 QModelIndex QSqlQueryModel::indexInQuery(const QModelIndex &item) const
590 {
591     Q_D(const QSqlQueryModel);
592     if (item.column() < 0 || item.column() >= d->rec.count()
593         || !d->rec.isGenerated(item.column()))
594         return QModelIndex();
595     return createIndex(item.row(), item.column() - d->colOffsets[item.column()],
596                        item.internalPointer());
597 }
598
599 QT_END_NAMESPACE