Changeset View
Changeset View
Standalone View
Standalone View
src/KDbOrderByColumn.cpp
1 | /* This file is part of the KDE project | 1 | /* This file is part of the KDE project | ||
---|---|---|---|---|---|
2 | Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org> | 2 | Copyright (C) 2003-2018 Jarosław Staniek <staniek@kde.org> | ||
3 | 3 | | |||
4 | This library is free software; you can redistribute it and/or | 4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | 5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | 6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | 7 | version 2 of the License, or (at your option) any later version. | ||
8 | 8 | | |||
9 | This library is distributed in the hope that it will be useful, | 9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
Show All 11 Lines | |||||
22 | #include "KDbQuerySchema_p.h" | 22 | #include "KDbQuerySchema_p.h" | ||
23 | #include "KDbConnection.h" | 23 | #include "KDbConnection.h" | ||
24 | #include "kdb_debug.h" | 24 | #include "kdb_debug.h" | ||
25 | 25 | | |||
26 | class Q_DECL_HIDDEN KDbOrderByColumn::Private | 26 | class Q_DECL_HIDDEN KDbOrderByColumn::Private | ||
27 | { | 27 | { | ||
28 | public: | 28 | public: | ||
29 | Private() | 29 | Private() | ||
30 | : column(nullptr) | 30 | : columnIndex(-1) | ||
31 | , pos(-1) | 31 | , pos(-1) | ||
32 | , field(nullptr) | 32 | , field(nullptr) | ||
33 | , order(KDbOrderByColumn::SortOrder::Ascending) | 33 | , order(KDbOrderByColumn::SortOrder::Ascending) | ||
34 | { | 34 | { | ||
35 | } | 35 | } | ||
36 | Private(const Private &other) { | 36 | Private(const Private &other) { | ||
37 | copy(other); | 37 | copy(other); | ||
38 | } | 38 | } | ||
39 | #define KDbOrderByColumnPrivateArgs(o) std::tie(o.column, o.pos, o.field, o.order) | 39 | #define KDbOrderByColumnPrivateArgs(o) std::tie(o.querySchema, o.connection, o.columnIndex, o.pos, o.field, o.order) | ||
40 | Private(KDbQueryColumnInfo* aColumn, int aPos, KDbField* aField, KDbOrderByColumn::SortOrder aOrder) { | 40 | Private(KDbQueryColumnInfo* aColumn, int aPos, KDbField* aField, KDbOrderByColumn::SortOrder aOrder) | ||
41 | KDbOrderByColumnPrivateArgs((*this)) = std::tie(aColumn, aPos, aField, aOrder); | 41 | { | ||
42 | const KDbQuerySchema *foundQuerySchema = nullptr; | ||||
43 | KDbConnection *foundConnection = nullptr; | ||||
44 | int foundColumnIndex = -1; | ||||
45 | if (aColumn) { | ||||
46 | foundQuerySchema =aColumn->querySchema(); | ||||
47 | foundConnection = aColumn->connection(); | ||||
48 | const KDbQueryColumnInfo::Vector fieldsExpanded = foundQuerySchema->fieldsExpanded( | ||||
49 | foundConnection, KDbQuerySchema::FieldsExpandedMode::WithInternalFields); | ||||
50 | foundColumnIndex = fieldsExpanded.indexOf(aColumn); | ||||
51 | if (foundColumnIndex < 0) { | ||||
52 | kdbWarning() << "Column not found in query:" << *aColumn; | ||||
53 | } | ||||
54 | } | ||||
55 | KDbOrderByColumnPrivateArgs((*this)) | ||||
56 | = std::tie(foundQuerySchema, foundConnection, foundColumnIndex, aPos, aField, aOrder); | ||||
42 | } | 57 | } | ||
43 | void copy(const Private &other) { | 58 | void copy(const Private &other) { | ||
44 | KDbOrderByColumnPrivateArgs((*this)) = KDbOrderByColumnPrivateArgs(other); | 59 | KDbOrderByColumnPrivateArgs((*this)) = KDbOrderByColumnPrivateArgs(other); | ||
45 | } | 60 | } | ||
46 | bool operator==(const Private &other) const { | 61 | bool operator==(const Private &other) const { | ||
47 | return KDbOrderByColumnPrivateArgs((*this)) == KDbOrderByColumnPrivateArgs(other); | 62 | return KDbOrderByColumnPrivateArgs((*this)) == KDbOrderByColumnPrivateArgs(other); | ||
48 | } | 63 | } | ||
49 | 64 | | |||
50 | //! Column to sort, @c nullptr if field is non-0. | 65 | //! Query schema that owns the KDbQueryColumnInfo and thus also this KDbOrderByColumn object. | ||
51 | KDbQueryColumnInfo* column; | 66 | //! Cached for performance, can be cached since lifetime of the KDbOrderByColumn object depends | ||
67 | //! on the query. @c nullptr if columnIndex is not provided. @since 3.2 | ||||
68 | const KDbQuerySchema *querySchema = nullptr; | ||||
69 | | ||||
70 | //! Connection used to compute expanded fields. Like querySchema, connection is cached for | ||||
71 | //! performance and can be cached since lifetime of the KDbOrderByColumn object depends on the | ||||
72 | //! connection. @c nullptr if columnIndex is not provided. @since 3.2 | ||||
73 | KDbConnection *connection = nullptr; | ||||
74 | | ||||
75 | //! Index of column to sort, -1 if field is present. @since 3.2 | ||||
76 | int columnIndex; | ||||
52 | 77 | | |||
53 | //! Value that indicates that column to sort (columnIndex) has been specified by providing its | 78 | //! Value that indicates that column to sort (columnIndex) has been specified by providing its | ||
54 | //! position, not name. For example, using "SELECT a, b FROM T ORDER BY 2". | 79 | //! position, not name. For example, using "SELECT a, b FROM T ORDER BY 2". | ||
55 | //! Value of -1 means that the column to sort has been specified by providing its name (or alias). | 80 | //! Value of -1 means that the column to sort has been specified by providing its name (or alias). | ||
56 | //! For example "SELECT a, b FROM T ORDER BY b". -1 is the default. | 81 | //! For example "SELECT a, b FROM T ORDER BY b". -1 is the default. | ||
57 | int pos; | 82 | int pos; | ||
58 | 83 | | |||
59 | //! Used only in case when the second constructor is used. | 84 | //! Used only in case when the second constructor is used. | ||
Show All 31 Lines | |||||
91 | } | 116 | } | ||
92 | 117 | | |||
93 | KDbOrderByColumn *KDbOrderByColumn::copy(KDbConnection *conn, KDbQuerySchema *fromQuery, | 118 | KDbOrderByColumn *KDbOrderByColumn::copy(KDbConnection *conn, KDbQuerySchema *fromQuery, | ||
94 | KDbQuerySchema *toQuery) const | 119 | KDbQuerySchema *toQuery) const | ||
95 | { | 120 | { | ||
96 | if (d->field) { | 121 | if (d->field) { | ||
97 | return new KDbOrderByColumn(d->field, d->order); | 122 | return new KDbOrderByColumn(d->field, d->order); | ||
98 | } | 123 | } | ||
99 | if (d->column) { | 124 | if (d->columnIndex >= 0) { | ||
100 | KDbQueryColumnInfo* columnInfo; | 125 | KDbQueryColumnInfo* columnInfo; | ||
101 | if (fromQuery && toQuery) { | 126 | if (fromQuery && toQuery) { | ||
102 | int columnIndex = fromQuery->columnsOrder(conn).value(d->column); | 127 | columnInfo = toQuery->expandedOrInternalField(conn, d->columnIndex); | ||
103 | if (columnIndex < 0) { | | |||
104 | kdbWarning() << "Index not found for column" << *d->column; | | |||
105 | return nullptr; | | |||
106 | } | | |||
107 | columnInfo = toQuery->expandedOrInternalField(conn, columnIndex); | | |||
108 | if (!columnInfo) { | 128 | if (!columnInfo) { | ||
109 | kdbWarning() << "Column info not found at index" << columnIndex << "in toQuery"; | 129 | kdbWarning() << "Column info not found at index" << d->columnIndex << "in toQuery"; | ||
110 | return nullptr; | 130 | return nullptr; | ||
111 | } | 131 | } | ||
112 | } | 132 | } | ||
113 | else { | 133 | else { | ||
114 | columnInfo = d->column; | 134 | columnInfo = column(); | ||
115 | } | 135 | } | ||
116 | return new KDbOrderByColumn(columnInfo, d->order, d->pos); | 136 | return new KDbOrderByColumn(columnInfo, d->order, d->pos); | ||
117 | } | 137 | } | ||
118 | return nullptr; | 138 | return nullptr; | ||
119 | } | 139 | } | ||
120 | 140 | | |||
121 | KDbQueryColumnInfo* KDbOrderByColumn::column() const | 141 | KDbQueryColumnInfo* KDbOrderByColumn::column() const | ||
122 | { | 142 | { | ||
123 | return d->column; | 143 | if (d->columnIndex < 0 || !d->querySchema || !d->connection) { | ||
144 | return nullptr; | ||||
145 | } | ||||
146 | return d->querySchema->expandedOrInternalField(d->connection, d->columnIndex); | ||||
124 | } | 147 | } | ||
125 | 148 | | |||
126 | int KDbOrderByColumn::position() const | 149 | int KDbOrderByColumn::position() const | ||
127 | { | 150 | { | ||
128 | return d->pos; | 151 | return d->pos; | ||
129 | } | 152 | } | ||
130 | 153 | | |||
131 | KDbField* KDbOrderByColumn::field() const | 154 | KDbField* KDbOrderByColumn::field() const | ||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Line(s) | 194 | if (order.field()) { | |||
174 | return dbg.space(); | 197 | return dbg.space(); | ||
175 | } | 198 | } | ||
176 | dbg.nospace() << "NONE"; | 199 | dbg.nospace() << "NONE"; | ||
177 | return dbg.space(); | 200 | return dbg.space(); | ||
178 | } | 201 | } | ||
179 | 202 | | |||
180 | KDbEscapedString KDbOrderByColumn::toSqlString(bool includeTableName, | 203 | KDbEscapedString KDbOrderByColumn::toSqlString(bool includeTableName, | ||
181 | KDbConnection *conn, | 204 | KDbConnection *conn, | ||
205 | KDbQuerySchema *query, | ||||
182 | KDb::IdentifierEscapingType escapingType) const | 206 | KDb::IdentifierEscapingType escapingType) const | ||
183 | { | 207 | { | ||
184 | const QByteArray orderString(d->order == KDbOrderByColumn::SortOrder::Ascending ? "" : " DESC"); | 208 | const QByteArray orderString(d->order == KDbOrderByColumn::SortOrder::Ascending ? "" : " DESC"); | ||
185 | KDbEscapedString fieldName, tableName, collationString; | 209 | KDbEscapedString fieldName, tableName, collationString; | ||
186 | if (d->column) { | 210 | KDbQueryColumnInfo *col = column(); | ||
211 | if (col) { | ||||
187 | if (d->pos > -1) | 212 | if (d->pos > -1) | ||
188 | return KDbEscapedString::number(d->pos + 1) + orderString; | 213 | return KDbEscapedString::number(d->pos + 1) + orderString; | ||
189 | else { | 214 | else { | ||
190 | if (includeTableName && d->column->alias().isEmpty()) { | 215 | if (includeTableName && col->field()->table() && col->alias().isEmpty()) { | ||
191 | tableName = KDbEscapedString(escapeIdentifier(d->column->field()->table()->name(), conn, escapingType)); | 216 | tableName = KDbEscapedString(escapeIdentifier(col->field()->table()->name(), conn, escapingType)); | ||
192 | tableName += '.'; | 217 | tableName += '.'; | ||
193 | } | 218 | } | ||
194 | fieldName = KDbEscapedString(escapeIdentifier(d->column->aliasOrName(), conn, escapingType)); | 219 | fieldName = KDbEscapedString(escapeIdentifier(col->aliasOrName(), conn, escapingType)); | ||
195 | } | 220 | } | ||
196 | if (d->column->field()->isTextType() && escapingType == KDb::DriverEscaping) { | 221 | if (conn && col->field()->isTextType() && escapingType == KDb::DriverEscaping) { | ||
197 | collationString = conn->driver()->collationSql(); | 222 | collationString = conn->driver()->collationSql(); | ||
198 | } | 223 | } | ||
199 | } | 224 | } | ||
200 | else { | 225 | else { | ||
201 | if (d->field && includeTableName) { | 226 | QString aliasOrName; | ||
227 | if (includeTableName && d->field && d->field->table()) { | ||||
202 | tableName = KDbEscapedString(escapeIdentifier(d->field->table()->name(), conn, escapingType)); | 228 | tableName = KDbEscapedString(escapeIdentifier(d->field->table()->name(), conn, escapingType)); | ||
203 | tableName += '.'; | 229 | tableName += '.'; | ||
230 | } else if (d->field && conn && query) { | ||||
231 | if (d->field->isExpression()) { | ||||
232 | const int indexOfField = query->indexOf(*d->field); | ||||
233 | aliasOrName = query->columnAlias(indexOfField); | ||||
234 | if (aliasOrName.isEmpty()) { | ||||
235 | kdbWarning() << "This field does not belong to specified query:" << *d->field | ||||
236 | << endl << "cannot find alias"; | ||||
237 | aliasOrName = QLatin1String("?unknown_field?"); | ||||
238 | } | ||||
239 | } else { | ||||
240 | KDbQueryColumnInfo *ci = query->columnInfo(conn, d->field->name()); | ||||
241 | if (ci) { | ||||
242 | aliasOrName = ci->aliasOrName(); | ||||
243 | } | ||||
244 | } | ||||
245 | } | ||||
246 | if (aliasOrName.isEmpty()) { | ||||
247 | // The field is not present on the SELECT list but is still correct, | ||||
248 | // e.g. SELECT id FROM cars ORDER BY owner | ||||
249 | aliasOrName = d->field ? d->field->name() : QLatin1String("?missing_field?")/*error*/; | ||||
204 | } | 250 | } | ||
205 | fieldName = KDbEscapedString(escapeIdentifier( | 251 | fieldName = KDbEscapedString(escapeIdentifier(aliasOrName, conn, escapingType)); | ||
206 | d->field ? d->field->name() : QLatin1String("??")/*error*/, conn, escapingType)); | 252 | if (conn && d->field && d->field->isTextType() && escapingType == KDb::DriverEscaping) { | ||
207 | if (d->field && d->field->isTextType() && escapingType == KDb::DriverEscaping) { | | |||
208 | collationString = conn->driver()->collationSql(); | 253 | collationString = conn->driver()->collationSql(); | ||
209 | } | 254 | } | ||
210 | } | 255 | } | ||
211 | return tableName + fieldName + collationString + orderString; | 256 | return tableName + fieldName + collationString + orderString; | ||
212 | } | 257 | } | ||
213 | 258 | | |||
259 | KDbEscapedString KDbOrderByColumn::toSqlString(bool includeTableName, | ||||
260 | KDbConnection *conn, | ||||
261 | KDb::IdentifierEscapingType escapingType) const | ||||
262 | { | ||||
263 | return toSqlString(includeTableName, conn, nullptr, escapingType); | ||||
264 | } | ||||
265 | | ||||
214 | //======================================= | 266 | //======================================= | ||
215 | 267 | | |||
216 | class Q_DECL_HIDDEN KDbOrderByColumnList::Private | 268 | class Q_DECL_HIDDEN KDbOrderByColumnList::Private | ||
217 | { | 269 | { | ||
218 | public: | 270 | public: | ||
219 | Private() { | 271 | Private() { | ||
220 | } | 272 | } | ||
221 | ~Private() { | 273 | ~Private() { | ||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Line(s) | 439 | for (QList<KDbOrderByColumn*>::ConstIterator it(list.constBegin()); it != list.constEnd(); ++it) { | |||
390 | else | 442 | else | ||
391 | dbg.nospace() << '\n'; | 443 | dbg.nospace() << '\n'; | ||
392 | dbg.nospace() << *(*it); | 444 | dbg.nospace() << *(*it); | ||
393 | } | 445 | } | ||
394 | return dbg.space(); | 446 | return dbg.space(); | ||
395 | } | 447 | } | ||
396 | 448 | | |||
397 | KDbEscapedString KDbOrderByColumnList::toSqlString(bool includeTableNames, KDbConnection *conn, | 449 | KDbEscapedString KDbOrderByColumnList::toSqlString(bool includeTableNames, KDbConnection *conn, | ||
450 | KDbQuerySchema *query, | ||||
398 | KDb::IdentifierEscapingType escapingType) const | 451 | KDb::IdentifierEscapingType escapingType) const | ||
399 | { | 452 | { | ||
400 | KDbEscapedString string; | 453 | KDbEscapedString string; | ||
401 | for (QList<KDbOrderByColumn*>::ConstIterator it(constBegin()); it != constEnd(); ++it) { | 454 | for (QList<KDbOrderByColumn*>::ConstIterator it(constBegin()); it != constEnd(); ++it) { | ||
402 | if (!string.isEmpty()) | 455 | if (!string.isEmpty()) | ||
403 | string += ", "; | 456 | string += ", "; | ||
404 | string += (*it)->toSqlString(includeTableNames, conn, escapingType); | 457 | string += (*it)->toSqlString(includeTableNames, conn, query, escapingType); | ||
405 | } | 458 | } | ||
406 | return string; | 459 | return string; | ||
407 | } | 460 | } | ||
408 | 461 | | |||
462 | KDbEscapedString KDbOrderByColumnList::toSqlString(bool includeTableNames, KDbConnection *conn, | ||||
463 | KDb::IdentifierEscapingType escapingType) const | ||||
464 | { | ||||
465 | return toSqlString(includeTableNames, conn, nullptr, escapingType); | ||||
466 | } | ||||
467 | | ||||
409 | void KDbOrderByColumnList::clear() | 468 | void KDbOrderByColumnList::clear() | ||
410 | { | 469 | { | ||
411 | qDeleteAll(d->data); | 470 | qDeleteAll(d->data); | ||
412 | d->data.clear(); | 471 | d->data.clear(); | ||
413 | } | 472 | } |