summaryrefslogtreecommitdiffstats
path: root/src/sql
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2012-03-23 13:36:29 +0100
committerKent Hansen <kent.hansen@nokia.com>2012-03-23 14:10:58 +0100
commit3b512ae142017f105f297467f74dc28d3cb9030a (patch)
tree9e131e23c01537f051851a1da9576c1e1ddf5ba2 /src/sql
parente20c4730192f312881591fb50e571af0a88fe421 (diff)
parentf956f9a83603a3df5651e3238c24e8df37558d6e (diff)
Merge master into api_changes
Diffstat (limited to 'src/sql')
-rw-r--r--src/sql/models/qsqlquerymodel_p.h39
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp149
-rw-r--r--src/sql/models/qsqltablemodel.cpp101
-rw-r--r--src/sql/models/qsqltablemodel_p.h5
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