KDb

KDbOrderByColumn.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003-2018 Jarosław Staniek <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #include "KDbOrderByColumn.h"
21 #include "KDbQuerySchema.h"
22 #include "KDbQuerySchema_p.h"
23 #include "KDbConnection.h"
24 #include "kdb_debug.h"
25 
26 class Q_DECL_HIDDEN KDbOrderByColumn::Private
27 {
28 public:
29  Private()
30  : columnIndex(-1)
31  , pos(-1)
32  , field(nullptr)
33  , order(KDbOrderByColumn::SortOrder::Ascending)
34  {
35  }
36  Private(const Private &other) {
37  copy(other);
38  }
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)
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(
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);
57  }
58  void copy(const Private &other) {
59  KDbOrderByColumnPrivateArgs((*this)) = KDbOrderByColumnPrivateArgs(other);
60  }
61  bool operator==(const Private &other) const {
62  return KDbOrderByColumnPrivateArgs((*this)) == KDbOrderByColumnPrivateArgs(other);
63  }
64 
65  //! Query schema that owns the KDbQueryColumnInfo and thus also this KDbOrderByColumn object.
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;
77 
78  //! Value that indicates that column to sort (columnIndex) has been specified by providing its
79  //! position, not name. For example, using "SELECT a, b FROM T ORDER BY 2".
80  //! Value of -1 means that the column to sort has been specified by providing its name (or alias).
81  //! For example "SELECT a, b FROM T ORDER BY b". -1 is the default.
82  int pos;
83 
84  //! Used only in case when the second constructor is used.
85  KDbField* field;
86 
87  //! Sort order
89 };
90 
91 //----
92 
94  : d(new Private)
95 {
96 }
97 
99  : d(new Private(column, pos, nullptr, order))
100 {
101 }
102 
104  : d(new Private(nullptr, -1, field, order))
105 {
106 }
107 
109  : d(new Private(*other.d))
110 {
111 }
112 
113 KDbOrderByColumn::~KDbOrderByColumn()
114 {
115  delete d;
116 }
117 
119  KDbQuerySchema *toQuery) const
120 {
121  if (d->field) {
122  return new KDbOrderByColumn(d->field, d->order);
123  }
124  if (d->columnIndex >= 0) {
125  KDbQueryColumnInfo* columnInfo;
126  if (fromQuery && toQuery) {
127  columnInfo = toQuery->expandedOrInternalField(conn, d->columnIndex);
128  if (!columnInfo) {
129  kdbWarning() << "Column info not found at index" << d->columnIndex << "in toQuery";
130  return nullptr;
131  }
132  }
133  else {
134  columnInfo = column();
135  }
136  return new KDbOrderByColumn(columnInfo, d->order, d->pos);
137  }
138  return nullptr;
139 }
140 
142 {
143  if (d->columnIndex < 0 || !d->querySchema || !d->connection) {
144  return nullptr;
145  }
146  return d->querySchema->expandedOrInternalField(d->connection, d->columnIndex);
147 }
148 
150 {
151  return d->pos;
152 }
153 
155 {
156  return d->field;
157 }
158 
160 {
161  return d->order;
162 }
163 
165 {
166  if (this != &other) {
167  *d = *other.d;
168  }
169  return *this;
170 }
171 
173 {
174  return *d == *col.d;
175 }
176 
177 QDebug operator<<(QDebug dbg, const KDbOrderByColumn& order)
178 {
179  const QLatin1String orderString(
180  order.sortOrder() == KDbOrderByColumn::SortOrder::Ascending ? "ASCENDING" : "DESCENDING");
181  if (order.column()) {
182  if (order.position() > -1) {
183  dbg.nospace() << qPrintable(QString::fromLatin1("COLUMN_AT_POSITION_%1(").arg(order.position() + 1))
184  << *order.column() << ','
185  << qPrintable(orderString) << ')';
186  return dbg.space();
187  }
188  else {
189  dbg.nospace() << "COLUMN(" << *order.column() << ',';
190  dbg.nospace() << qPrintable(orderString) << ')';
191  return dbg.space();
192  }
193  }
194  if (order.field()) {
195  dbg.nospace() << "FIELD(" << *order.field() << ',';
196  dbg.nospace() << qPrintable(orderString) << ')';
197  return dbg.space();
198  }
199  dbg.nospace() << "NONE";
200  return dbg.space();
201 }
202 
204  KDbConnection *conn,
205  KDbQuerySchema *query,
206  KDb::IdentifierEscapingType escapingType) const
207 {
208  const QByteArray orderString(d->order == KDbOrderByColumn::SortOrder::Ascending ? "" : " DESC");
209  KDbEscapedString fieldName, tableName, collationString;
210  KDbQueryColumnInfo *col = column();
211  if (col) {
212  if (d->pos > -1)
213  return KDbEscapedString::number(d->pos + 1) + orderString;
214  else {
215  if (includeTableName && col->field()->table() && col->alias().isEmpty()) {
216  tableName = KDbEscapedString(escapeIdentifier(col->field()->table()->name(), conn, escapingType));
217  tableName += '.';
218  }
219  fieldName = KDbEscapedString(escapeIdentifier(col->aliasOrName(), conn, escapingType));
220  }
221  if (conn && col->field()->isTextType() && escapingType == KDb::DriverEscaping) {
222  collationString = conn->driver()->collationSql();
223  }
224  }
225  else {
226  QString aliasOrName;
227  if (includeTableName && d->field && d->field->table()) {
228  tableName = KDbEscapedString(escapeIdentifier(d->field->table()->name(), conn, escapingType));
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*/;
250  }
251  fieldName = KDbEscapedString(escapeIdentifier(aliasOrName, conn, escapingType));
252  if (conn && d->field && d->field->isTextType() && escapingType == KDb::DriverEscaping) {
253  collationString = conn->driver()->collationSql();
254  }
255  }
256  return tableName + fieldName + collationString + orderString;
257 }
258 
260  KDbConnection *conn,
261  KDb::IdentifierEscapingType escapingType) const
262 {
263  return toSqlString(includeTableName, conn, nullptr, escapingType);
264 }
265 
266 //=======================================
267 
268 class Q_DECL_HIDDEN KDbOrderByColumnList::Private
269 {
270 public:
271  Private() {
272  }
273  ~Private() {
274  qDeleteAll(data);
275  }
277 };
278 
280  : d(new Private)
281 {
282 }
283 
285  KDbQuerySchema* fromQuery, KDbQuerySchema* toQuery)
287 {
288  for (QList<KDbOrderByColumn *>::ConstIterator it(other.constBegin()); it != other.constEnd();
289  ++it)
290  {
291  KDbOrderByColumn* order = (*it)->copy(conn, fromQuery, toQuery);
292  if (order) {
293  d->data.append(order);
294  }
295  }
296 }
297 
298 KDbOrderByColumnList::~KDbOrderByColumnList()
299 {
300  delete d;
301 }
302 
304 {
305  return d->data == other.d->data;
306 }
307 
309 {
310  return d->data.value(index);
311 }
312 
314 {
315  return d->data.value(index);
316 }
317 
319  const QString& field1, KDbOrderByColumn::SortOrder order1,
320  const QString& field2, KDbOrderByColumn::SortOrder order2,
321  const QString& field3, KDbOrderByColumn::SortOrder order3,
322  const QString& field4, KDbOrderByColumn::SortOrder order4,
323  const QString& field5, KDbOrderByColumn::SortOrder order5)
324 {
325  if (!querySchema) {
326  return false;
327  }
328  int numAdded = 0;
329 #define ADD_COL(fieldName, order) \
330  if (ok && !fieldName.isEmpty()) { \
331  if (!appendField(conn, querySchema, fieldName, order)) \
332  ok = false; \
333  else \
334  numAdded++; \
335  }
336  bool ok = true;
337  ADD_COL(field1, order1)
338  ADD_COL(field2, order2)
339  ADD_COL(field3, order3)
340  ADD_COL(field4, order4)
341  ADD_COL(field5, order5)
342 #undef ADD_COL
343  if (ok) {
344  return true;
345  }
346  for (int i = 0; i < numAdded; i++) {
347  d->data.removeLast();
348  }
349  return false;
350 }
351 
354 {
355  if (columnInfo) {
356  d->data.append(new KDbOrderByColumn(columnInfo, order));
357  }
358 }
359 
361  KDbOrderByColumn::SortOrder order, int pos)
362 {
363  if (!querySchema) {
364  return false;
365  }
366  const KDbQueryColumnInfo::Vector fieldsExpanded(querySchema->fieldsExpanded(conn));
367  if (pos < 0 || pos >= fieldsExpanded.size()) {
368  return false;
369  }
370  KDbQueryColumnInfo* ci = fieldsExpanded[pos];
371  d->data.append(new KDbOrderByColumn(ci, order, pos));
372  return true;
373 }
374 
376 {
377  if (field) {
378  d->data.append(new KDbOrderByColumn(field, order));
379  }
380 }
381 
383  const QString& fieldName, KDbOrderByColumn::SortOrder order)
384 {
385  if (!querySchema) {
386  return false;
387  }
388  KDbQueryColumnInfo *columnInfo = querySchema->columnInfo(conn, fieldName);
389  if (columnInfo) {
390  d->data.append(new KDbOrderByColumn(columnInfo, order));
391  return true;
392  }
393  KDbField *field = querySchema->findTableField(fieldName);
394  if (field) {
395  d->data.append(new KDbOrderByColumn(field, order));
396  return true;
397  }
398  kdbWarning() << "no such field" << fieldName;
399  return false;
400 }
401 
403 {
404  return d->data.isEmpty();
405 }
406 
408 {
409  return d->data.count();
410 }
411 
413 {
414  return d->data.begin();
415 }
416 
418 {
419  return d->data.end();
420 }
421 
423 {
424  return d->data.constBegin();
425 }
426 
428 {
429  return d->data.constEnd();
430 }
431 
433 {
434  if (list.isEmpty()) {
435  dbg.nospace() << "NONE";
436  return dbg.space();
437  }
438  bool first = true;
440  if (first)
441  first = false;
442  else
443  dbg.nospace() << '\n';
444  dbg.nospace() << *(*it);
445  }
446  return dbg.space();
447 }
448 
450  KDbQuerySchema *query,
451  KDb::IdentifierEscapingType escapingType) const
452 {
453  KDbEscapedString string;
454  for (QList<KDbOrderByColumn*>::ConstIterator it(constBegin()); it != constEnd(); ++it) {
455  if (!string.isEmpty())
456  string += ", ";
457  string += (*it)->toSqlString(includeTableNames, conn, query, escapingType);
458  }
459  return string;
460 }
461 
463  KDb::IdentifierEscapingType escapingType) const
464 {
465  return toSqlString(includeTableNames, conn, nullptr, escapingType);
466 }
467 
469 {
470  qDeleteAll(d->data);
471  d->data.clear();
472 }
KDbQueryColumnInfo::Vector fieldsExpanded(KDbConnection *conn, FieldsExpandedMode mode=FieldsExpandedMode::Default) const
KDbOrderByColumn * copy(KDbConnection *conn, KDbQuerySchema *fromQuery, KDbQuerySchema *toQuery) const
KDbOrderByColumn provides information about a single query column used for sorting.
KDbTableSchema * table()
Definition: KDbField.cpp:585
QDebug & nospace()
Specialized string for escaping.
QList< KDbOrderByColumn * >::ConstIterator constEnd() const
int indexOf(const T &value, int from) const const
QString name
void appendField(KDbField *field, KDbOrderByColumn::SortOrder order=KDbOrderByColumn::SortOrder::Ascending)
QDebug & space()
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
bool appendFields(KDbConnection *conn, KDbQuerySchema *querySchema, const QString &field1, KDbOrderByColumn::SortOrder order1=KDbOrderByColumn::SortOrder::Ascending, const QString &field2=QString(), KDbOrderByColumn::SortOrder order2=KDbOrderByColumn::SortOrder::Ascending, const QString &field3=QString(), KDbOrderByColumn::SortOrder order3=KDbOrderByColumn::SortOrder::Ascending, const QString &field4=QString(), KDbOrderByColumn::SortOrder order4=KDbOrderByColumn::SortOrder::Ascending, const QString &field5=QString(), KDbOrderByColumn::SortOrder order5=KDbOrderByColumn::SortOrder::Ascending)
QList::const_iterator constBegin() const const
@ DriverEscaping
Identifiers are escaped by driver.
Definition: KDbGlobal.h:145
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
void appendColumn(KDbQueryColumnInfo *columnInfo, KDbOrderByColumn::SortOrder order=KDbOrderByColumn::SortOrder::Ascending)
QString aliasOrName() const
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
bool isTextType() const
Definition: KDbField.h:353
QList< KDbOrderByColumn * >::Iterator end()
KDbField * field() const
A field to sort, used only in case when the second constructor was used.
KDbField * findTableField(const QString &fieldOrTableAndFieldName) const
int indexOf(const T &value, int from) const const
bool isEmpty() const const
bool isEmpty() const const
const KDbQuerySchema * querySchema() const
Returns query schema for this column.
KDbQueryColumnInfo * columnInfo(KDbConnection *conn, const QString &identifier, ExpandMode mode=ExpandMode::Expanded) const
KDbEscapedString toSqlString(bool includeTableName, KDbConnection *conn, KDbQuerySchema *query, KDb::IdentifierEscapingType escapingType=KDb::DriverEscaping) const
Return an SQL string like "name ASC" or "2 DESC" usable for building an SQL statement.
QList< KDbOrderByColumn * >::Iterator begin()
KDbOrderByColumn & operator=(const KDbOrderByColumn &other)
Assigns other to this object returns a reference to this object.
QList::const_iterator constEnd() const const
KDbQuerySchema provides information about database query.
KDbOrderByColumn::SortOrder sortOrder() const
KDbEscapedString toSqlString(bool includeTableNames, KDbConnection *conn, KDbQuerySchema *query, KDb::IdentifierEscapingType escapingType=KDb::DriverEscaping) const
Return an SQL string like "name ASC, 2 DESC" usable for building an SQL statement.
QString fromLatin1(const char *str, int size)
bool operator==(const KDbOrderByColumnList &other) const
Meta-data for a field.
Definition: KDbField.h:71
bool operator==(const KDbOrderByColumn &col) const
const KDbOrderByColumn * value(int index) const
Returns column with given index.
SortOrder
Column sort order.
int size() const const
KDbConnection * connection()
Returns connection for this column.
KDbOrderByColumnList provides list of sorted columns for a query schema.
KDbOrderByColumn()
Creates an empty information about a single query column.
Provides database connection, allowing queries and data modification.
Definition: KDbConnection.h:51
KDbDriver * driver() const
@ WithInternalFields
Like Default but internal fields (for lookup) are appended.
virtual KDbEscapedString collationSql() const
Definition: KDbDriver.h:232
Helper class that assigns additional information for the column in a query.
IdentifierEscapingType
Escaping type for identifiers.
Definition: KDbGlobal.h:144
QList< KDbOrderByColumn * >::ConstIterator constBegin() const
KDbQueryColumnInfo * column() const
A column to sort.
KDbQueryColumnInfo * expandedOrInternalField(KDbConnection *conn, int index) const
const QList< QKeySequence > & copy()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:21:33 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.