1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsqlrelationaltablemodel.h"
41
42#include "qhash.h"
43#include "qstringlist.h"
44#include "qsqldatabase.h"
45#include "qsqldriver.h"
46#include "qsqlerror.h"
47#include "qsqlfield.h"
48#include "qsqlindex.h"
49#include "qsqlquery.h"
50#include "qsqlrecord.h"
51
52#include "qsqltablemodel_p.h"
53
54#include "qdebug.h"
55
56QT_BEGIN_NAMESPACE
57
58class QSqlRelationalTableModelSql: public QSqlTableModelSql
59{
60public:
61 inline const static QString relTablePrefix(int i) { return QString::number(i).prepend(QLatin1String("relTblAl_")); }
62};
63
64typedef QSqlRelationalTableModelSql Sql;
65
66/*!
67 \class QSqlRelation
68 \inmodule QtSql
69 \brief The QSqlRelation class stores information about an SQL foreign key.
70
71 QSqlRelation is a helper class for QSqlRelationalTableModel. See
72 QSqlRelationalTableModel::setRelation() and
73 QSqlRelationalTableModel::relation() for details.
74
75 \sa QSqlRelationalTableModel, QSqlRelationalDelegate,
76 {Relational Table Model Example}
77*/
78
79/*!
80 \fn QSqlRelation::QSqlRelation()
81
82 Constructs an invalid QSqlRelation object.
83
84 For such an object, the tableName(), indexColumn(), and
85 displayColumn() functions return an empty string.
86
87 \sa isValid()
88*/
89
90/*!
91 \fn QSqlRelation::QSqlRelation(const QString &tableName, const QString &indexColumn,
92 const QString &displayColumn)
93
94 Constructs a QSqlRelation object, where \a tableName is the SQL
95 table name to which a foreign key refers, \a indexColumn is the
96 foreign key, and \a displayColumn is the field that should be
97 presented to the user.
98
99 \sa tableName(), indexColumn(), displayColumn()
100*/
101
102/*!
103 \fn void QSqlRelation::swap(QSqlRelation &other)
104
105 Swaps \c this with \a other.
106 */
107
108/*!
109 \fn QString QSqlRelation::tableName() const
110
111 Returns the name of the table to which a foreign key refers.
112*/
113
114/*!
115 \fn QString QSqlRelation::indexColumn() const
116
117 Returns the index column from table tableName() to which a
118 foreign key refers.
119*/
120
121/*!
122 \fn QString QSqlRelation::displayColumn() const
123
124 Returns the column from table tableName() that should be
125 presented to the user instead of a foreign key.
126*/
127
128/*!
129 \fn bool QSqlRelation::isValid() const
130
131 Returns \c true if the QSqlRelation object is valid; otherwise
132 returns \c false.
133*/
134
135class QRelatedTableModel;
136
137struct QRelation
138{
139 public:
140 QRelation(): model(nullptr), m_parent(nullptr), m_dictInitialized(false) {}
141 void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation);
142
143 void populateModel();
144
145 bool isDictionaryInitialized();
146 void populateDictionary();
147 void clearDictionary();
148
149 void clear();
150 bool isValid();
151
152 QSqlRelation rel;
153 QRelatedTableModel *model;
154 QHash<QString, QVariant> dictionary;//maps keys to display values
155
156 private:
157 QSqlRelationalTableModel *m_parent;
158 bool m_dictInitialized;
159};
160
161class QRelatedTableModel : public QSqlTableModel
162{
163public:
164 QRelatedTableModel(QRelation *rel, QObject *parent = nullptr, const QSqlDatabase &db = QSqlDatabase());
165 bool select() override;
166private:
167 bool firstSelect;
168 QRelation *relation;
169};
170/*
171 A QRelation must be initialized before it is considered valid.
172 Note: population of the model and dictionary are kept separate
173 from initialization, and are populated on an as needed basis.
174*/
175void QRelation::init(QSqlRelationalTableModel *parent, const QSqlRelation &relation)
176{
177 Q_ASSERT(parent != nullptr);
178 m_parent = parent;
179 rel = relation;
180}
181
182void QRelation::populateModel()
183{
184 if (!isValid())
185 return;
186 Q_ASSERT(m_parent != nullptr);
187
188 if (!model) {
189 model = new QRelatedTableModel(this, m_parent, m_parent->database());
190 model->setTable(rel.tableName());
191 model->select();
192 }
193}
194
195bool QRelation::isDictionaryInitialized()
196{
197 return m_dictInitialized;
198}
199
200void QRelation::populateDictionary()
201{
202 if (!isValid())
203 return;
204
205 if (model == nullptr)
206 populateModel();
207
208 QSqlRecord record;
209 QString indexColumn;
210 QString displayColumn;
211 for (int i=0; i < model->rowCount(); ++i) {
212 record = model->record(i);
213
214 indexColumn = rel.indexColumn();
215 if (m_parent->database().driver()->isIdentifierEscaped(indexColumn, QSqlDriver::FieldName))
216 indexColumn = m_parent->database().driver()->stripDelimiters(indexColumn, QSqlDriver::FieldName);
217
218 displayColumn = rel.displayColumn();
219 if (m_parent->database().driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
220 displayColumn = m_parent->database().driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
221
222 dictionary[record.field(indexColumn).value().toString()] =
223 record.field(displayColumn).value();
224 }
225 m_dictInitialized = true;
226}
227
228void QRelation::clearDictionary()
229{
230 dictionary.clear();
231 m_dictInitialized = false;
232}
233
234void QRelation::clear()
235{
236 delete model;
237 model = nullptr;
238 clearDictionary();
239}
240
241bool QRelation::isValid()
242{
243 return (rel.isValid() && m_parent != nullptr);
244}
245
246
247
248QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, const QSqlDatabase &db) :
249 QSqlTableModel(parent, db), firstSelect(true), relation(rel)
250{
251}
252
253bool QRelatedTableModel::select()
254{
255 if (firstSelect) {
256 firstSelect = false;
257 return QSqlTableModel::select();
258 }
259 relation->clearDictionary();
260 bool res = QSqlTableModel::select();
261 if (res)
262 relation->populateDictionary();
263 return res;
264}
265
266
267class QSqlRelationalTableModelPrivate: public QSqlTableModelPrivate
268{
269 Q_DECLARE_PUBLIC(QSqlRelationalTableModel)
270public:
271 QSqlRelationalTableModelPrivate()
272 : QSqlTableModelPrivate(),
273 joinMode( QSqlRelationalTableModel::InnerJoin )
274 {}
275 QString fullyQualifiedFieldName(const QString &tableName, const QString &fieldName) const;
276
277 int nameToIndex(const QString &name) const override;
278 mutable QList<QRelation> relations;
279 QSqlRecord baseRec; // the record without relations
280 void clearChanges();
281 void clearCache() override;
282 void revertCachedRow(int row) override;
283
284 void translateFieldNames(QSqlRecord &values) const;
285 QSqlRelationalTableModel::JoinMode joinMode;
286};
287
288void QSqlRelationalTableModelPrivate::clearChanges()
289{
290 for (int i = 0; i < relations.count(); ++i) {
291 QRelation &rel = relations[i];
292 rel.clear();
293 }
294}
295
296void QSqlRelationalTableModelPrivate::revertCachedRow(int row)
297{
298 QSqlTableModelPrivate::revertCachedRow(row);
299}
300
301int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
302{
303 const QString fieldname = strippedFieldName(name);
304 int idx = baseRec.indexOf(fieldname);
305 if (idx == -1) {
306 // If the name is an alias we can find it here.
307 idx = QSqlTableModelPrivate::nameToIndex(name);
308 }
309 return idx;
310}
311
312void QSqlRelationalTableModelPrivate::clearCache()
313{
314 for (int i = 0; i < relations.count(); ++i)
315 relations[i].clearDictionary();
316
317 QSqlTableModelPrivate::clearCache();
318}
319
320/*!
321 \class QSqlRelationalTableModel
322 \brief The QSqlRelationalTableModel class provides an editable
323 data model for a single database table, with foreign key support.
324
325 \ingroup database
326 \inmodule QtSql
327
328 QSqlRelationalTableModel acts like QSqlTableModel, but allows
329 columns to be set as foreign keys into other database tables.
330
331 \table
332 \row \li \inlineimage noforeignkeys.png
333 \li \inlineimage foreignkeys.png
334 \endtable
335
336 The screenshot on the left shows a plain QSqlTableModel in a
337 QTableView. Foreign keys (\c city and \c country) aren't resolved
338 to human-readable values. The screenshot on the right shows a
339 QSqlRelationalTableModel, with foreign keys resolved into
340 human-readable text strings.
341
342 The following code snippet shows how the QSqlRelationalTableModel
343 was set up:
344
345 \snippet relationaltablemodel/relationaltablemodel.cpp 0
346 \codeline
347 \snippet relationaltablemodel/relationaltablemodel.cpp 1
348 \snippet relationaltablemodel/relationaltablemodel.cpp 2
349
350 The setRelation() function calls establish a relationship between
351 two tables. The first call specifies that column 2 in table \c
352 employee is a foreign key that maps with field \c id of table \c
353 city, and that the view should present the \c{city}'s \c name
354 field to the user. The second call does something similar with
355 column 3.
356
357 If you use a read-write QSqlRelationalTableModel, you probably
358 want to use QSqlRelationalDelegate on the view. Unlike the default
359 delegate, QSqlRelationalDelegate provides a combobox for fields
360 that are foreign keys into other tables. To use the class, simply
361 call QAbstractItemView::setItemDelegate() on the view with an
362 instance of QSqlRelationalDelegate:
363
364 \snippet relationaltablemodel/relationaltablemodel.cpp 4
365
366 The \l{relationaltablemodel} example illustrates how to use
367 QSqlRelationalTableModel in conjunction with
368 QSqlRelationalDelegate to provide tables with foreign key
369 support.
370
371 \image relationaltable.png
372
373 Notes:
374
375 \list
376 \li The table must have a primary key declared.
377 \li The table's primary key may not contain a relation to
378 another table.
379 \li If a relational table contains keys that refer to non-existent
380 rows in the referenced table, the rows containing the invalid
381 keys will not be exposed through the model. The user or the
382 database is responsible for keeping referential integrity.
383 \li If a relation's display column name is also used as a column
384 name in the relational table, or if it is used as display column
385 name in more than one relation it will be aliased. The alias is
386 the relation's table name, display column name and a unique id
387 joined by an underscore (e.g. tablename_columnname_id).
388 QSqlRecord::fieldName() will return the aliased column name.
389 All occurrences of the duplicate display column name are aliased when
390 duplication is detected, but no aliasing is done to the column
391 names in the main table. The aliasing doesn't affect
392 QSqlRelation, so QSqlRelation::displayColumn() will return the
393 original display column name.
394 \li The reference table name is aliased. The alias is the word "relTblAl"
395 and the relationed column index joined by an underscore
396 (e.g. relTblAl_2). The alias can be used to filter the table
397 (For example, setFilter("relTblAl_2='Oslo' OR
398 relTblAl_3='USA'")).
399 \li When using setData() the role should always be Qt::EditRole,
400 and when using data() the role should always be Qt::DisplayRole.
401 \endlist
402
403 \sa QSqlRelation, QSqlRelationalDelegate,
404 {Relational Table Model Example}
405*/
406
407
408/*!
409 Creates an empty QSqlRelationalTableModel and sets the parent to \a parent
410 and the database connection to \a db. If \a db is not valid, the
411 default database connection will be used.
412*/
413QSqlRelationalTableModel::QSqlRelationalTableModel(QObject *parent, const QSqlDatabase &db)
414 : QSqlTableModel(*new QSqlRelationalTableModelPrivate, parent, db)
415{
416}
417
418/*!
419 Destroys the object and frees any allocated resources.
420*/
421QSqlRelationalTableModel::~QSqlRelationalTableModel()
422{
423}
424
425/*!
426 \reimp
427*/
428QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role) const
429{
430 Q_D(const QSqlRelationalTableModel);
431
432 if (role == Qt::DisplayRole && index.column() >= 0 && index.column() < d->relations.count() &&
433 d->relations.value(index.column()).isValid()) {
434 QRelation &relation = d->relations[index.column()];
435 if (!relation.isDictionaryInitialized())
436 relation.populateDictionary();
437
438 //only perform a dictionary lookup for the display value
439 //when the value at index has been changed or added.
440 //At an unmodified index, the underlying model will
441 //already have the correct display value.
442 if (d->strategy != OnFieldChange) {
443 const QSqlTableModelPrivate::ModifiedRow row = d->cache.value(index.row());
444 if (row.op() != QSqlTableModelPrivate::None && row.rec().isGenerated(index.column())) {
445 if (d->strategy == OnManualSubmit || row.op() != QSqlTableModelPrivate::Delete) {
446 QVariant v = row.rec().value(index.column());
447 if (v.isValid())
448 return relation.dictionary[v.toString()];
449 }
450 }
451 }
452 }
453 return QSqlTableModel::data(index, role);
454}
455
456/*!
457 Sets the data for the \a role in the item with the specified \a
458 index to the \a value given. Depending on the edit strategy, the
459 value might be applied to the database at once, or it may be
460 cached in the model.
461
462 Returns \c true if the value could be set, or false on error (for
463 example, if \a index is out of bounds).
464
465 For relational columns, \a value must be the index, not the
466 display value. The index must also exist in the referenced
467 table, otherwise the function returns \c false.
468
469 \sa editStrategy(), data(), submit(), revertRow()
470*/
471bool QSqlRelationalTableModel::setData(const QModelIndex &index, const QVariant &value,
472 int role)
473{
474 Q_D(QSqlRelationalTableModel);
475 if ( role == Qt::EditRole && index.column() > 0 && index.column() < d->relations.count()
476 && d->relations.value(index.column()).isValid()) {
477 QRelation &relation = d->relations[index.column()];
478 if (!relation.isDictionaryInitialized())
479 relation.populateDictionary();
480 if (!relation.dictionary.contains(value.toString()))
481 return false;
482 }
483 return QSqlTableModel::setData(index, value, role);
484}
485
486/*!
487 Lets the specified \a column be a foreign index specified by \a relation.
488
489 Example:
490
491 \snippet relationaltablemodel/relationaltablemodel.cpp 0
492 \codeline
493 \snippet relationaltablemodel/relationaltablemodel.cpp 1
494
495 The setRelation() call specifies that column 2 in table \c
496 employee is a foreign key that maps with field \c id of table \c
497 city, and that the view should present the \c{city}'s \c name
498 field to the user.
499
500 Note: The table's primary key may not contain a relation to another table.
501
502 \sa relation()
503*/
504void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)
505{
506 Q_D(QSqlRelationalTableModel);
507 if (column < 0)
508 return;
509 if (d->relations.size() <= column)
510 d->relations.resize(column + 1);
511 d->relations[column].init(this, relation);
512}
513
514/*!
515 Returns the relation for the column \a column, or an invalid
516 relation if no relation is set.
517
518 \sa setRelation(), QSqlRelation::isValid()
519*/
520QSqlRelation QSqlRelationalTableModel::relation(int column) const
521{
522 Q_D(const QSqlRelationalTableModel);
523 return d->relations.value(column).rel;
524}
525
526QString QSqlRelationalTableModelPrivate::fullyQualifiedFieldName(const QString &tableName,
527 const QString &fieldName) const
528{
529 QString ret;
530 ret.reserve(tableName.size() + fieldName.size() + 1);
531 ret.append(tableName).append(QLatin1Char('.')).append(fieldName);
532
533 return ret;
534}
535
536/*!
537 \reimp
538*/
539QString QSqlRelationalTableModel::selectStatement() const
540{
541 Q_D(const QSqlRelationalTableModel);
542
543 if (tableName().isEmpty())
544 return QString();
545 if (d->relations.isEmpty())
546 return QSqlTableModel::selectStatement();
547
548 // Count how many times each field name occurs in the record
549 QHash<QString, int> fieldNames;
550 QStringList fieldList;
551 for (int i = 0; i < d->baseRec.count(); ++i) {
552 QSqlRelation relation = d->relations.value(i).rel;
553 QString name;
554 if (relation.isValid()) {
555 // Count the display column name, not the original foreign key
556 name = relation.displayColumn();
557 if (d->db.driver()->isIdentifierEscaped(name, QSqlDriver::FieldName))
558 name = d->db.driver()->stripDelimiters(name, QSqlDriver::FieldName);
559
560 const QSqlRecord rec = database().record(relation.tableName());
561 for (int i = 0; i < rec.count(); ++i) {
562 if (name.compare(rec.fieldName(i), Qt::CaseInsensitive) == 0) {
563 name = rec.fieldName(i);
564 break;
565 }
566 }
567 }
568 else {
569 name = d->baseRec.fieldName(i);
570 }
571 fieldNames[name] = fieldNames.value(name, 0) + 1;
572 fieldList.append(name);
573 }
574
575 QString fList;
576 QString conditions;
577 QString from = Sql::from(tableName());
578 for (int i = 0; i < d->baseRec.count(); ++i) {
579 QSqlRelation relation = d->relations.value(i).rel;
580 const QString tableField = d->fullyQualifiedFieldName(tableName(), d->db.driver()->escapeIdentifier(d->baseRec.fieldName(i), QSqlDriver::FieldName));
581 if (relation.isValid()) {
582 const QString relTableAlias = Sql::relTablePrefix(i);
583 QString displayTableField = d->fullyQualifiedFieldName(relTableAlias, relation.displayColumn());
584
585 // Duplicate field names must be aliased
586 if (fieldNames.value(fieldList[i]) > 1) {
587 QString relTableName = relation.tableName().section(QChar::fromLatin1('.'), -1, -1);
588 if (d->db.driver()->isIdentifierEscaped(relTableName, QSqlDriver::TableName))
589 relTableName = d->db.driver()->stripDelimiters(relTableName, QSqlDriver::TableName);
590 QString displayColumn = relation.displayColumn();
591 if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
592 displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
593 QString alias = QString::fromLatin1("%1_%2_%3")
594 .arg(relTableName, displayColumn, QString::number(fieldNames.value(fieldList[i])));
595 alias.truncate(d->db.driver()->maximumIdentifierLength(QSqlDriver::FieldName));
596 displayTableField = Sql::as(displayTableField, alias);
597 --fieldNames[fieldList[i]];
598 }
599
600 fList = Sql::comma(fList, displayTableField);
601
602 // Join related table
603 const QString tblexpr = Sql::concat(relation.tableName(), relTableAlias);
604 const QString relTableField = d->fullyQualifiedFieldName(relTableAlias, relation.indexColumn());
605 const QString cond = Sql::eq(tableField, relTableField);
606 if (d->joinMode == QSqlRelationalTableModel::InnerJoin) {
607 // FIXME: InnerJoin code is known to be broken.
608 // Use LeftJoin mode if you want correct behavior.
609 from = Sql::comma(from, tblexpr);
610 conditions = Sql::et(conditions, cond);
611 } else {
612 from = Sql::concat(from, Sql::leftJoin(tblexpr));
613 from = Sql::concat(from, Sql::on(cond));
614 }
615 } else {
616 fList = Sql::comma(fList, tableField);
617 }
618 }
619
620 if (fList.isEmpty())
621 return QString();
622
623 const QString stmt = Sql::concat(Sql::select(fList), from);
624 const QString where = Sql::where(Sql::et(Sql::paren(conditions), Sql::paren(filter())));
625 return Sql::concat(Sql::concat(stmt, where), orderByClause());
626}
627
628/*!
629 Returns a QSqlTableModel object for accessing the table for which
630 \a column is a foreign key, or \nullptr if there is no relation for
631 the given \a column.
632
633 The returned object is owned by the QSqlRelationalTableModel.
634
635 \sa setRelation(), relation()
636*/
637QSqlTableModel *QSqlRelationalTableModel::relationModel(int column) const
638{
639 Q_D(const QSqlRelationalTableModel);
640 if (column < 0 || column >= d->relations.count())
641 return nullptr;
642
643 QRelation &relation = const_cast<QSqlRelationalTableModelPrivate *>(d)->relations[column];
644 if (!relation.isValid())
645 return nullptr;
646
647 if (!relation.model)
648 relation.populateModel();
649 return relation.model;
650}
651
652/*!
653 \reimp
654*/
655void QSqlRelationalTableModel::revertRow(int row)
656{
657 QSqlTableModel::revertRow(row);
658}
659
660/*!
661 \reimp
662*/
663void QSqlRelationalTableModel::clear()
664{
665 Q_D(QSqlRelationalTableModel);
666 beginResetModel();
667 d->clearChanges();
668 d->relations.clear();
669 QSqlTableModel::clear();
670 endResetModel();
671}
672
673
674/*! \enum QSqlRelationalTableModel::JoinMode
675
676 \value InnerJoin - Inner join mode, return rows when there is at least one match in both tables.
677 \value LeftJoin - Left join mode, returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2).
678
679 \sa QSqlRelationalTableModel::setJoinMode()
680 \since 4.8
681*/
682
683/*!
684 Sets the SQL \a joinMode to show or hide rows with NULL foreign keys.
685 In InnerJoin mode (the default) these rows will not be shown: use the
686 LeftJoin mode if you want to show them.
687
688 \sa QSqlRelationalTableModel::JoinMode
689 \since 4.8
690*/
691void QSqlRelationalTableModel::setJoinMode( QSqlRelationalTableModel::JoinMode joinMode )
692{
693 Q_D(QSqlRelationalTableModel);
694 d->joinMode = joinMode;
695}
696/*!
697 \reimp
698*/
699bool QSqlRelationalTableModel::select()
700{
701 return QSqlTableModel::select();
702}
703
704/*!
705 \reimp
706*/
707void QSqlRelationalTableModel::setTable(const QString &table)
708{
709 Q_D(QSqlRelationalTableModel);
710
711 // memorize the table before applying the relations
712 d->baseRec = d->db.record(table);
713
714 QSqlTableModel::setTable(table);
715}
716
717/*! \internal
718 */
719void QSqlRelationalTableModelPrivate::translateFieldNames(QSqlRecord &values) const
720{
721 for (int i = 0; i < values.count(); ++i) {
722 if (relations.value(i).isValid()) {
723 QVariant v = values.value(i);
724 bool gen = values.isGenerated(i);
725 values.replace(i, baseRec.field(i));
726 values.setValue(i, v);
727 values.setGenerated(i, gen);
728 }
729 }
730}
731
732/*!
733 \reimp
734*/
735bool QSqlRelationalTableModel::updateRowInTable(int row, const QSqlRecord &values)
736{
737 Q_D(QSqlRelationalTableModel);
738
739 QSqlRecord rec = values;
740 d->translateFieldNames(rec);
741
742 return QSqlTableModel::updateRowInTable(row, rec);
743}
744
745/*!
746 \reimp
747*/
748bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values)
749{
750 Q_D(QSqlRelationalTableModel);
751
752 QSqlRecord rec = values;
753 d->translateFieldNames(rec);
754
755 return QSqlTableModel::insertRowIntoTable(rec);
756}
757
758/*!
759 \reimp
760*/
761QString QSqlRelationalTableModel::orderByClause() const
762{
763 Q_D(const QSqlRelationalTableModel);
764
765 const QSqlRelation rel = d->relations.value(d->sortColumn).rel;
766 if (!rel.isValid())
767 return QSqlTableModel::orderByClause();
768
769 QString f = d->fullyQualifiedFieldName(Sql::relTablePrefix(d->sortColumn), rel.displayColumn());
770 f = d->sortOrder == Qt::AscendingOrder ? Sql::asc(f) : Sql::desc(f);
771 return Sql::orderBy(f);
772}
773
774/*!
775 \reimp
776*/
777bool QSqlRelationalTableModel::removeColumns(int column, int count, const QModelIndex &parent)
778{
779 Q_D(QSqlRelationalTableModel);
780
781 if (parent.isValid() || column < 0 || column + count > d->rec.count())
782 return false;
783
784 for (int i = 0; i < count; ++i) {
785 d->baseRec.remove(column);
786 if (d->relations.count() > column)
787 d->relations.remove(column);
788 }
789 return QSqlTableModel::removeColumns(column, count, parent);
790}
791
792QT_END_NAMESPACE
793