diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2012-03-23 13:36:29 +0100 |
---|---|---|
committer | Kent Hansen <kent.hansen@nokia.com> | 2012-03-23 14:10:58 +0100 |
commit | 3b512ae142017f105f297467f74dc28d3cb9030a (patch) | |
tree | 9e131e23c01537f051851a1da9576c1e1ddf5ba2 /src/sql | |
parent | e20c4730192f312881591fb50e571af0a88fe421 (diff) | |
parent | f956f9a83603a3df5651e3238c24e8df37558d6e (diff) |
Merge master into api_changes
Change-Id: I93551e4d13a1b0815b359b9415060e9089477db1
Diffstat (limited to 'src/sql')
-rw-r--r-- | src/sql/models/qsqlquerymodel_p.h | 39 | ||||
-rw-r--r-- | src/sql/models/qsqlrelationaltablemodel.cpp | 149 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel.cpp | 101 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel_p.h | 5 |
4 files changed, 141 insertions, 153 deletions
diff --git a/src/sql/models/qsqlquerymodel_p.h b/src/sql/models/qsqlquerymodel_p.h index b5eb60c57d..6e0349f032 100644 --- a/src/sql/models/qsqlquerymodel_p.h +++ b/src/sql/models/qsqlquerymodel_p.h @@ -82,6 +82,45 @@ public: QVarLengthArray<int, 56> colOffsets; // used to calculate indexInQuery of columns }; +// helpers for building SQL expressions +class QSqlQueryModelSql +{ +public: + // SQL keywords + inline const static QLatin1String as() { return QLatin1String("AS"); } + inline const static QLatin1String asc() { return QLatin1String("ASC"); } + inline const static QLatin1String comma() { return QLatin1String(","); } + inline const static QLatin1String desc() { return QLatin1String("DESC"); } + inline const static QLatin1String eq() { return QLatin1String("="); } + // "and" is a C++ keyword + inline const static QLatin1String et() { return QLatin1String("AND"); } + inline const static QLatin1String from() { return QLatin1String("FROM"); } + inline const static QLatin1String leftJoin() { return QLatin1String("LEFT JOIN"); } + inline const static QLatin1String on() { return QLatin1String("ON"); } + inline const static QLatin1String orderBy() { return QLatin1String("ORDER BY"); } + inline const static QLatin1String parenClose() { return QLatin1String(")"); } + inline const static QLatin1String parenOpen() { return QLatin1String("("); } + inline const static QLatin1String select() { return QLatin1String("SELECT"); } + inline const static QLatin1String sp() { return QLatin1String(" "); } + inline const static QLatin1String where() { return QLatin1String("WHERE"); } + + // Build expressions based on key words + inline const static QString as(const QString &a, const QString &b) { return b.isEmpty() ? a : concat(concat(a, as()), b); } + inline const static QString asc(const QString &s) { return concat(s, asc()); } + inline const static QString comma(const QString &a, const QString &b) { return a.isEmpty() ? b : b.isEmpty() ? a : QString(a).append(comma()).append(b); } + inline const static QString concat(const QString &a, const QString &b) { return a.isEmpty() ? b : b.isEmpty() ? a : QString(a).append(sp()).append(b); } + inline const static QString desc(const QString &s) { return concat(s, desc()); } + inline const static QString eq(const QString &a, const QString &b) { return QString(a).append(eq()).append(b); } + inline const static QString et(const QString &a, const QString &b) { return a.isEmpty() ? b : b.isEmpty() ? a : concat(concat(a, et()), b); } + inline const static QString from(const QString &s) { return concat(from(), s); } + inline const static QString leftJoin(const QString &s) { return concat(leftJoin(), s); } + inline const static QString on(const QString &s) { return concat(on(), s); } + inline const static QString orderBy(const QString &s) { return s.isEmpty() ? s : concat(orderBy(), s); } + inline const static QString paren(const QString &s) { return s.isEmpty() ? s : parenOpen() + s + parenClose(); } + inline const static QString select(const QString &s) { return concat(select(), s); } + inline const static QString where(const QString &s) { return s.isEmpty() ? s : concat(where(), s); } +}; + QT_END_NAMESPACE #endif // QSQLQUERYMODEL_P_H diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index 3a521deea2..0387e5691f 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -57,6 +57,14 @@ QT_BEGIN_NAMESPACE +class QSqlRelationalTableModelSql: public QSqlTableModelSql +{ +public: + inline const static QString relTablePrefix(int i) { return QString::number(i).prepend(QLatin1String("relTblAl_")); } +}; + +typedef QSqlRelationalTableModelSql Sql; + /*! \class QSqlRelation \brief The QSqlRelation class stores information about an SQL foreign key. @@ -124,7 +132,7 @@ class QRelatedTableModel; struct QRelation { public: - QRelation(): model(0),m_parent(0),m_dictInitialized(false){} + QRelation(): model(0), m_parent(0), m_dictInitialized(false) {} void init(QSqlRelationalTableModel *parent, const QSqlRelation &relation); void populateModel(); @@ -259,7 +267,7 @@ public: : QSqlTableModelPrivate(), joinMode( QSqlRelationalTableModel::InnerJoin ) {} - QString relationField(const QString &tableName, const QString &fieldName) const; + QString fullyQualifiedFieldName(const QString &tableName, const QString &fieldName) const; int nameToIndex(const QString &name) const; mutable QVector<QRelation> relations; @@ -272,18 +280,6 @@ public: QSqlRelationalTableModel::JoinMode joinMode; }; -static void qAppendWhereClause(QString &query, const QString &clause1, const QString &clause2) -{ - if (clause1.isEmpty() && clause2.isEmpty()) - return; - if (clause1.isEmpty() || clause2.isEmpty()) - query.append(QLatin1String(" WHERE (")).append(clause1).append(clause2); - else - query.append(QLatin1String(" WHERE (")).append(clause1).append( - QLatin1String(") AND (")).append(clause2); - query.append(QLatin1String(") ")); -} - void QSqlRelationalTableModelPrivate::clearChanges() { for (int i = 0; i < relations.count(); ++i) { @@ -299,7 +295,7 @@ void QSqlRelationalTableModelPrivate::revertCachedRow(int row) int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const { - QString fieldname = strippedFieldName(name); + const QString fieldname = strippedFieldName(name); int idx = baseRec.indexOf(fieldname); if (idx == -1) { // If the name is an alias we can find it here. @@ -520,8 +516,8 @@ QSqlRelation QSqlRelationalTableModel::relation(int column) const return d->relations.value(column).rel; } -QString QSqlRelationalTableModelPrivate::relationField(const QString &tableName, - const QString &fieldName) const +QString QSqlRelationalTableModelPrivate::fullyQualifiedFieldName(const QString &tableName, + const QString &fieldName) const { QString ret; ret.reserve(tableName.size() + fieldName.size() + 1); @@ -536,35 +532,25 @@ QString QSqlRelationalTableModelPrivate::relationField(const QString &tableName, QString QSqlRelationalTableModel::selectStatement() const { Q_D(const QSqlRelationalTableModel); - QString query; if (tableName().isEmpty()) - return query; + return QString(); if (d->relations.isEmpty()) return QSqlTableModel::selectStatement(); - QString tList; - QString fList; - QString where; - - QSqlRecord rec = d->baseRec; - QStringList tables; - const QRelation nullRelation; - // Count how many times each field name occurs in the record QHash<QString, int> fieldNames; QStringList fieldList; - for (int i = 0; i < rec.count(); ++i) { - QSqlRelation relation = d->relations.value(i, nullRelation).rel; + for (int i = 0; i < d->baseRec.count(); ++i) { + QSqlRelation relation = d->relations.value(i).rel; QString name; - if (relation.isValid()) - { + if (relation.isValid()) { // Count the display column name, not the original foreign key name = relation.displayColumn(); if (d->db.driver()->isIdentifierEscaped(name, QSqlDriver::FieldName)) name = d->db.driver()->stripDelimiters(name, QSqlDriver::FieldName); - QSqlRecord rec = database().record(relation.tableName()); + const QSqlRecord rec = database().record(relation.tableName()); for (int i = 0; i < rec.count(); ++i) { if (name.compare(rec.fieldName(i), Qt::CaseInsensitive) == 0) { name = rec.fieldName(i); @@ -572,21 +558,24 @@ QString QSqlRelationalTableModel::selectStatement() const } } } - else - name = rec.fieldName(i); - fieldNames.insert(name, fieldNames.value(name, 0) + 1); + else { + name = d->baseRec.fieldName(i); + } + fieldNames[name] = fieldNames.value(name, 0) + 1; fieldList.append(name); } - for (int i = 0; i < rec.count(); ++i) { - QSqlRelation relation = d->relations.value(i, nullRelation).rel; + QString fList; + QString conditions; + QString from = Sql::from(tableName()); + for (int i = 0; i < d->baseRec.count(); ++i) { + QSqlRelation relation = d->relations.value(i).rel; + const QString tableField = d->fullyQualifiedFieldName(tableName(), d->db.driver()->escapeIdentifier(d->baseRec.fieldName(i), QSqlDriver::FieldName)); if (relation.isValid()) { - QString relTableAlias = QString::fromLatin1("relTblAl_%1").arg(i); - if (!fList.isEmpty()) - fList.append(QLatin1String(", ")); - fList.append(d->relationField(relTableAlias,relation.displayColumn())); + const QString relTableAlias = Sql::relTablePrefix(i); + QString displayTableField = d->fullyQualifiedFieldName(relTableAlias, relation.displayColumn()); - // If there are duplicate field names they must be aliased + // Duplicate field names must be aliased if (fieldNames.value(fieldList[i]) > 1) { QString relTableName = relation.tableName().section(QChar::fromLatin1('.'), -1, -1); if (d->db.driver()->isIdentifierEscaped(relTableName, QSqlDriver::TableName)) @@ -594,65 +583,37 @@ QString QSqlRelationalTableModel::selectStatement() const QString displayColumn = relation.displayColumn(); if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName)) displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName); - fList.append(QString::fromLatin1(" AS %1_%2_%3").arg(relTableName).arg(displayColumn).arg(fieldNames.value(fieldList[i]))); - fieldNames.insert(fieldList[i], fieldNames.value(fieldList[i])-1); + const QString alias = QString::fromLatin1("%1_%2_%3").arg(relTableName).arg(displayColumn).arg(fieldNames.value(fieldList[i])); + displayTableField = Sql::as(displayTableField, alias); + --fieldNames[fieldList[i]]; } + fList = Sql::comma(fList, displayTableField); + + // Join related table + const QString tblexpr = Sql::concat(relation.tableName(), relTableAlias); + const QString relTableField = d->fullyQualifiedFieldName(relTableAlias, relation.indexColumn()); + const QString cond = Sql::eq(tableField, relTableField); if (d->joinMode == QSqlRelationalTableModel::InnerJoin) { - // this needs fixing!! the below if is borken. - // Use LeftJoin mode if you want correct behavior - tables.append(relation.tableName().append(QLatin1Char(' ')).append(relTableAlias)); - if(!where.isEmpty()) - where.append(QLatin1String(" AND ")); - where.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName))); - where.append(QLatin1String(" = ")); - where.append(d->relationField(relTableAlias, relation.indexColumn())); + // FIXME: InnerJoin code is known to be broken. + // Use LeftJoin mode if you want correct behavior. + from = Sql::comma(from, tblexpr); + conditions = Sql::et(conditions, cond); } else { - tables.append(QLatin1String(" LEFT JOIN")); - tables.append(relation.tableName().append(QLatin1Char(' ')).append(relTableAlias)); - tables.append(QLatin1String("ON")); - - QString clause; - clause.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName))); - clause.append(QLatin1String(" = ")); - clause.append(d->relationField(relTableAlias, relation.indexColumn())); - - tables.append(clause); + from = Sql::concat(from, Sql::leftJoin(tblexpr)); + from = Sql::concat(from, Sql::on(cond)); } } else { - if (!fList.isEmpty()) - fList.append(QLatin1String(", ")); - fList.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName))); + fList = Sql::comma(fList, tableField); } } - if (d->joinMode == QSqlRelationalTableModel::InnerJoin && !tables.isEmpty()) { - tList.append(tables.join(QLatin1String(", "))); - if(!tList.isEmpty()) - tList.prepend(QLatin1String(", ")); - } else - tList.append(tables.join(QLatin1String(" "))); - if (fList.isEmpty()) - return query; - - tList.prepend(tableName()); - query.append(QLatin1String("SELECT ")); - query.append(fList).append(QLatin1String(" FROM ")).append(tList); - - if (d->joinMode == QSqlRelationalTableModel::InnerJoin) { - qAppendWhereClause(query, where, filter()); - } else if (!filter().isEmpty()) { - query.append(QLatin1String(" WHERE (")); - query.append(filter()); - query.append(QLatin1String(")")); - } - - QString orderBy = orderByClause(); - if (!orderBy.isEmpty()) - query.append(QLatin1Char(' ')).append(orderBy); + return QString(); - return query; + const QString stmt = Sql::concat(Sql::select(fList), from); + const QString where = Sql::where(Sql::et(Sql::paren(conditions), Sql::paren(filter()))); + return Sql::concat(Sql::concat(stmt, where), orderByClause()); } /*! @@ -794,11 +755,9 @@ QString QSqlRelationalTableModel::orderByClause() const if (!rel.isValid()) return QSqlTableModel::orderByClause(); - QString s = QLatin1String("ORDER BY "); - s.append(d->relationField(QLatin1String("relTblAl_") + QString::number(d->sortColumn), - rel.displayColumn())); - s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC"); - return s; + QString f = d->fullyQualifiedFieldName(Sql::relTablePrefix(d->sortColumn), rel.displayColumn()); + f = d->sortOrder == Qt::AscendingOrder ? Sql::asc(f) : Sql::desc(f); + return Sql::orderBy(f); } /*! diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index d8d691fa0c..20d2be36e1 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE +typedef QSqlTableModelSql Sql; + /*! \internal Populates our record with values. */ @@ -84,12 +86,9 @@ int QSqlTableModelPrivate::insertCount(int maxRow) const int cnt = 0; CacheMap::ConstIterator i = cache.constBegin(); const CacheMap::ConstIterator e = cache.constEnd(); - for (; - i != e && (maxRow < 0 || i.key() <= maxRow); - ++i) { + for ( ; i != e && (maxRow < 0 || i.key() <= maxRow); ++i) if (i.value().insert()) ++cnt; - } return cnt; } @@ -175,14 +174,12 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement, } } int i; - for (i = 0; i < rec.count(); ++i) { + for (i = 0; i < rec.count(); ++i) if (rec.isGenerated(i)) editQuery.addBindValue(rec.value(i)); - } - for (i = 0; i < whereValues.count(); ++i) { + for (i = 0; i < whereValues.count(); ++i) if (whereValues.isGenerated(i) && !whereValues.isNull(i)) editQuery.addBindValue(whereValues.value(i)); - } if (!editQuery.exec()) { error = editQuery.lastError(); @@ -363,7 +360,7 @@ QString QSqlTableModel::tableName() const bool QSqlTableModel::select() { Q_D(QSqlTableModel); - QString query = selectStatement(); + const QString query = selectStatement(); if (query.isEmpty()) return false; @@ -416,8 +413,9 @@ bool QSqlTableModel::selectRow(int row) d->tableName, d->primaryValues(row), false); - if (d->filter.startsWith(QLatin1String("WHERE "), Qt::CaseInsensitive)) - d->filter.remove(0, 6); + static const QString wh = Sql::where() + Sql::sp(); + if (d->filter.startsWith(wh, Qt::CaseInsensitive)) + d->filter.remove(0, wh.length()); const QString stmt = selectStatement(); d->sortColumn = table_sort_col; d->filter = table_filter; @@ -593,20 +591,19 @@ bool QSqlTableModel::updateRowInTable(int row, const QSqlRecord &values) emit beforeUpdate(row, rec); const QSqlRecord whereValues = d->primaryValues(row); - bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); - QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName, - rec, prepStatement); - QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, d->tableName, - whereValues, prepStatement); + const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); + const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::UpdateStatement, d->tableName, + rec, prepStatement); + const QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, d->tableName, + whereValues, prepStatement); if (stmt.isEmpty() || where.isEmpty() || row < 0 || row >= rowCount()) { d->error = QSqlError(QLatin1String("No Fields to update"), QString(), QSqlError::StatementError); return false; } - stmt.append(QLatin1Char(' ')).append(where); - return d->exec(stmt, prepStatement, rec, whereValues); + return d->exec(Sql::concat(stmt, where), prepStatement, rec, whereValues); } @@ -629,9 +626,9 @@ bool QSqlTableModel::insertRowIntoTable(const QSqlRecord &values) QSqlRecord rec = values; emit beforeInsert(rec); - bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); - QString stmt = d->db.driver()->sqlStatement(QSqlDriver::InsertStatement, d->tableName, - rec, prepStatement); + const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); + const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::InsertStatement, d->tableName, + rec, prepStatement); if (stmt.isEmpty()) { d->error = QSqlError(QLatin1String("No Fields to update"), QString(), @@ -660,24 +657,23 @@ bool QSqlTableModel::deleteRowFromTable(int row) emit beforeDelete(row); const QSqlRecord whereValues = d->primaryValues(row); - bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); - QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement, - d->tableName, - QSqlRecord(), - prepStatement); - QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, - d->tableName, - whereValues, - prepStatement); + const bool prepStatement = d->db.driver()->hasFeature(QSqlDriver::PreparedQueries); + const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::DeleteStatement, + d->tableName, + QSqlRecord(), + prepStatement); + const QString where = d->db.driver()->sqlStatement(QSqlDriver::WhereStatement, + d->tableName, + whereValues, + prepStatement); if (stmt.isEmpty() || where.isEmpty()) { d->error = QSqlError(QLatin1String("Unable to delete row"), QString(), QSqlError::StatementError); return false; } - stmt.append(QLatin1Char(' ')).append(where); - return d->exec(stmt, prepStatement, QSqlRecord() /* no new values */, whereValues); + return d->exec(Sql::concat(stmt, where), prepStatement, QSqlRecord() /* no new values */, whereValues); } /*! @@ -838,9 +834,8 @@ void QSqlTableModel::revertAll() Q_D(QSqlTableModel); const QList<int> rows(d->cache.keys()); - for (int i = rows.size() - 1; i >= 0; --i) { + for (int i = rows.size() - 1; i >= 0; --i) revertRow(rows.value(i)); - } } /*! @@ -929,19 +924,16 @@ void QSqlTableModel::setSort(int column, Qt::SortOrder order) QString QSqlTableModel::orderByClause() const { Q_D(const QSqlTableModel); - QString s; QSqlField f = d->rec.field(d->sortColumn); if (!f.isValid()) - return s; - - QString table = d->tableName; + return QString(); + //we can safely escape the field because it would have been obtained from the database //and have the correct case QString field = d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName); - s.append(QLatin1String("ORDER BY ")).append(table).append(QLatin1Char('.')).append(field); - s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC"); - - return s; + field.prepend(QLatin1Char('.')).prepend(d->tableName); + field = d->sortOrder == Qt::AscendingOrder ? Sql::asc(field) : Sql::desc(field); + return Sql::orderBy(field); } /*! @@ -964,34 +956,27 @@ int QSqlTableModel::fieldIndex(const QString &fieldName) const QString QSqlTableModel::selectStatement() const { Q_D(const QSqlTableModel); - QString query; if (d->tableName.isEmpty()) { d->error = QSqlError(QLatin1String("No table name given"), QString(), QSqlError::StatementError); - return query; + return QString(); } if (d->rec.isEmpty()) { d->error = QSqlError(QLatin1String("Unable to find table ") + d->tableName, QString(), QSqlError::StatementError); - return query; + return QString(); } - query = d->db.driver()->sqlStatement(QSqlDriver::SelectStatement, - d->tableName, - d->rec, - false); - if (query.isEmpty()) { + const QString stmt = d->db.driver()->sqlStatement(QSqlDriver::SelectStatement, + d->tableName, + d->rec, + false); + if (stmt.isEmpty()) { d->error = QSqlError(QLatin1String("Unable to select fields from table ") + d->tableName, QString(), QSqlError::StatementError); - return query; + return stmt; } - if (!d->filter.isEmpty()) - query.append(QLatin1String(" WHERE ")).append(d->filter); - QString orderBy(orderByClause()); - if (!orderBy.isEmpty()) - query.append(QLatin1Char(' ')).append(orderBy); - - return query; + return Sql::concat(Sql::concat(stmt, Sql::where(d->filter)), orderByClause()); } /*! diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index 20ca63af61..2bbb4e1cf8 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -191,6 +191,11 @@ public: CacheMap cache; }; +class QSqlTableModelSql: public QSqlQueryModelSql +{ +public: +}; + QT_END_NAMESPACE #endif // QSQLTABLEMODEL_P_H |