KDb

KDbExpression.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
3 Copyright (C) 2014 Radoslaw Wicik <radoslaw@wicik.pl>
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
35class KDbExpressionClassNames
36{
37public:
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
59Q_GLOBAL_STATIC(KDbExpressionClassNames, KDb_expressionClassNames)
60
61KDB_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
67KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbExpression& expr)
68{
70 return expr.debug(dbg.nospace(), &callStack);
71}
72
73//=========================================
74
75KDbExpressionData::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
91KDbExpressionData::~KDbExpressionData()
92{
93 //ExpressionDebug << "~KDbExpressionData" << ref;
94}
95
96KDbExpressionData* KDbExpressionData::clone()
97{
98 ExpressionDebug << "KDbExpressionData::clone" << *this;
99 return new KDbExpressionData(*this);
100}
101
102KDbField::Type KDbExpressionData::typeInternal(KDb::ExpressionCallStack* callStack) const
103{
104 Q_UNUSED(callStack);
106}
107
109{
110 if (!addToCallStack(nullptr, callStack)) {
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
124bool KDbExpressionData::isValid() const
125{
126 return type() != KDbField::InvalidType;
127}
128
129bool KDbExpressionData::isTextType() const
130{
131 return KDbField::isTextType(type());
132}
133
134bool KDbExpressionData::isIntegerType() const
135{
137}
138
139bool KDbExpressionData::isNumericType() const
140{
142}
143
144bool KDbExpressionData::isFPNumericType() const
145{
147}
148
149bool KDbExpressionData::isDateTimeType() const
150{
152}
153
154bool KDbExpressionData::validate(KDbParseInfo *parseInfo)
155{
156 KDb::ExpressionCallStack callStack;
157 return validate(parseInfo, &callStack);
158}
159
160bool 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
170bool KDbExpressionData::validateInternal(KDbParseInfo *parseInfo, KDb::ExpressionCallStack* callStack)
171{
172 Q_UNUSED(parseInfo);
173 Q_UNUSED(callStack);
174 return true;
175}
176
177KDbEscapedString 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
200KDbEscapedString 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
211void KDbExpressionData::getQueryParameters(QList<KDbQuerySchemaParameter>* params)
212{
213 Q_UNUSED(params);
214}
215
216bool 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 : qAsConst(*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
248QDebug 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
287KDbExpression::~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
325bool 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
374
375void KDbExpression::appendChild(const KDbExpression& child)
376{
377 appendChild(child.d);
378}
379
380void 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
388void 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
407bool 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
415void 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
425KDbExpression 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
438int KDbExpression::indexOfChild(const KDbExpression& child, int from) const
439{
440 return d->children.indexOf(child.d, from);
441}
442
443int KDbExpression::lastIndexOfChild(const KDbExpression& child, int from) const
444{
445 return d->children.lastIndexOf(child.d, from);
446}
447
448bool 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
461void 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
484QDebug KDbExpression::debug(QDebug dbg, KDb::ExpressionCallStack* callStack) const
485{
486 if (d)
487 d->debug(dbg, callStack);
488 return dbg.space();
489}
490
491bool KDbExpression::operator==(const KDbExpression& e) const
492{
493 return d == e.d;
494}
495
496bool KDbExpression::operator!=(const KDbExpression& e) const
497{
498 return !operator==(e);
499}
500
501bool KDbExpression::isNArg() const
502{
503 return d->convertConst<KDbNArgExpressionData>();
504}
505
506bool KDbExpression::isUnary() const
507{
508 return d->convertConst<KDbUnaryExpressionData>();
509}
510
511bool KDbExpression::isBinary() const
512{
513 return d->convertConst<KDbBinaryExpressionData>();
514}
515
516bool KDbExpression::isConst() const
517{
518 return d->convertConst<KDbConstExpressionData>();
519}
520
521bool KDbExpression::isVariable() const
522{
523 return d->convertConst<KDbVariableExpressionData>();
524}
525
526bool KDbExpression::isFunction() const
527{
528 return d->convertConst<KDbFunctionExpressionData>();
529}
530
531bool KDbExpression::isQueryParameter() const
532{
533 return d->convertConst<KDbQueryParameterExpressionData>();
534}
535
536#define CAST(T) \
537 d->convert<T ## Data>() ? T(d) : T()
538
543
544KDbUnaryExpression KDbExpression::toUnary() const
545{
546 return CAST(KDbUnaryExpression);
547}
548
549KDbBinaryExpression KDbExpression::toBinary() const
550{
551 return CAST(KDbBinaryExpression);
552}
553
554KDbConstExpression KDbExpression::toConst() const
555{
556 return CAST(KDbConstExpression);
557}
558
559KDbQueryParameterExpression KDbExpression::toQueryParameter() const
560{
561 return CAST(KDbQueryParameterExpression);
562}
563
564KDbVariableExpression KDbExpression::toVariable() const
565{
566 return CAST(KDbVariableExpression);
567}
568
569KDbFunctionExpression 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
Internal data class used to implement implicitly shared class KDbBinaryExpression.
The KDbBinaryExpression class represents binary operation.
Internal data class used to implement implicitly shared class KDbConstExpression.
The KDbConstExpression class represents const expression.
Database driver's abstraction.
Definition KDbDriver.h:50
static QString defaultSqlTypeName(KDbField::Type type)
Specialized string for escaping.
Internal data class used to implement implicitly shared class KDbExpression.
KDbField::Type type() const
virtual void debugInternal(QDebug dbg, KDb::ExpressionCallStack *callStack) const
Sends information about this expression to debug output dbg (internal).
QDebug debug(QDebug dbg, KDb::ExpressionCallStack *callStack) const
Sends information about this expression to debug output dbg.
The KDbExpression class represents a base class for all expressions.
bool isFPNumericType() const
bool isNull() const
KDb::ExpressionClass expressionClass() const
static KDb::ExpressionClass classForToken(KDbToken token)
bool validate(KDbParseInfo *parseInfo)
bool isTextType() const
void setExpressionClass(KDb::ExpressionClass aClass)
void setToken(KDbToken token)
KDbToken token() const
KDbExpression parent() const
KDbEscapedString toString(const KDbDriver *driver, KDbQuerySchemaParameterValueListIterator *params=nullptr, KDb::ExpressionCallStack *callStack=nullptr) const
bool isNumericType() const
bool isDateTimeType() const
void getQueryParameters(QList< KDbQuerySchemaParameter > *params)
void setLeftOrRight(const KDbExpression &right, int index)
Only for KDbBinaryExpression::setLeft() and KDbBinaryExpression::setRight()
void insertEmptyChild(int i)
Used for inserting placeholders, e.g. in KDbBinaryExpression::KDbBinaryExpression()
KDbField::Type type() const
KDbExpression clone() const
Creates a deep (not shallow) copy of the KDbExpression.
bool isIntegerType() const
bool isValid() const
QList< ExplicitlySharedExpressionDataPointer > children() const
KDbNArgExpression toNArg() const
Convenience type casts.
ExplicitlySharedExpressionDataPointer d
bool isNumericType() const
Definition KDbField.h:317
bool isTextType() const
Definition KDbField.h:353
bool isDateTimeType() const
Definition KDbField.h:344
@ InvalidType
Definition KDbField.h:86
bool isFPNumericType() const
Definition KDbField.h:335
bool isIntegerType() const
Definition KDbField.h:326
Internal data class used to implement implicitly shared class KDbFunctionExpression.
The KDbFunctionExpression class represents expression that use functional notation F(x,...
Internal data class used to implement implicitly shared class KDbNArgExpression.
The KDbNArgExpression class represents a base class N-argument expression.
Internal data class used to implement implicitly shared class KDbQueryParameterExpression.
The KDbQueryParameterExpression class represents query parameter expression.
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:37
int value() const
Definition KDbToken.h:85
Internal data class used to implement implicitly shared class KDbUnaryExpression.
The KDbUnaryExpression class represents unary expression (with a single argument).
Internal data class used to implement implicitly shared class KDbVariableExpression.
The KDbVariableExpression class represents variables such as fieldname or tablename....
A database connectivity and creation framework.
ExpressionClass
Classes of expressions.
QStringView level(QStringView ifopt)
QDebug operator<<(QDebug dbg, const PerceptualColor::LchaDouble &value)
QDebug & noquote()
QDebug & nospace()
QDebug & space()
void append(QList< T > &&value)
bool contains(const AT &value) const const
qsizetype length() const const
void removeLast()
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
QTextStream & endl(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:59 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.