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{
69 KDb::ExpressionCallStack callStack;
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
108KDbField::Type KDbExpressionData::type(KDb::ExpressionCallStack* callStack) const
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
238QDebug KDbExpressionData::debug(QDebug dbg, KDb::ExpressionCallStack* callStack) const
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
254void KDbExpressionData::debugInternal(QDebug dbg, KDb::ExpressionCallStack* callStack) const
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
282KDbExpression::KDbExpression(const ExplicitlySharedExpressionDataPointer &ptr)
283 : d(ptr ? ptr : ExplicitlySharedExpressionDataPointer(new KDbExpressionData))
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
539KDbNArgExpression KDbExpression::toNArg() const
540{
541 return CAST(KDbNArgExpression);
542}
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
The KDbBinaryExpression class represents binary operation.
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
The KDbFunctionExpression class represents expression that use functional notation F(x,...
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
The KDbUnaryExpression class represents unary expression (with a single argument).
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 & 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-2025 The KDE developers.
Generated on Fri Feb 21 2025 11:51:49 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.