KDb

KDbExpression.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003-2015 Jarosław Staniek <[email protected]>
3  Copyright (C) 2014 Radoslaw Wicik <[email protected]>
4 
5  Based on nexp.cpp : Parser module of Python-like language
6  (C) 2001 Jarosław Staniek, MIMUW (www.mimuw.edu.pl)
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  * Boston, MA 02110-1301, USA.
21  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  */
23 
24 #include "KDbExpression.h"
25 #include "KDb.h"
26 #include "KDbDriver.h"
27 #include "KDbQuerySchema.h"
28 #include "KDbParser_p.h"
29 #include "kdb_debug.h"
30 #include "generated/sqlparser.h"
31 
32 #include <vector>
33 
34 //! @internal A cache
35 class KDbExpressionClassNames
36 {
37 public:
38  KDbExpressionClassNames()
39  : names({
40  QLatin1String("Unknown"),
41  QLatin1String("Unary"),
42  QLatin1String("Arithm"),
43  QLatin1String("Logical"),
44  QLatin1String("Relational"),
45  QLatin1String("SpecialBinary"),
46  QLatin1String("Const"),
47  QLatin1String("Variable"),
48  QLatin1String("Function"),
49  QLatin1String("Aggregation"),
50  QLatin1String("FieldList"),
51  QLatin1String("TableList"),
52  QLatin1String("ArgumentList"),
53  QLatin1String("QueryParameter")})
54  {
55  }
56  const std::vector<QString> names;
57 };
58 
59 Q_GLOBAL_STATIC(KDbExpressionClassNames, KDb_expressionClassNames)
60 
61 KDB_EXPORT QString expressionClassName(KDb::ExpressionClass c)
62 {
63  Q_ASSERT(size_t(c) < KDb_expressionClassNames->names.size());
64  return KDb_expressionClassNames->names[c];
65 }
66 
67 KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbExpression& expr)
68 {
69  KDb::ExpressionCallStack callStack;
70  return expr.debug(dbg.nospace(), &callStack);
71 }
72 
73 //=========================================
74 
75 KDbExpressionData::KDbExpressionData()
76  : expressionClass(KDb::UnknownExpression)
77 {
78  //ExpressionDebug << "KDbExpressionData" << ref;
79 }
80 
81 /*Data(const Data& other)
82 : QSharedData(other)
83 , token(other.token)
84 , expressionClass(other.expressionClass)
85 , parent(other.parent)
86 , children(other.children)
87 {
88  ExpressionDebug << "KDbExpressionData" << ref;
89 }*/
90 
91 KDbExpressionData::~KDbExpressionData()
92 {
93  //ExpressionDebug << "~KDbExpressionData" << ref;
94 }
95 
96 KDbExpressionData* KDbExpressionData::clone()
97 {
98  ExpressionDebug << "KDbExpressionData::clone" << *this;
99  return new KDbExpressionData(*this);
100 }
101 
102 KDbField::Type KDbExpressionData::typeInternal(KDb::ExpressionCallStack* callStack) const
103 {
104  Q_UNUSED(callStack);
105  return KDbField::InvalidType;
106 }
107 
109 {
110  if (!addToCallStack(nullptr, callStack)) {
111  return KDbField::InvalidType;
112  }
113  const KDbField::Type t = typeInternal(callStack);
114  callStack->removeLast();
115  return t;
116 }
117 
119 {
120  KDb::ExpressionCallStack callStack;
121  return type(&callStack);
122 }
123 
124 bool KDbExpressionData::isValid() const
125 {
126  return type() != KDbField::InvalidType;
127 }
128 
129 bool KDbExpressionData::isTextType() const
130 {
131  return KDbField::isTextType(type());
132 }
133 
134 bool KDbExpressionData::isIntegerType() const
135 {
136  return KDbField::isIntegerType(type());
137 }
138 
139 bool KDbExpressionData::isNumericType() const
140 {
141  return KDbField::isNumericType(type());
142 }
143 
144 bool KDbExpressionData::isFPNumericType() const
145 {
147 }
148 
149 bool KDbExpressionData::isDateTimeType() const
150 {
151  return KDbField::isDateTimeType(type());
152 }
153 
154 bool KDbExpressionData::validate(KDbParseInfo *parseInfo)
155 {
156  KDb::ExpressionCallStack callStack;
157  return validate(parseInfo, &callStack);
158 }
159 
160 bool KDbExpressionData::validate(KDbParseInfo *parseInfo, KDb::ExpressionCallStack* callStack)
161 {
162  if (!addToCallStack(nullptr, callStack)) {
163  return false;
164  }
165  bool result = validateInternal(parseInfo, callStack);
166  callStack->removeLast();
167  return result;
168 }
169 
170 bool KDbExpressionData::validateInternal(KDbParseInfo *parseInfo, KDb::ExpressionCallStack* callStack)
171 {
172  Q_UNUSED(parseInfo);
173  Q_UNUSED(callStack);
174  return true;
175 }
176 
177 KDbEscapedString KDbExpressionData::toString(
178  const KDbDriver *driver,
180  KDb::ExpressionCallStack* callStack) const
181 {
182  const bool owned = !callStack;
183  if (owned) {
184  callStack = new KDb::ExpressionCallStack();
185  }
186  if (!addToCallStack(nullptr, callStack)) {
187  if (owned) {
188  delete callStack;
189  }
190  return KDbEscapedString("<CYCLE!>");
191  }
192  KDbEscapedString s = toStringInternal(driver, params, callStack);
193  callStack->removeLast();
194  if (owned) {
195  delete callStack;
196  }
197  return s;
198 }
199 
200 KDbEscapedString KDbExpressionData::toStringInternal(
201  const KDbDriver *driver,
203  KDb::ExpressionCallStack* callStack) const
204 {
205  Q_UNUSED(driver);
206  Q_UNUSED(params);
207  Q_UNUSED(callStack);
208  return KDbEscapedString("<UNKNOWN!>");
209 }
210 
211 void KDbExpressionData::getQueryParameters(QList<KDbQuerySchemaParameter>* params)
212 {
213  Q_UNUSED(params);
214 }
215 
216 bool KDbExpressionData::addToCallStack(QDebug *dbg, KDb::ExpressionCallStack* callStack) const
217 {
218  if (callStack->contains(this)) {
219  if (dbg)
220  dbg->nospace() << "<CYCLE!>";
221  QString warning;
222  QDebug debug(&warning);
223  debug.nospace() << "Cycle detected in expression (depth " << callStack->length() << "):";
224  int level = 0;
225  for (const KDbExpressionData *data : *callStack) {
226  debug.nospace() << endl << level + 1 << ":";
227  debug.space().noquote() << expressionClassName(data->expressionClass);
228  debug.nospace() << data->token;
229  ++level;
230  }
231  kdbWarning().noquote() << warning;
232  return false;
233  }
234  callStack->append(this);
235  return true;
236 }
237 
239 {
240  if (!addToCallStack(&dbg, callStack)) {
241  return dbg.nospace();
242  }
243  debugInternal(dbg, callStack);
244  callStack->removeLast();
245  return dbg;
246 }
247 
248 QDebug operator<<(QDebug dbg, const KDbExpressionData& expr)
249 {
250  KDb::ExpressionCallStack callStack;
251  return expr.debug(dbg.nospace(), &callStack);
252 }
253 
255 {
256  Q_UNUSED(callStack);
257  dbg.nospace() << QString::fromLatin1("Exp(%1,type=%2)")
259 }
260 
261 //=========================================
262 
264  : d(new KDbExpressionData)
265 {
266  ExpressionDebug << "KDbExpression ctor ()" << *this << d->ref;
267 }
268 
270  : d(data)
271 {
272  d->expressionClass = aClass;
273  d->token = token;
274 }
275 
277  : d(data)
278 {
279  ExpressionDebug << "KDbExpression ctor (KDbExpressionData*)" << *this;
280 }
281 
284 {
285 }
286 
287 KDbExpression::~KDbExpression()
288 {
289  //kdbDebug() << *this << d->ref;
290  if (d->parent && d->ref == 1) {
291  d->parent->children.removeOne(d);
292  }
293 }
294 
296 {
297  return d->expressionClass == KDb::UnknownExpression;
298 }
299 
301 {
302  return KDbExpression(d->clone());
303 }
304 
306 {
307  return d->token;
308 }
309 
311 {
312  d->token = token;
313 }
314 
316 {
317  return d->expressionClass;
318 }
319 
321 {
322  d->expressionClass = aClass;
323 }
324 
325 bool KDbExpression::validate(KDbParseInfo *parseInfo)
326 {
327  return d->validate(parseInfo);
328 }
329 
331 {
332  return d->type();
333 }
334 
336 {
337  return d->isValid();
338 }
339 
341 {
342  return d->isTextType();
343 }
344 
346 {
347  return d->isIntegerType();
348 }
349 
351 {
352  return d->isNumericType();
353 }
354 
356 {
357  return d->isFPNumericType();
358 }
359 
361 {
362  return d->isDateTimeType();
363 }
364 
366 {
367  return d->parent.data() ? KDbExpression(d->parent) : KDbExpression();
368 }
369 
371 {
372  return d->children;
373 }
374 
375 void KDbExpression::appendChild(const KDbExpression& child)
376 {
377  appendChild(child.d);
378 }
379 
380 void KDbExpression::prependChild(const KDbExpression& child)
381 {
382  if (!checkBeforeInsert(child.d))
383  return;
384  d->children.prepend(child.d);
385  child.d->parent = d;
386 }
387 
388 void KDbExpression::insertChild(int i, const KDbExpression& child)
389 {
390  if (!checkBeforeInsert(child.d))
391  return;
392  if (i < 0 || i > d->children.count())
393  return;
394  d->children.insert(i, child.d);
395  child.d->parent = d;
396 }
397 
399 {
400  if (i < 0 || i > d->children.count())
401  return;
402  KDbExpression child;
403  d->children.insert(i, child.d);
404  child.d->parent = d;
405 }
406 
407 bool KDbExpression::removeChild(const KDbExpression& child)
408 {
409  if (isNull() || child.isNull())
410  return false;
411  child.d->parent.reset(); // no longer parent
412  return d->children.removeOne(child.d);
413 }
414 
415 void KDbExpression::removeChild(int i)
416 {
417  if (isNull())
418  return;
419  if (i < 0 || i >= d->children.count())
420  return;
421  //kdbDebug() << d->children.count() << d->children.at(i);
422  d->children.removeAt(i);
423 }
424 
425 KDbExpression KDbExpression::takeChild(int i)
426 {
427  if (isNull())
428  return KDbExpression();
429  if (i < 0 || i >= d->children.count())
430  return KDbExpression();
431  ExplicitlySharedExpressionDataPointer child = d->children.takeAt(i);
432  if (!child)
433  return KDbExpression();
434  child->parent.reset();
435  return KDbExpression(child);
436 }
437 
438 int KDbExpression::indexOfChild(const KDbExpression& child, int from) const
439 {
440  return d->children.indexOf(child.d, from);
441 }
442 
443 int KDbExpression::lastIndexOfChild(const KDbExpression& child, int from) const
444 {
445  return d->children.lastIndexOf(child.d, from);
446 }
447 
448 bool KDbExpression::checkBeforeInsert(const ExplicitlySharedExpressionDataPointer& child)
449 {
450  if (!child)
451  return false;
452  if (d == child) // expression cannot be own child
453  return false;
454  if (child->parent == d) // cannot insert child twice
455  return false;
456  if (child->parent) // remove from old parent
457  child->parent->children.removeOne(child);
458  return true;
459 }
460 
461 void KDbExpression::appendChild(const ExplicitlySharedExpressionDataPointer& child)
462 {
463  if (!checkBeforeInsert(child))
464  return;
465  d->children.append(child);
466  child->parent = d;
467 }
468 
471  KDb::ExpressionCallStack* callStack) const
472 {
473  if (isNull())
474  return KDbEscapedString("<UNKNOWN!>");
475  return d->toString(driver, params, callStack);
476 }
477 
479 {
480  Q_ASSERT(params);
481  d->getQueryParameters(params);
482 }
483 
484 QDebug KDbExpression::debug(QDebug dbg, KDb::ExpressionCallStack* callStack) const
485 {
486  if (d)
487  d->debug(dbg, callStack);
488  return dbg.space();
489 }
490 
491 bool KDbExpression::operator==(const KDbExpression& e) const
492 {
493  return d == e.d;
494 }
495 
496 bool KDbExpression::operator!=(const KDbExpression& e) const
497 {
498  return !operator==(e);
499 }
500 
501 bool KDbExpression::isNArg() const
502 {
503  return d->convertConst<KDbNArgExpressionData>();
504 }
505 
506 bool KDbExpression::isUnary() const
507 {
508  return d->convertConst<KDbUnaryExpressionData>();
509 }
510 
511 bool KDbExpression::isBinary() const
512 {
513  return d->convertConst<KDbBinaryExpressionData>();
514 }
515 
516 bool KDbExpression::isConst() const
517 {
518  return d->convertConst<KDbConstExpressionData>();
519 }
520 
521 bool KDbExpression::isVariable() const
522 {
523  return d->convertConst<KDbVariableExpressionData>();
524 }
525 
526 bool KDbExpression::isFunction() const
527 {
528  return d->convertConst<KDbFunctionExpressionData>();
529 }
530 
531 bool KDbExpression::isQueryParameter() const
532 {
533  return d->convertConst<KDbQueryParameterExpressionData>();
534 }
535 
536 #define CAST(T) \
537  d->convert<T ## Data>() ? T(d) : T()
538 
540 {
541  return CAST(KDbNArgExpression);
542 }
543 
544 KDbUnaryExpression KDbExpression::toUnary() const
545 {
546  return CAST(KDbUnaryExpression);
547 }
548 
549 KDbBinaryExpression KDbExpression::toBinary() const
550 {
551  return CAST(KDbBinaryExpression);
552 }
553 
554 KDbConstExpression KDbExpression::toConst() const
555 {
556  return CAST(KDbConstExpression);
557 }
558 
559 KDbQueryParameterExpression KDbExpression::toQueryParameter() const
560 {
561  return CAST(KDbQueryParameterExpression);
562 }
563 
564 KDbVariableExpression KDbExpression::toVariable() const
565 {
566  return CAST(KDbVariableExpression);
567 }
568 
569 KDbFunctionExpression KDbExpression::toFunction() const
570 {
571  return CAST(KDbFunctionExpression);
572 }
573 
575 {
576  if (this == &e) {
577  kdbWarning() << "Expression" << *this << "cannot be set as own child";
578  return;
579  }
580  if (d->children.indexOf(e.d) == index) { // cannot set twice
581  return;
582  }
583  if (d->children[index == 0 ? 1 : 0] == e.d) { // this arg was at right, remove
584  d->children[index] = e.d;
585  d->children[index == 0 ? 1 : 0] = new KDbExpressionData;
586  }
587  else {
588  if (e.d->parent) { // remove from old parent
589  e.d->parent->children.removeOne(e.d);
590  }
591  d->children[index] = e.d;
592  }
593 }
594 
595 // static
597 {
598  switch (token.value()) {
599  case '+':
600  case '-':
601  case '*':
602  case '/':
603  case '&':
604  case '|':
605  case '%':
606  case BITWISE_SHIFT_RIGHT:
607  case BITWISE_SHIFT_LEFT:
608  case CONCATENATION:
609  return KDb::ArithmeticExpression;
610  case '=':
611  case '<':
612  case '>':
613  case NOT_EQUAL:
614  case NOT_EQUAL2:
615  case LESS_OR_EQUAL:
616  case GREATER_OR_EQUAL:
617  case LIKE:
618  case NOT_LIKE:
619  case SQL_IN:
620  case SIMILAR_TO:
621  case NOT_SIMILAR_TO:
622  return KDb::RelationalExpression;
623  case OR:
624  case AND:
625  case XOR:
626  return KDb::LogicalExpression;
627  case AS:
628  case AS_EMPTY:
629  return KDb::SpecialBinaryExpression;
630  default:;
631  }
632  return KDb::UnknownExpression;
633 }
634 
635 #undef CAST
bool isFPNumericType() const
void setLeftOrRight(const KDbExpression &right, int index)
Only for KDbBinaryExpression::setLeft() and KDbBinaryExpression::setRight()
Internal data class used to implement implicitly shared class KDbExpression.
bool validate(KDbParseInfo *parseInfo)
QTextStream & endl(QTextStream &stream)
An iterator for a list of values of query schema parameters Allows to iterate over parameters and ret...
A type-safe KDbSQL token It can be used in KDb expressions.
Definition: KDbToken.h:36
@ InvalidType
Definition: KDbField.h:86
The KDbBinaryExpression class represents binary operation.
Internal data class used to implement implicitly shared class KDbBinaryExpression.
void setToken(KDbToken token)
The KDbVariableExpression class represents variables such as fieldname or tablename....
QDebug & nospace()
int length() const const
A database connectivity and creation framework.
KDbField::Type type() const
Specialized string for escaping.
QStringView level(QStringView ifopt)
QDebug debug(QDebug dbg, KDb::ExpressionCallStack *callStack) const
Sends information about this expression to debug output dbg.
bool isNumericType() const
QDebug & space()
KDbExpression parent() const
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
Database driver's abstraction.
Definition: KDbDriver.h:49
Internal data class used to implement implicitly shared class KDbQueryParameterExpression.
The KDbQueryParameterExpression class represents query parameter expression.
static KDb::ExpressionClass classForToken(KDbToken token)
void setExpressionClass(KDb::ExpressionClass aClass)
bool contains(const T &value) const const
bool isFPNumericType() const
Definition: KDbField.h:335
Internal data class used to implement implicitly shared class KDbUnaryExpression.
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
static QString defaultSqlTypeName(KDbField::Type type)
Definition: KDbDriver.cpp:164
void removeLast()
QDebug & noquote()
bool isTextType() const
Definition: KDbField.h:353
bool isIntegerType() const
Definition: KDbField.h:326
The KDbUnaryExpression class represents unary expression (with a single argument).
Internal data class used to implement implicitly shared class KDbConstExpression.
Internal data class used to implement implicitly shared class KDbVariableExpression.
KDbEscapedString toString(const KDbDriver *driver, KDbQuerySchemaParameterValueListIterator *params=nullptr, KDb::ExpressionCallStack *callStack=nullptr) const
bool isTextType() const
ExplicitlySharedExpressionDataPointer d
bool isValid() const
ExpressionClass
Classes of expressions.
bool isNumericType() const
Definition: KDbField.h:317
Internal data class used to implement implicitly shared class KDbNArgExpression.
bool isDateTimeType() const
Definition: KDbField.h:344
The KDbNArgExpression class represents a base class N-argument expression.
KDbToken token() const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
KDbExpression clone() const
Creates a deep (not shallow) copy of the KDbExpression.
KDb::ExpressionClass expressionClass() const
virtual void debugInternal(QDebug dbg, KDb::ExpressionCallStack *callStack) const
Sends information about this expression to debug output dbg (internal).
bool isIntegerType() const
QString fromLatin1(const char *str, int size)
bool isNull() const
void insertEmptyChild(int i)
Used for inserting placeholders, e.g. in KDbBinaryExpression::KDbBinaryExpression()
KDbNArgExpression toNArg() const
Convenience type casts.
Internal data class used to implement implicitly shared class KDbFunctionExpression.
int value() const
Definition: KDbToken.h:85
bool isDateTimeType() const
The KDbConstExpression class represents const expression.
QList< ExplicitlySharedExpressionDataPointer > children() const
The KDbExpression class represents a base class for all expressions.
Definition: KDbExpression.h:51
KDbField::Type type() const
The KDbFunctionExpression class represents expression that use functional notation F(x,...
QString & append(QChar ch)
void getQueryParameters(QList< KDbQuerySchemaParameter > *params)
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.