Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsqlquerymodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsqlquerymodel.h"
5#include "qsqlquerymodel_p.h"
6
7#include <qdebug.h>
8#include <qsqldriver.h>
9#include <qsqlfield.h>
10
12
13using namespace Qt::StringLiterals;
14
15#define QSQL_PREFETCH 255
16
18{
19 Q_Q(QSqlQueryModel);
20
21 if (atEnd || limit <= bottom.row() || bottom.column() == -1)
22 return;
23
24 QModelIndex newBottom;
25 const int oldBottomRow = qMax(bottom.row(), 0);
26
27 // try to seek directly
28 if (query.seek(limit)) {
29 newBottom = q->createIndex(limit, bottom.column());
30 } else {
31 // have to seek back to our old position for MS Access
32 int i = oldBottomRow;
33 if (query.seek(i)) {
34 while (query.next())
35 ++i;
36 newBottom = q->createIndex(i, bottom.column());
37 } else {
38 // empty or invalid query
39 newBottom = q->createIndex(-1, bottom.column());
40 }
41 atEnd = true; // this is the end.
42 }
43 if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) {
44 q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());
45 bottom = newBottom;
46 q->endInsertRows();
47 } else {
48 bottom = newBottom;
49 }
50}
51
53{
54}
55
57{
59 memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int));
60}
61
62int QSqlQueryModelPrivate::columnInQuery(int modelColumn) const
63{
64 if (modelColumn < 0 || modelColumn >= rec.count() || !rec.isGenerated(modelColumn) || modelColumn >= colOffsets.size())
65 return -1;
66 return modelColumn - colOffsets[modelColumn];
67}
68
122{
123}
124
129{
130}
131
138{
139}
140
157{
158 Q_D(QSqlQueryModel);
159 if (parent.isValid())
160 return;
161 d->prefetch(qMax(d->bottom.row(), 0) + QSQL_PREFETCH);
162}
163
176{
177 Q_D(const QSqlQueryModel);
178 return (!parent.isValid() && !d->atEnd);
179}
180
199{
201 { Qt::DisplayRole, QByteArrayLiteral("display") }
202 };
203}
204
208{
209 Q_D(QSqlQueryModel);
210 if (!d->nestedResetLevel)
212}
213
217{
218 Q_D(QSqlQueryModel);
219 if (!d->nestedResetLevel)
221}
222
226{
227 Q_D(QSqlQueryModel);
228 if (!d->nestedResetLevel)
230}
231
235{
236 Q_D(QSqlQueryModel);
237 if (!d->nestedResetLevel)
239}
240
244{
245 Q_D(QSqlQueryModel);
246 if (!d->nestedResetLevel)
248}
249
253{
254 Q_D(QSqlQueryModel);
255 if (!d->nestedResetLevel)
257}
258
262{
263 Q_D(QSqlQueryModel);
264 if (!d->nestedResetLevel)
266}
267
271{
272 Q_D(QSqlQueryModel);
273 if (!d->nestedResetLevel)
275}
276
280{
281 Q_D(QSqlQueryModel);
282 if (!d->nestedResetLevel)
284 ++d->nestedResetLevel;
285}
286
290{
291 Q_D(QSqlQueryModel);
292 --d->nestedResetLevel;
293 if (!d->nestedResetLevel)
295}
296
310{
311 Q_D(const QSqlQueryModel);
312 return index.isValid() ? 0 : d->bottom.row() + 1;
313}
314
318{
319 Q_D(const QSqlQueryModel);
320 return index.isValid() ? 0 : d->rec.count();
321}
322
332{
333 Q_D(const QSqlQueryModel);
334 if (!item.isValid())
335 return QVariant();
336
337 QVariant v;
338 if (role & ~(Qt::DisplayRole | Qt::EditRole))
339 return v;
340
341 if (!d->rec.isGenerated(item.column()))
342 return v;
344 if (dItem.row() > d->bottom.row())
345 const_cast<QSqlQueryModelPrivate *>(d)->prefetch(dItem.row());
346
347 if (!d->query.seek(dItem.row())) {
348 d->error = d->query.lastError();
349 return v;
350 }
351
352 return d->query.value(dItem.column());
353}
354
359QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, int role) const
360{
361 Q_D(const QSqlQueryModel);
362 if (orientation == Qt::Horizontal) {
363 QVariant val = d->headers.value(section).value(role);
364 if (role == Qt::DisplayRole && !val.isValid())
365 val = d->headers.value(section).value(Qt::EditRole);
366 if (val.isValid())
367 return val;
368 if (role == Qt::DisplayRole && d->rec.count() > section && d->columnInQuery(section) != -1)
369 return d->rec.fieldName(section);
370 }
371 return QAbstractItemModel::headerData(section, orientation, role);
372}
373
383{
384 // do nothing
385}
386
387#if QT_DEPRECATED_SINCE(6, 2)
395{
397 setQuery(std::move(copy));
398}
399#endif // QT_DEPRECATED_SINCE(6, 2)
400
416{
417 Q_D(QSqlQueryModel);
419
420 QSqlRecord newRec = query.record();
421 bool columnsChanged = (newRec != d->rec);
422
423 if (d->colOffsets.size() != newRec.count() || columnsChanged)
424 d->initColOffsets(newRec.count());
425
426 d->bottom = QModelIndex();
427 d->error = QSqlError();
428 d->query = std::move(query);
429 d->rec = newRec;
430 d->atEnd = true;
431
432 if (d->query.isForwardOnly()) {
433 d->error = QSqlError("Forward-only queries cannot be used in a data model"_L1,
436 return;
437 }
438
439 if (!d->query.isActive()) {
440 d->error = d->query.lastError();
442 return;
443 }
444
445 if (d->query.driver()->hasFeature(QSqlDriver::QuerySize) && d->query.size() > 0) {
446 d->bottom = createIndex(d->query.size() - 1, d->rec.count() - 1);
447 } else {
448 d->bottom = createIndex(-1, d->rec.count() - 1);
449 d->atEnd = false;
450 }
451
452
453 // fetchMore does the rowsInserted stuff for incremental models
454 fetchMore();
455
457 queryChange();
458}
459
475{
477}
478
483{
484 Q_D(QSqlQueryModel);
486 d->error = QSqlError();
487 d->atEnd = true;
488 d->query.clear();
489 d->rec.clear();
490 d->colOffsets.clear();
491 d->bottom = QModelIndex();
492 d->headers.clear();
494}
495
510bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation,
511 const QVariant &value, int role)
512{
513 Q_D(QSqlQueryModel);
514 if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section)
515 return false;
516
517 if (d->headers.size() <= section)
518 d->headers.resize(qMax(section + 1, 16));
519 d->headers[section][role] = value;
520 emit headerDataChanged(orientation, section, section);
521 return true;
522}
523
530{
531 Q_D(const QSqlQueryModel);
532 return d->query;
533}
534
542{
543 Q_D(const QSqlQueryModel);
544 return d->error;
545}
546
554{
555 Q_D(QSqlQueryModel);
556 d->error = error;
557}
558
570{
571 Q_D(const QSqlQueryModel);
572 if (row < 0)
573 return d->rec;
574
575 QSqlRecord rec = d->rec;
576 for (int i = 0; i < rec.count(); ++i)
578 return rec;
579}
580
592{
593 Q_D(const QSqlQueryModel);
594 return d->rec;
595}
596
612{
613 Q_D(QSqlQueryModel);
614 if (count <= 0 || parent.isValid() || column < 0 || column > d->rec.count())
615 return false;
616
618 for (int c = 0; c < count; ++c) {
619 QSqlField field;
620 field.setReadOnly(true);
621 field.setGenerated(false);
622 d->rec.insert(column, field);
623 if (d->colOffsets.size() < d->rec.count()) {
624 int nVal = d->colOffsets.isEmpty() ? 0 : d->colOffsets[d->colOffsets.size() - 1];
625 d->colOffsets.append(nVal);
626 Q_ASSERT(d->colOffsets.size() >= d->rec.count());
627 }
628 for (int i = column + 1; i < d->colOffsets.size(); ++i)
629 ++d->colOffsets[i];
630 }
632 return true;
633}
634
647{
648 Q_D(QSqlQueryModel);
649 if (count <= 0 || parent.isValid() || column < 0 || column >= d->rec.count())
650 return false;
651
653
654 int i;
655 for (i = 0; i < count; ++i)
656 d->rec.remove(column);
657 for (i = column; i < d->colOffsets.size(); ++i)
658 d->colOffsets[i] -= count;
659
661 return true;
662}
663
677{
678 Q_D(const QSqlQueryModel);
679 int modelColumn = d->columnInQuery(item.column());
680 if (modelColumn < 0)
681 return QModelIndex();
682 return createIndex(item.row(), modelColumn, item.internalPointer());
683}
684
686
687#include "moc_qsqlquerymodel.cpp"
void endResetModel()
Completes a model reset operation.
virtual Q_INVOKABLE 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.
void endRemoveRows()
Ends a row removal operation.
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
Begins a column removal operation.
void headerDataChanged(Qt::Orientation orientation, int first, int last)
This signal is emitted whenever a header is changed.
void beginInsertColumns(const QModelIndex &parent, int first, int last)
Begins a column insertion operation.
void endInsertRows()
Ends a row insertion operation.
void beginResetModel()
Begins a model reset operation.
void endRemoveColumns()
Ends a column removal operation.
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
Creates a model index for the given row and column with the internal pointer ptr.
void endInsertColumns()
Ends a column insertion operation.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
Begins a row removal operation.
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
\inmodule QtCore
Definition qhash.h:818
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
\inmodule QtCore
Definition qobject.h:90
The QSqlDatabase class handles a connection to a database.
The QSqlError class provides SQL database error information.
Definition qsqlerror.h:17
@ ConnectionError
Definition qsqlerror.h:21
The QSqlField class manipulates the fields in SQL database tables and views.
Definition qsqlfield.h:19
void setReadOnly(bool readOnly)
Sets the read only flag of the field's value to readOnly.
void setGenerated(bool gen)
Sets the generated state.
QVarLengthArray< int, 56 > colOffsets
void initColOffsets(int size)
int columnInQuery(int modelColumn) const
The QSqlQueryModel class provides a read-only data model for SQL result sets.
void beginInsertRows(const QModelIndex &parent, int first, int last)
virtual QModelIndex indexInQuery(const QModelIndex &item) const
Returns the index of the value in the database result set for the given item in the model.
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const override
Returns the value for the specified item and role.
QSqlQueryModel(QObject *parent=nullptr)
Creates an empty QSqlQueryModel with the given parent.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
const QSqlQuery & query(QT6_DECL_NEW_OVERLOAD) const
Returns a reference to the const QSqlQuery object associated with this model.
virtual void queryChange()
This virtual function is called whenever the query changes.
void setLastError(const QSqlError &error)
Protected function which allows derived classes to set the value of the last error that occurred on t...
bool canFetchMore(const QModelIndex &parent=QModelIndex()) const override
void setQuery(QSqlQuery &&query)
Resets the model and sets the data provider to be the given query.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns the header data for the given role in the section of the header with the specified orientatio...
virtual ~QSqlQueryModel()
Destroys the object and frees any allocated resources.
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole) override
Sets the caption for a horizontal header for the specified role to value.
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
QHash< int, QByteArray > roleNames() const override
void fetchMore(const QModelIndex &parent=QModelIndex()) override
void beginInsertColumns(const QModelIndex &parent, int first, int last)
QSqlError lastError() const
Returns information about the last error that occurred on the database.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
\reimp
QSqlRecord record() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
virtual void clear()
Clears the model and releases any acquired resource.
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
Inserts count columns into the model at position column.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
Removes count columns from the model starting from position column.
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition qsqlquery.h:23
The QSqlRecord class encapsulates a database record.
Definition qsqlrecord.h:20
int count() const
Returns the number of fields in the record.
void setValue(int i, const QVariant &val)
Sets the value of the field at position index to val.
bool isGenerated(int i) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
constexpr size_type size() const noexcept
void resize(qsizetype sz)
T * data() noexcept
\inmodule QtCore
Definition qvariant.h:64
Combined button and popup list for selecting options.
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ EditRole
@ DisplayRole
static jboolean copy(JNIEnv *, jobject)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define QT_IGNORE_DEPRECATIONS(statement)
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLenum GLsizei count
GLint GLint bottom
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint first
GLenum GLenum GLsizei void GLsizei void * column
GLenum query
const GLubyte * c
GLuint GLfloat * val
GLint limit
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QSQL_PREFETCH
#define emit
#define QT6_IMPL_NEW_OVERLOAD
QMimeDatabase db
[0]
QGraphicsItem * item
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent