1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtSql module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include "qsqlquerymodel.h"
43
#include "qsqlquerymodel_p.h"
46
#include <qsqldriver.h>
47
#include <qsqlfield.h>
51
#define QSQL_PREFETCH 255
53
void QSqlQueryModelPrivate::prefetch(int limit)
57
if (atEnd || limit <= bottom.row() || bottom.column() == -1)
60
QModelIndex newBottom;
61
const int oldBottomRow = qMax(bottom.row(), 0);
63
// try to seek directly
64
if (query.seek(limit)) {
65
newBottom = q->createIndex(limit, bottom.column());
67
// have to seek back to our old position for MS Access
72
newBottom = q->createIndex(i, bottom.column());
74
// empty or invalid query
75
newBottom = q->createIndex(-1, bottom.column());
77
atEnd = true; // this is the end.
79
if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) {
80
q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());
88
QSqlQueryModelPrivate::~QSqlQueryModelPrivate()
92
void QSqlQueryModelPrivate::initColOffsets(int size)
94
colOffsets.resize(size);
95
memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int));
100
\brief The QSqlQueryModel class provides a read-only data model for SQL
106
QSqlQueryModel is a high-level interface for executing SQL
107
statements and traversing the result set. It is built on top of
108
the lower-level QSqlQuery and can be used to provide data to
109
view classes such as QTableView. For example:
111
\snippet sqldatabase/sqldatabase.cpp 16
113
We set the model's query, then we set up the labels displayed in
116
QSqlQueryModel can also be used to access a database
117
programmatically, without binding it to a view:
119
\snippet sqldatabase/sqldatabase.cpp 21
121
The code snippet above extracts the \c salary field from record 4 in
122
the result set of the query \c{SELECT * from employee}. Assuming
123
that \c salary is column 2, we can rewrite the last line as follows:
125
\snippet sqldatabase/sqldatabase.cpp 22
127
The model is read-only by default. To make it read-write, you
128
must subclass it and reimplement setData() and flags(). Another
129
option is to use QSqlTableModel, which provides a read-write
130
model based on a single database table.
132
The \l{querymodel} example illustrates how to use
133
QSqlQueryModel to display the result of a query. It also shows
134
how to subclass QSqlQueryModel to customize the contents of the
135
data before showing it to the user, and how to create a
136
read-write model based on QSqlQueryModel.
138
If the database doesn't return the number of selected rows in
139
a query, the model will fetch rows incrementally.
140
See fetchMore() for more information.
142
\sa QSqlTableModel, QSqlRelationalTableModel, QSqlQuery,
143
{Model/View Programming}, {Query Model Example}
147
Creates an empty QSqlQueryModel with the given \a parent.
149
QSqlQueryModel::QSqlQueryModel(QObject *parent)
150
: QAbstractTableModel(*new QSqlQueryModelPrivate, parent)
156
QSqlQueryModel::QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent)
157
: QAbstractTableModel(dd, parent)
162
Destroys the object and frees any allocated resources.
166
QSqlQueryModel::~QSqlQueryModel()
173
Fetches more rows from a database.
174
This only affects databases that don't report back the size of a query
175
(see QSqlDriver::hasFeature()).
177
To force fetching of the entire result set, you can use the following:
179
\snippet code/src_sql_models_qsqlquerymodel.cpp 0
181
\a parent should always be an invalid QModelIndex.
185
void QSqlQueryModel::fetchMore(const QModelIndex &parent)
188
if (parent.isValid())
190
d->prefetch(qMax(d->bottom.row(), 0) + QSQL_PREFETCH);
196
Returns true if it is possible to read more rows from the database.
197
This only affects databases that don't report back the size of a query
198
(see QSqlDriver::hasFeature()).
200
\a parent should always be an invalid QModelIndex.
204
bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const
206
Q_D(const QSqlQueryModel);
207
return (!parent.isValid() && !d->atEnd);
212
void QSqlQueryModel::beginInsertRows(const QModelIndex &parent, int first, int last)
215
if (!d->nestedResetLevel)
216
QAbstractTableModel::beginInsertRows(parent, first, last);
221
void QSqlQueryModel::endInsertRows()
224
if (!d->nestedResetLevel)
225
QAbstractTableModel::endInsertRows();
230
void QSqlQueryModel::beginRemoveRows(const QModelIndex &parent, int first, int last)
233
if (!d->nestedResetLevel)
234
QAbstractTableModel::beginRemoveRows(parent, first, last);
239
void QSqlQueryModel::endRemoveRows()
242
if (!d->nestedResetLevel)
243
QAbstractTableModel::endRemoveRows();
248
void QSqlQueryModel::beginInsertColumns(const QModelIndex &parent, int first, int last)
251
if (!d->nestedResetLevel)
252
QAbstractTableModel::beginInsertColumns(parent, first, last);
257
void QSqlQueryModel::endInsertColumns()
260
if (!d->nestedResetLevel)
261
QAbstractTableModel::endInsertColumns();
266
void QSqlQueryModel::beginRemoveColumns(const QModelIndex &parent, int first, int last)
269
if (!d->nestedResetLevel)
270
QAbstractTableModel::beginRemoveColumns(parent, first, last);
275
void QSqlQueryModel::endRemoveColumns()
278
if (!d->nestedResetLevel)
279
QAbstractTableModel::endRemoveColumns();
284
void QSqlQueryModel::beginResetModel()
287
if (!d->nestedResetLevel)
288
QAbstractTableModel::beginResetModel();
289
++d->nestedResetLevel;
294
void QSqlQueryModel::endResetModel()
297
--d->nestedResetLevel;
298
if (!d->nestedResetLevel)
299
QAbstractTableModel::endResetModel();
302
/*! \fn int QSqlQueryModel::rowCount(const QModelIndex &parent) const
305
If the database supports returning the size of a query
306
(see QSqlDriver::hasFeature()), the number of rows of the current
307
query is returned. Otherwise, returns the number of rows
308
currently cached on the client.
310
\a parent should always be an invalid QModelIndex.
312
\sa canFetchMore(), QSqlDriver::hasFeature()
314
int QSqlQueryModel::rowCount(const QModelIndex &index) const
316
Q_D(const QSqlQueryModel);
317
return index.isValid() ? 0 : d->bottom.row() + 1;
322
int QSqlQueryModel::columnCount(const QModelIndex &index) const
324
Q_D(const QSqlQueryModel);
325
return index.isValid() ? 0 : d->rec.count();
329
Returns the value for the specified \a item and \a role.
331
If \a item is out of bounds or if an error occurred, an invalid
332
QVariant is returned.
336
QVariant QSqlQueryModel::data(const QModelIndex &item, int role) const
338
Q_D(const QSqlQueryModel);
343
if (role & ~(Qt::DisplayRole | Qt::EditRole))
346
if (!d->rec.isGenerated(item.column()))
348
QModelIndex dItem = indexInQuery(item);
349
if (dItem.row() > d->bottom.row())
350
const_cast<QSqlQueryModelPrivate *>(d)->prefetch(dItem.row());
352
if (!d->query.seek(dItem.row())) {
353
d->error = d->query.lastError();
357
return d->query.value(dItem.column());
361
Returns the header data for the given \a role in the \a section
362
of the header with the specified \a orientation.
364
QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, int role) const
366
Q_D(const QSqlQueryModel);
367
if (orientation == Qt::Horizontal) {
368
QVariant val = d->headers.value(section).value(role);
369
if (role == Qt::DisplayRole && !val.isValid())
370
val = d->headers.value(section).value(Qt::EditRole);
374
// See if it's an inserted column (iiq.column() != -1)
375
QModelIndex dItem = indexInQuery(createIndex(0, section));
377
if (role == Qt::DisplayRole && d->rec.count() > section && dItem.column() != -1)
378
return d->rec.fieldName(section);
380
return QAbstractItemModel::headerData(section, orientation, role);
384
This virtual function is called whenever the query changes. The
385
default implementation does nothing.
387
query() returns the new query.
389
\sa query(), setQuery()
391
void QSqlQueryModel::queryChange()
397
Resets the model and sets the data provider to be the given \a
398
query. Note that the query must be active and must not be
401
lastError() can be used to retrieve verbose information if there
402
was an error setting the query.
404
\note Calling setQuery() will remove any inserted columns.
406
\sa query(), QSqlQuery::isActive(), QSqlQuery::setForwardOnly(), lastError()
408
void QSqlQueryModel::setQuery(const QSqlQuery &query)
413
QSqlRecord newRec = query.record();
414
bool columnsChanged = (newRec != d->rec);
416
if (d->colOffsets.size() != newRec.count() || columnsChanged)
417
d->initColOffsets(newRec.count());
419
d->bottom = QModelIndex();
420
d->error = QSqlError();
425
if (query.isForwardOnly()) {
426
d->error = QSqlError(QLatin1String("Forward-only queries "
427
"cannot be used in a data model"),
428
QString(), QSqlError::ConnectionError);
433
if (!query.isActive()) {
434
d->error = query.lastError();
439
if (query.driver()->hasFeature(QSqlDriver::QuerySize) && d->query.size() > 0) {
440
d->bottom = createIndex(d->query.size() - 1, d->rec.count() - 1);
442
d->bottom = createIndex(-1, d->rec.count() - 1);
447
// fetchMore does the rowsInserted stuff for incremental models
456
Executes the query \a query for the given database connection \a
457
db. If no database (or an invalid database) is specified, the
458
default connection is used.
460
lastError() can be used to retrieve verbose information if there
461
was an error setting the query.
464
\snippet code/src_sql_models_qsqlquerymodel.cpp 1
466
\sa query(), queryChange(), lastError()
468
void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db)
470
setQuery(QSqlQuery(query, db));
474
Clears the model and releases any acquired resource.
476
void QSqlQueryModel::clear()
479
d->error = QSqlError();
483
d->colOffsets.clear();
484
d->bottom = QModelIndex();
489
Sets the caption for a horizontal header for the specified \a role to
490
\a value. This is useful if the model is used to
491
display data in a view (e.g., QTableView).
493
Returns true if \a orientation is Qt::Horizontal and
494
the \a section refers to a valid section; otherwise returns
497
Note that this function cannot be used to modify values in the
498
database since the model is read-only.
502
bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation,
503
const QVariant &value, int role)
506
if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section)
509
if (d->headers.size() <= section)
510
d->headers.resize(qMax(section + 1, 16));
511
d->headers[section][role] = value;
512
emit headerDataChanged(orientation, section, section);
517
Returns the QSqlQuery associated with this model.
521
QSqlQuery QSqlQueryModel::query() const
523
Q_D(const QSqlQueryModel);
528
Returns information about the last error that occurred on the
533
QSqlError QSqlQueryModel::lastError() const
535
Q_D(const QSqlQueryModel);
540
Protected function which allows derived classes to set the value of
541
the last error that occurred on the database to \a error.
545
void QSqlQueryModel::setLastError(const QSqlError &error)
552
Returns the record containing information about the fields of the
553
current query. If \a row is the index of a valid row, the record
554
will be populated with values from that row.
556
If the model is not initialized, an empty record will be
559
\sa QSqlRecord::isEmpty()
561
QSqlRecord QSqlQueryModel::record(int row) const
563
Q_D(const QSqlQueryModel);
567
QSqlRecord rec = d->rec;
568
for (int i = 0; i < rec.count(); ++i)
569
rec.setValue(i, data(createIndex(row, i), Qt::EditRole));
575
Returns an empty record containing information about the fields
576
of the current query.
578
If the model is not initialized, an empty record will be
581
\sa QSqlRecord::isEmpty()
583
QSqlRecord QSqlQueryModel::record() const
585
Q_D(const QSqlQueryModel);
590
Inserts \a count columns into the model at position \a column. The
591
\a parent parameter must always be an invalid QModelIndex, since
592
the model does not support parent-child relationships.
594
Returns true if \a column is within bounds; otherwise returns false.
596
By default, inserted columns are empty. To fill them with data,
597
reimplement data() and handle any inserted column separately:
599
\snippet sqldatabase/sqldatabase.cpp 23
603
bool QSqlQueryModel::insertColumns(int column, int count, const QModelIndex &parent)
606
if (count <= 0 || parent.isValid() || column < 0 || column > d->rec.count())
609
beginInsertColumns(parent, column, column + count - 1);
610
for (int c = 0; c < count; ++c) {
612
field.setReadOnly(true);
613
field.setGenerated(false);
614
d->rec.insert(column, field);
615
if (d->colOffsets.size() < d->rec.count()) {
616
int nVal = d->colOffsets.isEmpty() ? 0 : d->colOffsets[d->colOffsets.size() - 1];
617
d->colOffsets.append(nVal);
618
Q_ASSERT(d->colOffsets.size() >= d->rec.count());
620
for (int i = column + 1; i < d->colOffsets.count(); ++i)
628
Removes \a count columns from the model starting from position \a
629
column. The \a parent parameter must always be an invalid
630
QModelIndex, since the model does not support parent-child
633
Removing columns effectively hides them. It does not affect the
634
underlying QSqlQuery.
636
Returns true if the columns were removed; otherwise returns false.
638
bool QSqlQueryModel::removeColumns(int column, int count, const QModelIndex &parent)
641
if (count <= 0 || parent.isValid() || column < 0 || column >= d->rec.count())
644
beginRemoveColumns(parent, column, column + count - 1);
647
for (i = 0; i < count; ++i)
648
d->rec.remove(column);
649
for (i = column; i < d->colOffsets.count(); ++i)
650
d->colOffsets[i] -= count;
657
Returns the index of the value in the database result set for the
658
given \a item in the model.
660
The return value is identical to \a item if no columns or rows
661
have been inserted, removed, or moved around.
663
Returns an invalid model index if \a item is out of bounds or if
664
\a item does not point to a value in the result set.
666
\sa QSqlTableModel::indexInQuery(), insertColumns(), removeColumns()
668
QModelIndex QSqlQueryModel::indexInQuery(const QModelIndex &item) const
670
Q_D(const QSqlQueryModel);
671
if (item.column() < 0 || item.column() >= d->rec.count()
672
|| !d->rec.isGenerated(item.column())
673
|| item.column() >= d->colOffsets.size())
674
return QModelIndex();
675
return createIndex(item.row(), item.column() - d->colOffsets[item.column()],
676
item.internalPointer());