QGIS API Documentation 4.3.0-Master (16eddb2670e)
Loading...
Searching...
No Matches
qgsexpressionnodeimpl.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpressionnodeimpl.cpp
3 -------------------
4 begin : May 2017
5 copyright : (C) 2017 Matthias Kuhn
6 email : matthias@opengis.ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsexpression.h"
19#include "qgsexpressionutils.h"
20#include "qgsstringutils.h"
21#include "qgsvariantutils.h"
22
23#include <QColor>
24#include <QDate>
25#include <QDateTime>
26#include <QRegularExpression>
27#include <QString>
28#include <QTime>
29
30using namespace Qt::StringLiterals;
31
32const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] = {
33 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
34 "OR", "AND", "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT", "+", "-", "*", "/", "//", "%", "^", "||"
35};
36
37const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] = {
38 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
39 "NOT",
40 "-"
41};
42
44{
45 bool needs = false;
46 const QList< QgsExpressionNode * > nodeList = mList->list();
47 for ( QgsExpressionNode *n : nodeList )
48 needs |= n->needsGeometry();
49 return needs;
50}
51
53{
54 qDeleteAll( mList );
55}
56
58{
59 mList.append( node->node );
60 mNameList.append( cleanNamedNodeName( node->name ) );
61 mHasNamedNodes = true;
62 delete node;
63}
64
66{
67 NodeList *nl = new NodeList;
68 for ( QgsExpressionNode *node : mList )
69 {
70 nl->mList.append( node->clone() );
71 }
72 nl->mNameList = mNameList;
73
74 return nl;
75}
76
78{
79 QString msg;
80 bool first = true;
81 for ( QgsExpressionNode *n : mList )
82 {
83 if ( !first )
84 msg += ", "_L1;
85 else
86 first = false;
87 msg += n->dump();
88 }
89 return msg;
90}
91
92QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
93{
94 QString cleaned = name.toLower();
95
96 // upgrade older argument names to standard versions
97 if ( cleaned == "geom"_L1 )
98 cleaned = u"geometry"_s;
99 else if ( cleaned == "val"_L1 )
100 cleaned = u"value"_s;
101 else if ( cleaned == "geometry a"_L1 )
102 cleaned = u"geometry1"_s;
103 else if ( cleaned == "geometry b"_L1 )
104 cleaned = u"geometry2"_s;
105 else if ( cleaned == "i"_L1 )
106 cleaned = u"vertex"_s;
107 else if ( cleaned == "array_a"_L1 )
108 cleaned = u"array1"_s;
109 else if ( cleaned == "array_b"_L1 )
110 cleaned = u"array2"_s;
111 else if ( cleaned == "point_a"_L1 )
112 cleaned = u"point1"_s;
113 else if ( cleaned == "point_b"_L1 )
114 cleaned = u"point2"_s;
115 else if ( cleaned == "array_prioritize"_L1 )
116 cleaned = u"priority"_s;
117
118 return cleaned;
119}
120
121
122//
123
125{
126 QVariant val = mOperand->eval( parent, context );
128
129 switch ( mOp )
130 {
131 case uoNot:
132 {
133 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
135 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
136 }
137
138 case uoMinus:
139 if ( QgsExpressionUtils::isIntSafe( val ) )
140 return QVariant( -QgsExpressionUtils::getIntValue( val, parent ) );
141 else if ( QgsExpressionUtils::isDoubleSafe( val ) )
142 return QVariant( -QgsExpressionUtils::getDoubleValue( val, parent ) );
143 else
144 SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
145 }
146 return QVariant();
147}
148
153
155{
156 return mOperand->prepare( parent, context );
157}
158
160{
161 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand.get() ) )
162 return u"%1 ( %2 )"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
163 else
164 return u"%1 %2"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
165}
166
168{
169 if ( hasCachedStaticValue() )
170 return QSet< QString >();
171
172 return mOperand->referencedColumns();
173}
174
176{
177 return mOperand->referencedVariables();
178}
179
181{
182 return mOperand->referencedFunctions();
183}
184
185QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
186{
187 QList<const QgsExpressionNode *> lst;
188 lst.append( this );
189 lst += mOperand->nodes();
190 return lst;
191}
192
194{
195 return mOperand->needsGeometry();
196}
197
199{
200 QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
201 cloneTo( copy );
202 return copy;
203}
204
206{
207 std::unique_ptr< QgsExpressionNode > simplifiedOperand( mOperand->simplifiedNode() );
208 if ( simplifiedOperand->nodeType() == ntLiteral )
209 {
210 QgsExpressionNodeUnaryOperator tempNode( mOp, simplifiedOperand->clone() );
211 QgsExpression parentExp;
212 QVariant result = tempNode.eval( &parentExp, nullptr );
213 if ( !parentExp.hasEvalError() )
214 {
215 return new QgsExpressionNodeLiteral( result );
216 }
217 }
218
219 return new QgsExpressionNodeUnaryOperator( mOp, simplifiedOperand.release() );
220}
221
223{
224 return mOperand->isStatic( parent, context );
225}
226
228{
229 return UNARY_OPERATOR_TEXT[mOp];
230}
231
232//
233
235{
236 switch ( op )
237 {
239 return diff == 0;
241 return diff != 0;
243 return diff < 0;
245 return diff > 0;
247 return diff <= 0;
249 return diff >= 0;
250 default:
251 Q_ASSERT( false );
252 return false;
253 }
254}
255
257{
258 switch ( op )
259 {
261 return qgsDoubleNear( diff, 0.0 );
263 return !qgsDoubleNear( diff, 0.0 );
265 return diff < 0;
267 return diff > 0;
269 return diff <= 0;
271 return diff >= 0;
272 default:
273 Q_ASSERT( false );
274 return false;
275 }
276}
277
278QVariant QgsExpressionNodeBinaryOperator::compareNonNullValues( QgsExpression *parent, const QgsExpressionContext *, const QVariant &vL, const QVariant &vR, BinaryOperator op )
279{
280 if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
281 {
282 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
284 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
286
287 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
288 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
289 // results (due to different hidden timezones), we force all datetime comparisons to treat
290 // all datetime values as having the same time zone
291 dL.setTimeSpec( Qt::UTC );
292 dR.setTimeSpec( Qt::UTC );
293
294 return compareOp<qint64>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
295 }
296 else if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QString ) || ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QDateTime ) )
297 {
298 // left operand is a datetime, right is a string (or vice versa) -- here we try to implicitly cast the string operand to a datetime.
299 QDateTime dL;
300 if ( vL.userType() == QMetaType::Type::QDateTime )
301 {
302 dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
303 }
304 else
305 {
306 dL = QDateTime::fromString( vL.toString(), Qt::ISODate );
307 if ( !dL.isValid() )
308 {
309 if ( parent )
310 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( vL.toString() ) );
311 return QVariant();
312 }
313 }
315
316 QDateTime dR;
317 if ( vR.userType() == QMetaType::Type::QDateTime )
318 {
319 dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
320 }
321 else
322 {
323 dR = QDateTime::fromString( vR.toString(), Qt::ISODate );
324 if ( !dR.isValid() )
325 {
326 if ( parent )
327 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( vR.toString() ) );
328 return QVariant();
329 }
330 }
332
333 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
334 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
335 // results (due to different hidden timezones), we force all datetime comparisons to treat
336 // all datetime values as having the same time zone
337 dL.setTimeSpec( Qt::UTC );
338 dR.setTimeSpec( Qt::UTC );
339
340 return compareOp<qint64>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
341 }
342 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QString ) || ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QDate ) )
343 {
344 // left operand is a date, right is a string (or vice versa) -- here we try to implicitly cast the string operand to a date.
345 QDate dL;
346 if ( vL.userType() == QMetaType::Type::QDate )
347 {
348 dL = QgsExpressionUtils::getDateValue( vL, parent );
349 }
350 else
351 {
352 dL = QDate::fromString( vL.toString(), Qt::ISODate );
353 if ( !dL.isValid() )
354 {
355 if ( parent )
356 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( vL.toString() ) );
357 return QVariant();
358 }
359 }
361
362 QDate dR;
363 if ( vR.userType() == QMetaType::Type::QDate )
364 {
365 dR = QgsExpressionUtils::getDateValue( vR, parent );
366 }
367 else
368 {
369 dR = QDate::fromString( vR.toString(), Qt::ISODate );
370 if ( !dR.isValid() )
371 {
372 if ( parent )
373 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( vR.toString() ) );
374 return QVariant();
375 }
376 }
378
379 return compareOp<qint64>( dR.daysTo( dL ), op ) ? TVL_True : TVL_False;
380 }
381 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QString ) || ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QTime ) )
382 {
383 // left operand is a time, right is a string (or vice versa) -- here we try to implicitly cast the string operand to a time.
384 QTime dL;
385 if ( vL.userType() == QMetaType::Type::QTime )
386 {
387 dL = QgsExpressionUtils::getTimeValue( vL, parent );
388 }
389 else
390 {
391 dL = QTime::fromString( vL.toString(), Qt::ISODate );
392 if ( !dL.isValid() )
393 {
394 if ( parent )
395 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( vL.toString() ) );
396 return QVariant();
397 }
398 }
400
401 QTime dR;
402 if ( vR.userType() == QMetaType::Type::QTime )
403 {
404 dR = QgsExpressionUtils::getTimeValue( vR, parent );
405 }
406 else
407 {
408 dR = QTime::fromString( vR.toString(), Qt::ISODate );
409 if ( !dR.isValid() )
410 {
411 if ( parent )
412 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( vR.toString() ) );
413 return QVariant();
414 }
415 }
417
418 return compareOp<int>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
419 }
420 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
421 {
422 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
424 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
426 return compareOp<qint64>( dR.daysTo( dL ), op ) ? TVL_True : TVL_False;
427 }
428 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
429 {
430 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
432 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
434 return compareOp<int>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
435 }
436 else if ( ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
437 {
438 // do numeric comparison if both operators can be converted to numbers,
439 // and they aren't both string
440 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
442 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
444 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
445 }
446
447 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
448 {
449 // Documented behavior of QVariant::toBool() for each userType:
450 //
451 // For variant with userType():
452 //
453 // QMetaType::Bool:
454 // true if value is true
455 // false otherwise
456 //
457 // QMetaType::QChar, QMetaType::Double, QMetaType::Int,
458 // QMetaType::LongLong, QMetaType::UInt, and QMetaType::ULongLong:
459 // true if the value is non-zero
460 // false otherwise
461 //
462 // QMetaType::QString and QMetaType::QByteArray:
463 // false if its lower-case content is empty, "0" or "false"
464 // true otherwise
465 //
466 // All other variants always return false.
467
468 // Note: Boolean logical operators behave the same in C++ and SQL.
469 const bool vLBool = vL.toBool();
470 const bool vRBool = vR.toBool();
471 switch ( op )
472 {
473 case boEQ:
474 return vLBool == vRBool ? TVL_True : TVL_False;
475 case boNE:
476 return vLBool != vRBool ? TVL_True : TVL_False;
477 case boLT:
478 return vLBool < vRBool ? TVL_True : TVL_False;
479 case boLE:
480 return vLBool <= vRBool ? TVL_True : TVL_False;
481 case boGT:
482 return vLBool > vRBool ? TVL_True : TVL_False;
483 case boGE:
484 return vLBool >= vRBool ? TVL_True : TVL_False;
485 case boOr:
486 case boAnd:
487 case boRegexp:
488 case boLike:
489 case boNotLike:
490 case boILike:
491 case boNotILike:
492 case boIs:
493 case boIsNot:
494 case boPlus:
495 case boMinus:
496 case boMul:
497 case boDiv:
498 case boIntDiv:
499 case boMod:
500 case boPow:
501 case boConcat:
502 // should not happen
503 break;
504 }
505 return TVL_Unknown;
506 }
507
508 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
509 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
510 {
511 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
513 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
515 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
516 }
517 else
518 {
519 // do string comparison otherwise
520 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
522 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
524 int diff = QString::compare( sL, sR );
525 return compareOp<int>( diff, op ) ? TVL_True : TVL_False;
526 }
527}
528
530{
531 QVariant vL = mOpLeft->eval( parent, context );
533
534 if ( mOp == boAnd || mOp == boOr )
535 {
536 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
538 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
539 return TVL_False; // shortcut -- no need to evaluate right-hand side
540 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
541 return TVL_True; // shortcut -- no need to evaluate right-hand side
542 }
543
544 QVariant vR = mOpRight->eval( parent, context );
546
547 switch ( mOp )
548 {
549 case boPlus:
550 if ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
551 {
552 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
554 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
556 return QVariant( sL + sR );
557 }
558 //intentional fall-through
559 [[fallthrough]];
560 case boMinus:
561 case boMul:
562 case boDiv:
563 case boMod:
564 {
565 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
566 return QVariant();
567 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
568 {
569 // both are integers - let's use integer arithmetic
570 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
572 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
574
575 if ( mOp == boMod && iR == 0 )
576 return QVariant();
577
578 return QVariant( computeInt( iL, iR ) );
579 }
580 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
581 {
582 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
584 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
586 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
587 {
588 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
589 return QVariant();
590 }
591 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
592 }
593 else if ( mOp == boPlus
594 && ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) || ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
595 {
596 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
598 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
600 QDateTime dt = QDateTime( date, time );
601 return QVariant( dt );
602 }
603 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
604 {
605 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
607 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
609 return date1 - date2;
610 }
611 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
612 {
613 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
615 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
617 return time1 - time2;
618 }
619 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
620 {
621 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
623 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
625 return QgsInterval( datetime1 - datetime2 );
626 }
627 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv ) && vL.userType() == QMetaType::Type::QColor && vR.userType() == QMetaType::Type::QColor )
628 {
629 bool isQColor = false;
630 const QColor colorL = QgsExpressionUtils::getColorValue( vL, parent, isQColor );
632 const QColor colorR = QgsExpressionUtils::getColorValue( vR, parent, isQColor );
634
635 if ( !colorL.isValid() || !colorR.isValid() )
636 {
637 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
638 return QVariant();
639 }
640
641 QColor::Spec colorLSpec = colorL.spec();
642 QColor::Spec colorRSpec = colorR.spec();
643
644 switch ( colorLSpec )
645 {
646 case QColor::Cmyk:
647 {
648 if ( colorRSpec != QColor::Cmyk )
649 {
650 parent->setEvalErrorString( tr( "Cannot combine a CMYK color with a non-CMYK color" ) );
651 return QVariant();
652 }
653
654 float lc, lm, ly, lk, la, rc, rm, ry, rk, ra;
655 colorL.getCmykF( &lc, &lm, &ly, &lk, &la );
656 colorR.getCmykF( &rc, &rm, &ry, &rk, &ra );
657 return QColor::fromCmykF(
658 static_cast<float>( std::clamp( computeDouble( lc, rc ), 0.0, 1.0 ) ),
659 static_cast<float>( std::clamp( computeDouble( lm, rm ), 0.0, 1.0 ) ),
660 static_cast<float>( std::clamp( computeDouble( ly, ry ), 0.0, 1.0 ) ),
661 static_cast<float>( std::clamp( computeDouble( lk, rk ), 0.0, 1.0 ) ),
662 la
663 );
664 }
665 case QColor::Hsl:
666 case QColor::Hsv:
667 case QColor::Rgb:
668 case QColor::ExtendedRgb:
669 {
670 if ( colorRSpec == QColor::Cmyk )
671 {
672 parent->setEvalErrorString( tr( "Cannot combine a non-CMYK color with a CMYK color" ) );
673 return QVariant();
674 }
675
676 float lr, lg, lb, la, rr, rg, rb, ra;
677 colorL.getRgbF( &lr, &lg, &lb, &la );
678 colorR.getRgbF( &rr, &rg, &rb, &ra );
679 QColor result = QColor::
680 fromRgbF( static_cast<float>( std::clamp( computeDouble( lr, rr ), 0.0, 1.0 ) ), static_cast<float>( std::clamp( computeDouble( lg, rg ), 0.0, 1.0 ) ), static_cast<float>( std::clamp( computeDouble( lb, rb ), 0.0, 1.0 ) ), la );
681 return result;
682 }
683 default:
684 return QVariant();
685 }
686 }
687 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv )
688 && ( ( ( vL.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vR ) ) || ( ( vR.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vL ) ) ) )
689 {
690 const bool colorLeft = vL.userType() == QMetaType::Type::QColor;
691 bool isQColor = false;
692 const QColor color = QgsExpressionUtils::getColorValue( colorLeft ? vL : vR, parent, isQColor );
694
695 if ( !color.isValid() )
696 {
697 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
698 return QVariant();
699 }
700
701 const double value = QgsExpressionUtils::getDoubleValue( colorLeft ? vR : vL, parent );
703
704 if ( mOp == boDiv && value == 0.0 )
705 {
706 return QVariant();
707 }
708
709 // let's not divide with color
710 if ( !colorLeft && mOp == boDiv )
711 {
712 parent->setEvalErrorString( tr( "Can't perform / with a color value on the right" ) );
713 return QVariant();
714 }
715
716 switch ( color.spec() )
717 {
718 case QColor::Cmyk:
719 {
720 float c, m, y, k, a;
721 color.getCmykF( &c, &m, &y, &k, &a );
722 const double dc = static_cast<double>( c );
723 const double dm = static_cast<double>( m );
724 const double dy = static_cast<double>( y );
725 const double dk = static_cast<double>( k );
726
727 return QColor::fromCmykF(
728 static_cast<float>( std::clamp( computeDouble( colorLeft ? dc : value, colorLeft ? value : dc ), 0.0, 1.0 ) ),
729 static_cast<float>( std::clamp( computeDouble( colorLeft ? dm : value, colorLeft ? value : dm ), 0.0, 1.0 ) ),
730 static_cast<float>( std::clamp( computeDouble( colorLeft ? dy : value, colorLeft ? value : dy ), 0.0, 1.0 ) ),
731 static_cast<float>( std::clamp( computeDouble( colorLeft ? dk : value, colorLeft ? value : dk ), 0.0, 1.0 ) ),
732 a
733 );
734 }
735 case QColor::Hsl:
736 case QColor::Hsv:
737 case QColor::Rgb:
738 case QColor::ExtendedRgb: // color_rgbf constructor clamps it to 0-1, so we do the same here
739 {
740 float r, g, b, a;
741 color.getRgbF( &r, &g, &b, &a );
742 const double dr = static_cast<double>( r );
743 const double dg = static_cast<double>( g );
744 const double db = static_cast<double>( b );
745
746 return QColor::fromRgbF(
747 static_cast<float>( std::clamp( computeDouble( colorLeft ? dr : value, colorLeft ? value : dr ), 0.0, 1.0 ) ),
748 static_cast<float>( std::clamp( computeDouble( colorLeft ? dg : value, colorLeft ? value : dg ), 0.0, 1.0 ) ),
749 static_cast<float>( std::clamp( computeDouble( colorLeft ? db : value, colorLeft ? value : db ), 0.0, 1.0 ) ),
750 a
751 );
752 }
753 default:
754 return QVariant();
755 }
756 }
757 else
758 {
759 // general floating point arithmetic
760 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
762 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
764 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
765 return QVariant(); // silently handle division by zero and return NULL
766 return QVariant( computeDouble( fL, fR ) );
767 }
768 }
769 case boIntDiv:
770 {
771 //integer division
772 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
774 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
776 if ( fR == 0. )
777 return QVariant(); // silently handle division by zero and return NULL
778 return QVariant( qlonglong( std::floor( fL / fR ) ) );
779 }
780 case boPow:
781 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
782 return QVariant();
783 else
784 {
785 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
787 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
789 return QVariant( std::pow( fL, fR ) );
790 }
791
792 case boAnd:
793 {
794 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
796 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
797 }
798
799 case boOr:
800 {
801 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
803 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
804 }
805
806 case boEQ:
807 case boNE:
808 case boLT:
809 case boGT:
810 case boLE:
811 case boGE:
812 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
813 {
814 return TVL_Unknown;
815 }
816 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
817 {
818 // verify that we have two lists
819 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
820 return TVL_Unknown;
821
822 // and search for not equal respective items
823 QVariantList lL = vL.toList();
824 QVariantList lR = vR.toList();
825 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
826 {
827 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
828 continue; // same behavior as PostgreSQL
829
830 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
831 {
832 switch ( mOp )
833 {
834 case boEQ:
835 return false;
836 case boNE:
837 return true;
838 case boLT:
839 case boLE:
840 return QgsExpressionUtils::isNull( lR.at( i ) );
841 case boGT:
842 case boGE:
843 return QgsExpressionUtils::isNull( lL.at( i ) );
844 default:
845 Q_ASSERT( false );
846 return TVL_Unknown;
847 }
848 }
849
850 QgsExpressionNodeLiteral nL( lL.at( i ) );
851 QgsExpressionNodeLiteral nR( lR.at( i ) );
852 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
853 QVariant eq = eqNode.eval( parent, context );
855 if ( eq == TVL_False )
856 {
857 // return the two items comparison
858 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
859 QVariant v = node.eval( parent, context );
861 return v;
862 }
863 }
864
865 // default to length comparison
866 switch ( mOp )
867 {
868 case boEQ:
869 return lL.length() == lR.length();
870 case boNE:
871 return lL.length() != lR.length();
872 case boLT:
873 return lL.length() < lR.length();
874 case boGT:
875 return lL.length() > lR.length();
876 case boLE:
877 return lL.length() <= lR.length();
878 case boGE:
879 return lL.length() >= lR.length();
880 default:
881 Q_ASSERT( false );
882 return TVL_Unknown;
883 }
884 }
885 else
886 {
887 return compareNonNullValues( parent, context, vL, vR, mOp );
888 }
889
890 case boIs:
891 case boIsNot:
892 {
893 const bool vLNull = QgsExpressionUtils::isNull( vL );
894 const bool vRNull = QgsExpressionUtils::isNull( vR );
895 if ( vLNull && vRNull ) // both operators null
896 return ( mOp == boIs ? TVL_True : TVL_False );
897 else if ( vLNull || vRNull ) // one operator null
898 return ( mOp == boIs ? TVL_False : TVL_True );
899 else // both operators non-null
900 {
901 return compareNonNullValues( parent, context, vL, vR, mOp == boIs ? boEQ : boNE );
902 }
903 }
904
905 case boRegexp:
906 case boLike:
907 case boNotLike:
908 case boILike:
909 case boNotILike:
910 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
911 return TVL_Unknown;
912 else
913 {
914 const QString str = QgsExpressionUtils::getStringValue( vL, parent );
916 const QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
918
919 QRegularExpression re;
920 const QString cachedRegExKey = u"re_bo_%1_%2"_s.arg( mOp ).arg( regexp );
921 if ( context )
922 {
923 re = context->cachedValue( cachedRegExKey ).value< QRegularExpression >();
924 }
925
926 bool matches = false;
927 if ( re.pattern().isEmpty() )
928 {
929 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
930 {
931 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
932 // manage escape % and _
933 if ( esc_regexp.startsWith( '%' ) )
934 {
935 esc_regexp.replace( 0, 1, u".*"_s );
936 }
937 const thread_local QRegularExpression rx1( u"[^\\\\](%)"_s );
938 int pos = 0;
939 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
940 {
941 esc_regexp.replace( pos + 1, 1, u".*"_s );
942 pos += 1;
943 }
944 const thread_local QRegularExpression rx2( u"\\\\%"_s );
945 esc_regexp.replace( rx2, u"%"_s );
946 if ( esc_regexp.startsWith( '_' ) )
947 {
948 esc_regexp.replace( 0, 1, u"."_s );
949 }
950 const thread_local QRegularExpression rx3( u"[^\\\\](_)"_s );
951 pos = 0;
952 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
953 {
954 esc_regexp.replace( pos + 1, 1, '.' );
955 pos += 1;
956 }
957 esc_regexp.replace( "\\\\_"_L1, "_"_L1 );
958
959 re = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption );
960 }
961 else
962 {
963 re = QRegularExpression( regexp );
964 }
965 if ( context )
966 {
967 context->setCachedValue( cachedRegExKey, re );
968 }
969 }
970
971 matches = re.match( str ).hasMatch();
972
973 if ( mOp == boNotLike || mOp == boNotILike )
974 {
975 matches = !matches;
976 }
977
978 return matches ? TVL_True : TVL_False;
979 }
980
981 case boConcat:
982 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
983 return QVariant();
984 else
985 {
986 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
988 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
990 return QVariant( sL + sR );
991 }
992 }
993 Q_ASSERT( false );
994 return QVariant();
995}
996
997qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
998{
999 switch ( mOp )
1000 {
1001 case boPlus:
1002 return x + y;
1003 case boMinus:
1004 return x - y;
1005 case boMul:
1006 return x * y;
1007 case boDiv:
1008 return x / y;
1009 case boMod:
1010 return x % y;
1011 default:
1012 Q_ASSERT( false );
1013 return 0;
1014 }
1015}
1016
1017QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
1018{
1019 switch ( mOp )
1020 {
1021 case boPlus:
1022 return d.addSecs( i->seconds() );
1023 case boMinus:
1024 return d.addSecs( -i->seconds() );
1025 default:
1026 Q_ASSERT( false );
1027 return QDateTime();
1028 }
1029}
1030
1031double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
1032{
1033 switch ( mOp )
1034 {
1035 case boPlus:
1036 return x + y;
1037 case boMinus:
1038 return x - y;
1039 case boMul:
1040 return x * y;
1041 case boDiv:
1042 return x / y;
1043 case boMod:
1044 return std::fmod( x, y );
1045 default:
1046 Q_ASSERT( false );
1047 return 0;
1048 }
1049}
1050
1055
1057{
1058 // if this is an OR, try to collapse the OR expression into an IN node
1059 if ( mOp == boOr )
1060 {
1061 // First step: flatten OR chain and collect values
1062 QMap<QString, QgsExpressionNode::NodeList> orValuesMap;
1063 QList<QString> orFieldNames;
1064
1065 // Get a list of all the OR and IN nodes chained together
1066 std::function<bool( QgsExpressionNode * )> visitOrNodes = [&visitOrNodes, &orValuesMap, &orFieldNames]( QgsExpressionNode *node ) -> bool {
1068 {
1069 if ( op->op() != boOr && op->op() != boEQ )
1070 {
1071 return false;
1072 }
1073
1074 if ( op->op() == boEQ )
1075 {
1076 // If left is a column ref and right is a literal, collect
1077 if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opLeft() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opRight() ) ) )
1078 {
1079 const QString fieldName = op->opLeft()->dump();
1080 if ( !orValuesMap.contains( fieldName ) )
1081 {
1082 orFieldNames.append( fieldName );
1083 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
1084 }
1085 orValuesMap[fieldName].append( op->opRight()->clone() );
1086 return true;
1087 }
1088 else if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opRight() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opLeft() ) ) )
1089 {
1090 const QString fieldName = op->opRight()->dump();
1091 if ( !orValuesMap.contains( fieldName ) )
1092 {
1093 orFieldNames.append( fieldName );
1094 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
1095 }
1096 orValuesMap[fieldName].append( op->opLeft()->clone() );
1097 return true;
1098 }
1099 return false;
1100 }
1101
1102 if ( visitOrNodes( op->opLeft() ) && visitOrNodes( op->opRight() ) )
1103 {
1104 return true;
1105 }
1106 }
1107 else if ( QgsExpressionNodeInOperator *inOp = dynamic_cast<QgsExpressionNodeInOperator *>( node ) )
1108 {
1109 if ( inOp->isNotIn() || inOp->node()->nodeType() != QgsExpressionNode::ntColumnRef )
1110 {
1111 return false;
1112 }
1113
1114 const QString fieldName = inOp->node()->dump();
1115
1116 // Check if all nodes are literals
1117 const auto nodes = inOp->list()->list();
1118 for ( const auto &valueNode : std::as_const( nodes ) )
1119 {
1120 if ( valueNode->nodeType() != QgsExpressionNode::ntLiteral )
1121 {
1122 return false;
1123 }
1124 }
1125
1126 auto orValuesMapIt = orValuesMap.find( fieldName );
1127 if ( orValuesMapIt == orValuesMap.end() )
1128 {
1129 orFieldNames.append( fieldName );
1130 orValuesMapIt = orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
1131 }
1132 for ( const auto &valueNode : std::as_const( nodes ) )
1133 {
1134 orValuesMapIt->append( valueNode->clone() );
1135 }
1136
1137 return true;
1138 }
1139 return false;
1140 };
1141
1142
1143 // Second step: build the OR chain of IN operators
1144 if ( visitOrNodes( this ) && !orValuesMap.empty() )
1145 {
1146 std::unique_ptr<QgsExpressionNode> currentNode;
1147 for ( const auto &fieldName : std::as_const( orFieldNames ) )
1148 {
1149 auto orValuesIt = orValuesMap.find( fieldName );
1150 if ( orValuesIt.value().count() == 1 )
1151 {
1152 auto eqNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boEQ, new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().at( 0 )->clone() );
1153 if ( currentNode )
1154 {
1155 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), eqNode.release() );
1156 }
1157 else
1158 {
1159 currentNode = std::move( eqNode );
1160 }
1161 }
1162 else
1163 {
1164 auto inNode = std::make_unique<QgsExpressionNodeInOperator>( new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().clone() );
1165 if ( currentNode )
1166 {
1167 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), inNode.release() );
1168 }
1169 else
1170 {
1171 currentNode = std::move( inNode );
1172 }
1173 }
1174 }
1175
1176
1177 if ( currentNode )
1178 {
1179 mCompiledSimplifiedNode = std::move( currentNode );
1180 }
1181 }
1182 }
1183
1184 bool resL = mOpLeft->prepare( parent, context );
1185 bool resR = mOpRight->prepare( parent, context );
1186 return resL && resR;
1187}
1188
1190{
1191 // see left/right in qgsexpressionparser.yy
1192 switch ( mOp )
1193 {
1194 case boOr:
1195 return 1;
1196
1197 case boAnd:
1198 return 2;
1199
1200 case boEQ:
1201 case boNE:
1202 case boLE:
1203 case boGE:
1204 case boLT:
1205 case boGT:
1206 case boRegexp:
1207 case boLike:
1208 case boILike:
1209 case boNotLike:
1210 case boNotILike:
1211 case boIs:
1212 case boIsNot:
1213 return 3;
1214
1215 case boPlus:
1216 case boMinus:
1217 return 4;
1218
1219 case boMul:
1220 case boDiv:
1221 case boIntDiv:
1222 case boMod:
1223 return 5;
1224
1225 case boPow:
1226 return 6;
1227
1228 case boConcat:
1229 return 7;
1230 }
1231 Q_ASSERT( false && "unexpected binary operator" );
1232 return -1;
1233}
1234
1236{
1237 // see left/right in qgsexpressionparser.yy
1238 switch ( mOp )
1239 {
1240 case boOr:
1241 case boAnd:
1242 case boEQ:
1243 case boNE:
1244 case boLE:
1245 case boGE:
1246 case boLT:
1247 case boGT:
1248 case boRegexp:
1249 case boLike:
1250 case boILike:
1251 case boNotLike:
1252 case boNotILike:
1253 case boIs:
1254 case boIsNot:
1255 case boPlus:
1256 case boMinus:
1257 case boMul:
1258 case boDiv:
1259 case boIntDiv:
1260 case boMod:
1261 case boConcat:
1262 return true;
1263
1264 case boPow:
1265 return false;
1266 }
1267 Q_ASSERT( false && "unexpected binary operator" );
1268 return false;
1269}
1270
1272{
1273 QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft.get() );
1274 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight.get() );
1275 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight.get() );
1276
1277 QString rdump( mOpRight->dump() );
1278
1279 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
1280 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
1281 {
1282 rdump.prepend( '(' ).append( ')' );
1283 }
1284
1285 QString fmt;
1286 if ( leftAssociative() )
1287 {
1288 fmt += lOp && ( lOp->precedence() < precedence() ) ? u"(%1)"_s : u"%1"_s;
1289 fmt += " %2 "_L1;
1290 fmt += rOp && ( rOp->precedence() <= precedence() ) ? u"(%3)"_s : u"%3"_s;
1291 }
1292 else
1293 {
1294 fmt += lOp && ( lOp->precedence() <= precedence() ) ? u"(%1)"_s : u"%1"_s;
1295 fmt += " %2 "_L1;
1296 fmt += rOp && ( rOp->precedence() < precedence() ) ? u"(%3)"_s : u"%3"_s;
1297 }
1298
1299 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
1300}
1301
1303{
1304 if ( hasCachedStaticValue() )
1305 return QSet< QString >();
1306
1307 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
1308}
1309
1311{
1312 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
1313}
1314
1316{
1317 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
1318}
1319
1320QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
1321{
1322 QList<const QgsExpressionNode *> lst;
1323 lst << this;
1324 lst += mOpLeft->nodes() + mOpRight->nodes();
1325 return lst;
1326}
1327
1329{
1330 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
1331}
1332
1334{
1335 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
1336 cloneTo( copy );
1337 return copy;
1338}
1339
1341{
1342 const bool leftStatic = mOpLeft->isStatic( parent, context );
1343 const bool rightStatic = mOpRight->isStatic( parent, context );
1344
1345 if ( leftStatic && rightStatic )
1346 return true;
1347
1348 // special logic for certain ops...
1349 switch ( mOp )
1350 {
1352 {
1353 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
1354 // of the value of the other node!
1355 if ( leftStatic )
1356 {
1357 mOpLeft->prepare( parent, context );
1358 if ( mOpLeft->hasCachedStaticValue() )
1359 {
1360 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1361 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1362 {
1363 mCachedStaticValue = true;
1364 mHasCachedValue = true;
1365 return true;
1366 }
1367 }
1368 }
1369 else if ( rightStatic )
1370 {
1371 mOpRight->prepare( parent, context );
1372 if ( mOpRight->hasCachedStaticValue() )
1373 {
1374 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1375 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1376 {
1377 mCachedStaticValue = true;
1378 mHasCachedValue = true;
1379 return true;
1380 }
1381 }
1382 }
1383
1384 break;
1385 }
1387 {
1388 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
1389 // of the value of the other node!
1390
1391 if ( leftStatic )
1392 {
1393 mOpLeft->prepare( parent, context );
1394 if ( mOpLeft->hasCachedStaticValue() )
1395 {
1396 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1397 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1398 {
1399 mCachedStaticValue = false;
1400 mHasCachedValue = true;
1401 return true;
1402 }
1403 }
1404 }
1405 else if ( rightStatic )
1406 {
1407 mOpRight->prepare( parent, context );
1408 if ( mOpRight->hasCachedStaticValue() )
1409 {
1410 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1411 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1412 {
1413 mCachedStaticValue = false;
1414 mHasCachedValue = true;
1415 return true;
1416 }
1417 }
1418 }
1419
1420 break;
1421 }
1422
1444 break;
1445 }
1446
1447 return false;
1448}
1449
1451{
1452 std::unique_ptr< QgsExpressionNode > opLeft( mOpLeft->simplifiedNode() );
1453 std::unique_ptr< QgsExpressionNode > opRight( mOpRight->simplifiedNode() );
1454
1455 // if both operands are literals, evaluate the operation
1456 if ( opLeft->nodeType() == ntLiteral && opRight->nodeType() == ntLiteral )
1457 {
1458 QgsExpressionNodeBinaryOperator tempNode( mOp, opLeft->clone(), opRight->clone() );
1459 QgsExpression parentExp;
1460 QVariant result = tempNode.eval( &parentExp, nullptr );
1461 if ( !parentExp.hasEvalError() )
1462 {
1463 return new QgsExpressionNodeLiteral( result );
1464 }
1465 }
1466
1467 return new QgsExpressionNodeBinaryOperator( mOp, opLeft.release(), opRight.release() );
1468}
1469
1470//
1471
1473{
1474 if ( mList->count() == 0 )
1475 return mNotIn ? TVL_True : TVL_False;
1476 QVariant v1 = mNode->eval( parent, context );
1478 if ( QgsExpressionUtils::isNull( v1 ) )
1479 return TVL_Unknown;
1480
1481 bool listHasNull = false;
1482
1483 const QList< QgsExpressionNode * > nodeList = mList->list();
1484 for ( QgsExpressionNode *n : nodeList )
1485 {
1486 QVariant v2 = n->eval( parent, context );
1488 if ( QgsExpressionUtils::isNull( v2 ) )
1489 listHasNull = true;
1490 else
1491 {
1492 bool equal = false;
1493 // check whether they are equal
1494 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
1495 {
1496 // do numeric comparison if both operators can be converted to numbers,
1497 // and they aren't both string
1498 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
1500 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
1502 equal = qgsDoubleNear( f1, f2 );
1503 }
1504 else
1505 {
1506 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1508 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1510 equal = QString::compare( s1, s2 ) == 0;
1511 }
1512
1513 if ( equal ) // we know the result
1514 return mNotIn ? TVL_False : TVL_True;
1515 }
1516 }
1517
1518 // item not found
1519 if ( listHasNull )
1520 return TVL_Unknown;
1521 else
1522 return mNotIn ? TVL_True : TVL_False;
1523}
1524
1527
1532
1534{
1535 bool res = mNode->prepare( parent, context );
1536 const QList< QgsExpressionNode * > nodeList = mList->list();
1537 for ( QgsExpressionNode *n : nodeList )
1538 {
1539 res = res && n->prepare( parent, context );
1540 }
1541 return res;
1542}
1543
1545{
1546 return u"%1 %2 IN (%3)"_s.arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1547}
1548
1550{
1551 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1552 cloneTo( copy );
1553 return copy;
1554}
1555
1557{
1558 if ( !mNode->isStatic( parent, context ) )
1559 return false;
1560
1561 const QList< QgsExpressionNode * > nodeList = mList->list();
1562 for ( QgsExpressionNode *n : nodeList )
1563 {
1564 if ( !n->isStatic( parent, context ) )
1565 return false;
1566 }
1567
1568 return true;
1569}
1570
1572{
1573 std::unique_ptr< QgsExpressionNode > simplifiedTargetNode( mNode->simplifiedNode() );
1574 bool allLiterals = simplifiedTargetNode->nodeType() == ntLiteral;
1575
1576 auto simplifiedList = std::make_unique< QgsExpressionNode::NodeList >();
1577 simplifiedList->reserve( mList->count() );
1578 for ( QgsExpressionNode *node : mList->list() )
1579 {
1580 std::unique_ptr< QgsExpressionNode > simplifiedItem( node->simplifiedNode() );
1581 if ( simplifiedItem->nodeType() != ntLiteral )
1582 {
1583 allLiterals = false;
1584 }
1585
1586 if ( simplifiedTargetNode->nodeType() == ntLiteral
1587 && simplifiedItem->nodeType() == ntLiteral
1588 && qgis::down_cast< QgsExpressionNodeLiteral *>( simplifiedTargetNode.get() )->value() == qgis::down_cast< QgsExpressionNodeLiteral * >( simplifiedItem.get() )->value() )
1589 {
1590 return new QgsExpressionNodeLiteral( !mNotIn );
1591 }
1592
1593 simplifiedList->append( simplifiedItem.release() );
1594 }
1595
1596 // if target node and all items in the list are literals, we can just directly evaluate and replace with a literal
1597 if ( allLiterals )
1598 {
1599 QgsExpressionNodeInOperator tempNode( simplifiedTargetNode->clone(), simplifiedList->clone(), mNotIn );
1600 QgsExpression parentExp;
1601 QVariant result = tempNode.eval( &parentExp, nullptr );
1602 if ( !parentExp.hasEvalError() )
1603 {
1604 return new QgsExpressionNodeLiteral( result );
1605 }
1606 }
1607
1608 return new QgsExpressionNodeInOperator( simplifiedTargetNode.release(), simplifiedList.release(), mNotIn );
1609}
1610
1611//
1612
1614{
1616 const QString name = func->name();
1617
1618 QVariant res;
1619 if ( context && context->hasFunction( name ) )
1620 {
1621 QgsExpressionFunction *fd = context->function( name );
1622 res = fd->run( mArgs.get(), context, parent, this );
1623 }
1624 else
1625 {
1626 res = func->run( mArgs.get(), context, parent, this );
1627 }
1629
1630 // everything went fine
1631 return res;
1632}
1633
1637
1639 : mFunction( function )
1640{
1641 const QgsExpressionFunction::ParameterList &functionParams = mFunction->parameters();
1642 const qsizetype functionParamsSize = functionParams.size();
1643 if ( functionParams.isEmpty() )
1644 {
1645 // function does not support parameters
1646 mArgs.reset( args );
1647 }
1648 else if ( !args )
1649 {
1650 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1651 mArgs = std::make_unique<NodeList>();
1652 mArgs->reserve( functionParamsSize );
1653 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1654 {
1655 // insert default value for QgsExpressionFunction::Parameter
1656 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1657 }
1658 }
1659 else
1660 {
1661 mArgs = std::make_unique<NodeList>();
1662 mArgs->reserve( functionParamsSize );
1663
1664 int idx = 0;
1665 const QStringList argNames = args->names();
1666 const QList<QgsExpressionNode *> argList = args->list();
1667 //first loop through unnamed arguments
1668 {
1669 const qsizetype argNamesSize = argNames.size();
1670 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1671 {
1672 mArgs->append( argList.at( idx )->clone() );
1673 idx++;
1674 }
1675 }
1676
1677 //next copy named QgsExpressionFunction::Parameters in order expected by function
1678 for ( ; idx < functionParamsSize; ++idx )
1679 {
1680 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1681 qsizetype nodeIdx = argNames.indexOf( parameter.name().toLower() );
1682 if ( nodeIdx < 0 )
1683 {
1684 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1685 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1686 }
1687 else
1688 {
1689 mArgs->append( argList.at( nodeIdx )->clone() );
1690 }
1691 }
1692
1693 delete args;
1694 }
1695}
1696
1697
1700
1702{
1704 return functions->functionIndex( mFunction->name() );
1705}
1706
1707std::shared_ptr<QgsExpressionFunction> QgsExpressionNodeFunction::function() const
1708{
1709 return mFunction;
1710}
1711
1716
1718{
1720 bool res = func->prepare( this, parent, context );
1721 if ( mArgs && !func->lazyEval() )
1722 {
1723 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1724 for ( QgsExpressionNode *n : nodeList )
1725 {
1726 res = res && n->prepare( parent, context );
1727 }
1728 }
1729 return res;
1730}
1731
1733{
1735 if ( func->params() == 0 )
1736 return u"%1%2"_s.arg( func->name(), func->name().startsWith( '$' ) ? QString() : u"()"_s ); // special column
1737 else
1738 return u"%1(%2)"_s.arg( func->name(), mArgs ? mArgs->dump() : QString() ); // function
1739}
1740
1742{
1743 if ( hasCachedStaticValue() )
1744 return QSet< QString >();
1745
1747 QSet<QString> functionColumns = func->referencedColumns( this );
1748
1749 if ( !mArgs )
1750 {
1751 //no referenced columns in arguments, just return function's referenced columns
1752 return functionColumns;
1753 }
1754
1755 int paramIndex = 0;
1756 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1757 for ( QgsExpressionNode *n : nodeList )
1758 {
1759 if ( func->parameters().count() <= paramIndex || !func->parameters().at( paramIndex ).isSubExpression() )
1760 functionColumns.unite( n->referencedColumns() );
1761 paramIndex++;
1762 }
1763
1764 return functionColumns;
1765}
1766
1768{
1770 if ( func->name() == "var"_L1 )
1771 {
1772 if ( !mArgs->list().isEmpty() )
1773 {
1774 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1775 if ( var )
1776 return QSet<QString>() << var->value().toString();
1777 }
1778 return QSet<QString>() << QString();
1779 }
1780 else
1781 {
1782 QSet<QString> functionVariables = QSet<QString>();
1783
1784 if ( !mArgs )
1785 return functionVariables;
1786
1787 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1788 for ( QgsExpressionNode *n : nodeList )
1789 {
1790 functionVariables.unite( n->referencedVariables() );
1791 }
1792
1793 return functionVariables;
1794 }
1795}
1796
1798{
1800 QSet<QString> functions = QSet<QString>();
1801 functions.insert( func->name() );
1802
1803 if ( !mArgs )
1804 return functions;
1805
1806 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1807 for ( QgsExpressionNode *n : nodeList )
1808 {
1809 functions.unite( n->referencedFunctions() );
1810 }
1811 return functions;
1812}
1813
1814QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1815{
1816 QList<const QgsExpressionNode *> lst;
1817 lst << this;
1818 if ( !mArgs )
1819 return lst;
1820
1821 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1822 for ( QgsExpressionNode *n : nodeList )
1823 {
1824 lst += n->nodes();
1825 }
1826 return lst;
1827}
1828
1830{
1832 bool needs = func->usesGeometry( this );
1833 if ( mArgs )
1834 {
1835 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1836 for ( QgsExpressionNode *n : nodeList )
1837 needs |= n->needsGeometry();
1838 }
1839 return needs;
1840}
1841
1843{
1845 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( func, mArgs ? mArgs->clone() : nullptr );
1846 cloneTo( copy );
1847 return copy;
1848}
1849
1851{
1853 return func->isStatic( this, parent, context );
1854}
1855
1857{
1858 auto simplifiedArgs = std::make_unique< QgsExpressionNode::NodeList >();
1859 if ( mArgs )
1860 {
1861 simplifiedArgs->reserve( mArgs->count() );
1862 for ( QgsExpressionNode *arg : mArgs->list() )
1863 {
1864 std::unique_ptr< QgsExpressionNode > simplifiedArg( arg->simplifiedNode() );
1865 simplifiedArgs->append( simplifiedArg.release() );
1866 }
1867
1868 return new QgsExpressionNodeFunction( function(), simplifiedArgs.release() );
1869 }
1870 return clone();
1871}
1872
1874{
1875 if ( !args || !args->hasNamedNodes() )
1876 return true;
1877
1879 const QgsExpression::SharedFunctionPtr fd = functions->getFunction( fnIndex );
1880
1881 const QgsExpressionFunction::ParameterList &functionParams = fd->parameters();
1882 if ( functionParams.isEmpty() )
1883 {
1884 error = u"%1 does not support named QgsExpressionFunction::Parameters"_s.arg( fd->name() );
1885 return false;
1886 }
1887 else
1888 {
1889 QSet< int > providedArgs;
1890 QSet< int > handledArgs;
1891 int idx = 0;
1892 //first loop through unnamed arguments
1893 while ( args->names().at( idx ).isEmpty() )
1894 {
1895 providedArgs << idx;
1896 handledArgs << idx;
1897 idx++;
1898 }
1899
1900 //next check named QgsExpressionFunction::Parameters
1901 for ( ; idx < functionParams.count(); ++idx )
1902 {
1903 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1904 if ( nodeIdx < 0 )
1905 {
1906 if ( !functionParams.at( idx ).optional() )
1907 {
1908 error = u"No value specified for QgsExpressionFunction::Parameter '%1' for %2"_s.arg( functionParams.at( idx ).name(), fd->name() );
1909 return false;
1910 }
1911 }
1912 else
1913 {
1914 if ( providedArgs.contains( idx ) )
1915 {
1916 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( idx ).name(), fd->name() );
1917 return false;
1918 }
1919 }
1920 providedArgs << idx;
1921 handledArgs << nodeIdx;
1922 }
1923
1924 //last check for bad names
1925 idx = 0;
1926 const QStringList nameList = args->names();
1927 for ( const QString &name : nameList )
1928 {
1929 if ( !name.isEmpty() && !functionParams.contains( name ) )
1930 {
1931 error = u"Invalid QgsExpressionFunction::Parameter name '%1' for %2"_s.arg( name, fd->name() );
1932 return false;
1933 }
1934 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1935 {
1936 int functionIdx = functionParams.indexOf( name );
1937 if ( providedArgs.contains( functionIdx ) )
1938 {
1939 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( functionIdx ).name(), fd->name() );
1940 return false;
1941 }
1942 }
1943 idx++;
1944 }
1945 }
1946 return true;
1947}
1948
1949//
1950
1952{
1953 Q_UNUSED( context )
1954 Q_UNUSED( parent )
1955 return mValue;
1956}
1957
1962
1964{
1965 Q_UNUSED( parent )
1966 Q_UNUSED( context )
1967 return true;
1968}
1969
1970
1972{
1973 if ( QgsVariantUtils::isNull( mValue ) )
1974 return u"NULL"_s;
1975
1976 switch ( mValue.userType() )
1977 {
1978 case QMetaType::Type::Int:
1979 return QString::number( mValue.toInt() );
1980 case QMetaType::Type::Double:
1981 return qgsDoubleToString( mValue.toDouble() );
1982 case QMetaType::Type::LongLong:
1983 return QString::number( mValue.toLongLong() );
1984 case QMetaType::Type::QString:
1985 return QgsExpression::quotedString( mValue.toString() );
1986 case QMetaType::Type::QTime:
1987 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1988 case QMetaType::Type::QDate:
1989 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1990 case QMetaType::Type::QDateTime:
1991 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1992 case QMetaType::Type::Bool:
1993 return mValue.toBool() ? u"TRUE"_s : u"FALSE"_s;
1994 default:
1995 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1996 }
1997}
1998
2000{
2001 return valueAsString();
2002}
2003
2005{
2006 return QSet<QString>();
2007}
2008
2010{
2011 return QSet<QString>();
2012}
2013
2015{
2016 return QSet<QString>();
2017}
2018
2019QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
2020{
2021 QList<const QgsExpressionNode *> lst;
2022 lst << this;
2023 return lst;
2024}
2025
2027{
2028 return false;
2029}
2030
2032{
2034 cloneTo( copy );
2035 return copy;
2036}
2037
2039{
2040 Q_UNUSED( context )
2041 Q_UNUSED( parent )
2042 return true;
2043}
2044
2045//
2046
2048{
2049 Q_UNUSED( parent )
2050 int index = mIndex;
2051
2052 if ( index < 0 )
2053 {
2054 // have not yet found field index - first check explicitly set fields collection
2055 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
2056 {
2057 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
2058 index = fields.lookupField( mName );
2059 }
2060 }
2061
2062 if ( context )
2063 {
2064 QgsFeature feature = context->feature();
2065 if ( feature.isValid() )
2066 {
2067 if ( index >= 0 )
2068 return feature.attribute( index );
2069 else
2070 return feature.attribute( mName );
2071 }
2072 else
2073 {
2074 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
2075 }
2076 }
2077 if ( index < 0 )
2078 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
2079 return QVariant();
2080}
2081
2086
2088{
2089 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
2090 return false;
2091
2092 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
2093
2094 mIndex = fields.lookupField( mName );
2095
2096 if ( mIndex == -1 && context->hasFeature() )
2097 {
2098 mIndex = context->feature().fieldNameIndex( mName );
2099 }
2100
2101 if ( mIndex == -1 )
2102 {
2103 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
2104 return false;
2105 }
2106 return true;
2107}
2108
2110{
2111 const thread_local QRegularExpression re( u"^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$"_s );
2112 const QRegularExpressionMatch match = re.match( mName );
2113 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
2114}
2115
2117{
2118 return QSet<QString>() << mName;
2119}
2120
2122{
2123 return QSet<QString>();
2124}
2125
2127{
2128 return QSet<QString>();
2129}
2130
2131QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
2132{
2133 QList<const QgsExpressionNode *> result;
2134 result << this;
2135 return result;
2136}
2137
2139{
2140 return false;
2141}
2142
2144{
2146 cloneTo( copy );
2147 return copy;
2148}
2149
2151{
2152 Q_UNUSED( context )
2153 Q_UNUSED( parent )
2154 return false;
2155}
2156
2157//
2158
2165
2167{
2168 qDeleteAll( mConditions );
2169}
2170
2175
2177{
2178 for ( WhenThen *cond : std::as_const( mConditions ) )
2179 {
2180 QVariant vWhen = cond->mWhenExp->eval( parent, context );
2181 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
2183 if ( tvl == QgsExpressionUtils::True )
2184 {
2185 QVariant vRes = cond->mThenExp->eval( parent, context );
2187 return vRes;
2188 }
2189 }
2190
2191 if ( mElseExp )
2192 {
2193 QVariant vElse = mElseExp->eval( parent, context );
2195 return vElse;
2196 }
2197
2198 // return NULL if no condition is matching
2199 return QVariant();
2200}
2201
2203{
2204 bool foundAnyNonStaticConditions = false;
2205 for ( WhenThen *cond : std::as_const( mConditions ) )
2206 {
2207 const bool res = cond->mWhenExp->prepare( parent, context ) && cond->mThenExp->prepare( parent, context );
2208 if ( !res )
2209 return false;
2210
2211 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
2212 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
2213 {
2214 // ok, we now that we'll ALWAYS be picking the same condition, as the "WHEN" clause for this condition (and all previous conditions) is a static
2215 // value, and the static value for this WHEN clause is True.
2216 if ( cond->mThenExp->hasCachedStaticValue() )
2217 {
2218 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
2219 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
2220 mHasCachedValue = true;
2221 return true;
2222 }
2223 else
2224 {
2225 // we know at least that we'll ALWAYS be picking the same condition, so even though the THEN node is non-static we can effectively replace
2226 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
2227 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
2228 return true;
2229 }
2230 }
2231 }
2232
2233 if ( mElseExp )
2234 {
2235 const bool res = mElseExp->prepare( parent, context );
2236 if ( !res )
2237 return false;
2238
2239 if ( !foundAnyNonStaticConditions )
2240 {
2241 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
2242 if ( mElseExp->hasCachedStaticValue() )
2243 {
2244 mCachedStaticValue = mElseExp->cachedStaticValue();
2245 mHasCachedValue = true;
2246 return true;
2247 }
2248 else
2249 {
2250 // so even though the ELSE node is non-static we can effectively replace
2251 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
2252 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
2253 return true;
2254 }
2255 }
2256 }
2257
2258 return true;
2259}
2260
2262{
2263 QString msg( u"CASE"_s );
2264 for ( WhenThen *cond : mConditions )
2265 {
2266 msg += u" WHEN %1 THEN %2"_s.arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
2267 }
2268 if ( mElseExp )
2269 msg += u" ELSE %1"_s.arg( mElseExp->dump() );
2270 msg += " END"_L1;
2271 return msg;
2272}
2273
2275{
2276 if ( hasCachedStaticValue() )
2277 return QSet< QString >();
2278
2279 QSet<QString> lst;
2280 for ( WhenThen *cond : mConditions )
2281 {
2282 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
2283 }
2284
2285 if ( mElseExp )
2286 lst += mElseExp->referencedColumns();
2287
2288 return lst;
2289}
2290
2292{
2293 QSet<QString> lst;
2294 for ( WhenThen *cond : mConditions )
2295 {
2296 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
2297 }
2298
2299 if ( mElseExp )
2300 lst += mElseExp->referencedVariables();
2301
2302 return lst;
2303}
2304
2306{
2307 QSet<QString> lst;
2308 for ( WhenThen *cond : mConditions )
2309 {
2310 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
2311 }
2312
2313 if ( mElseExp )
2314 lst += mElseExp->referencedFunctions();
2315
2316 return lst;
2317}
2318
2319QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
2320{
2321 QList<const QgsExpressionNode *> lst;
2322 lst << this;
2323 for ( WhenThen *cond : mConditions )
2324 {
2325 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
2326 }
2327
2328 if ( mElseExp )
2329 lst += mElseExp->nodes();
2330
2331 return lst;
2332}
2333
2335{
2336 for ( WhenThen *cond : mConditions )
2337 {
2338 if ( cond->mWhenExp->needsGeometry() || cond->mThenExp->needsGeometry() )
2339 return true;
2340 }
2341
2342 return mElseExp && mElseExp->needsGeometry();
2343}
2344
2346{
2348 conditions.reserve( mConditions.size() );
2349 for ( WhenThen *wt : mConditions )
2350 conditions.append( wt->clone() );
2351
2352 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
2353 cloneTo( copy );
2354 return copy;
2355}
2356
2358{
2359 for ( WhenThen *wt : mConditions )
2360 {
2361 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
2362 return false;
2363 }
2364
2365 if ( mElseExp )
2366 return mElseExp->isStatic( parent, context );
2367
2368 return true;
2369}
2370
2372{
2373 auto simplifiedWhenThenList = std::make_unique< QgsExpressionNodeCondition::WhenThenList >();
2374 for ( QgsExpressionNodeCondition::WhenThen *clause : mConditions )
2375 {
2376 std::unique_ptr< QgsExpressionNode > simplifiedWhen( clause->whenExp()->simplifiedNode() );
2377 std::unique_ptr< QgsExpressionNode > simplifiedThen( clause->thenExp()->simplifiedNode() );
2378
2379 // if when condition is literal and TRUE we can just return the simplified THEN node
2380 if ( simplifiedWhenThenList->isEmpty() && simplifiedWhen->nodeType() == ntLiteral && simplifiedWhen->eval( nullptr, nullptr ).toBool() )
2381 {
2382 return simplifiedThen.release();
2383 }
2384 // if when simplifies to literal and FALSE, skip this condition as it can never be reached
2385 else if ( simplifiedWhen->nodeType() == ntLiteral && !simplifiedWhen->eval( nullptr, nullptr ).toBool() )
2386 {
2387 continue;
2388 }
2389
2390 simplifiedWhenThenList->append( new QgsExpressionNodeCondition::WhenThen( simplifiedWhen.release(), simplifiedThen.release() ) );
2391 }
2392
2393 std::unique_ptr< QgsExpressionNode > simplifiedElse( mElseExp ? mElseExp->simplifiedNode() : nullptr );
2394 if ( simplifiedWhenThenList->isEmpty() )
2395 {
2396 return simplifiedElse ? simplifiedElse.release() : new QgsExpressionNodeLiteral( QVariant() );
2397 }
2398
2399 return new QgsExpressionNodeCondition( simplifiedWhenThenList.release(), simplifiedElse.release() );
2400}
2401
2403{
2404 if ( hasCachedStaticValue() )
2405 return QSet< QString >();
2406
2407 QSet<QString> lst( mNode->referencedColumns() );
2408 const QList< QgsExpressionNode * > nodeList = mList->list();
2409 for ( const QgsExpressionNode *n : nodeList )
2410 lst.unite( n->referencedColumns() );
2411 return lst;
2412}
2413
2415{
2416 QSet<QString> lst( mNode->referencedVariables() );
2417 const QList< QgsExpressionNode * > nodeList = mList->list();
2418 for ( const QgsExpressionNode *n : nodeList )
2419 lst.unite( n->referencedVariables() );
2420 return lst;
2421}
2422
2424{
2425 QSet<QString> lst( mNode->referencedFunctions() );
2426 const QList< QgsExpressionNode * > nodeList = mList->list();
2427 for ( const QgsExpressionNode *n : nodeList )
2428 lst.unite( n->referencedFunctions() );
2429 return lst;
2430}
2431
2432QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
2433{
2434 QList<const QgsExpressionNode *> lst;
2435 lst << this;
2436 lst << mNode.get();
2437 const QList< QgsExpressionNode * > nodeList = mList->list();
2438 for ( const QgsExpressionNode *n : nodeList )
2439 lst += n->nodes();
2440 return lst;
2441}
2442
2443
2446
2451
2453{
2454 bool res = mNode->prepare( parent, context );
2455 res = res && mLowerBound->prepare( parent, context );
2456 res = res && mHigherBound->prepare( parent, context );
2457 return res;
2458}
2459
2461{
2462 const QVariant nodeVal = mNode->eval( parent, context );
2463 if ( QgsVariantUtils::isNull( nodeVal ) )
2464 {
2465 return QVariant();
2466 }
2467
2468 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
2469
2471 const QVariant lowBoundValue = lowBound.eval( parent, context );
2472 const bool lowBoundBool { lowBoundValue.toBool() };
2473
2474 if ( !QgsVariantUtils::isNull( lowBoundValue ) && !lowBoundBool )
2475 {
2476 return QVariant( mNegate );
2477 }
2478
2480 const QVariant highBoundValue = highBound.eval( parent, context );
2481
2482 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2483 {
2484 return QVariant();
2485 }
2486
2487 const bool highBoundBool { highBoundValue.toBool() };
2488
2489 // We already checked if both are nulls
2490 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2491 {
2492 // In this case we can return a boolean
2493 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && !highBoundBool ) || ( QgsVariantUtils::isNull( highBoundValue ) && !lowBoundBool ) )
2494 {
2495 return QVariant( mNegate );
2496 }
2497
2498 // Indetermined
2499 return QVariant();
2500 }
2501
2502 if ( !QgsVariantUtils::isNull( highBoundValue ) && !highBoundBool )
2503 {
2504 return QVariant( mNegate );
2505 }
2506
2507 const bool res { lowBoundBool && highBoundBool };
2508 return mNegate ? QVariant( !res ) : QVariant( res );
2509}
2510
2512{
2513 return u"%1 %2 %3 AND %4"_s.arg( mNode->dump(), mNegate ? u"NOT BETWEEN"_s : u"BETWEEN"_s, mLowerBound->dump(), mHigherBound->dump() );
2514}
2515
2517{
2518 QSet<QString> lst( mNode->referencedVariables() );
2519 lst.unite( mLowerBound->referencedVariables() );
2520 lst.unite( mHigherBound->referencedVariables() );
2521 return lst;
2522}
2523
2525{
2526 QSet<QString> lst( mNode->referencedFunctions() );
2527 lst.unite( mLowerBound->referencedFunctions() );
2528 lst.unite( mHigherBound->referencedFunctions() );
2529 return lst;
2530}
2531
2532QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2533{
2534 return { this, mLowerBound.get(), mHigherBound.get() };
2535}
2536
2538{
2539 QSet<QString> lst( mNode->referencedColumns() );
2540 lst.unite( mLowerBound->referencedColumns() );
2541 lst.unite( mHigherBound->referencedColumns() );
2542 return lst;
2543}
2544
2546{
2547 if ( mNode->needsGeometry() )
2548 return true;
2549
2550 if ( mLowerBound->needsGeometry() )
2551 return true;
2552
2553 if ( mHigherBound->needsGeometry() )
2554 return true;
2555
2556 return false;
2557}
2558
2560{
2561 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2562 cloneTo( copy );
2563 return copy;
2564}
2565
2567{
2568 if ( !mNode->isStatic( parent, context ) )
2569 return false;
2570
2571 if ( !mLowerBound->isStatic( parent, context ) )
2572 return false;
2573
2574 if ( !mHigherBound->isStatic( parent, context ) )
2575 return false;
2576
2577 return true;
2578}
2579
2581{
2582 return mLowerBound.get();
2583}
2584
2586{
2587 return mHigherBound.get();
2588}
2589
2591{
2592 return mNegate;
2593}
2594
2599
2602
2604{
2605 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2606}
2607
2609{
2610 return BINARY_OPERATOR_TEXT[mOp];
2611}
2612
2613//
2614
2616{
2617 const QVariant container = mContainer->eval( parent, context );
2619 const QVariant index = mIndex->eval( parent, context );
2621
2622 switch ( container.userType() )
2623 {
2624 case QMetaType::Type::QVariantMap:
2625 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2626
2627 case QMetaType::Type::QVariantList:
2628 case QMetaType::Type::QStringList:
2629 {
2630 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2631 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2632 if ( pos >= list.length() || pos < -list.length() )
2633 {
2634 return QVariant();
2635 }
2636 if ( pos < 0 )
2637 {
2638 // negative indices are from back of list
2639 pos += list.length();
2640 }
2641
2642 return list.at( pos );
2643 }
2644
2645 default:
2647 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2648 return QVariant();
2649 }
2650}
2651
2656
2658{
2659 bool resC = mContainer->prepare( parent, context );
2660 bool resV = mIndex->prepare( parent, context );
2661 return resC && resV;
2662}
2663
2665{
2666 return u"%1[%2]"_s.arg( mContainer->dump(), mIndex->dump() );
2667}
2668
2670{
2671 if ( hasCachedStaticValue() )
2672 return QSet< QString >();
2673
2674 return mContainer->referencedColumns() + mIndex->referencedColumns();
2675}
2676
2678{
2679 return mContainer->referencedVariables() + mIndex->referencedVariables();
2680}
2681
2683{
2684 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2685}
2686
2687QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2688{
2689 QList<const QgsExpressionNode *> lst;
2690 lst << this;
2691 lst += mContainer->nodes() + mIndex->nodes();
2692 return lst;
2693}
2694
2696{
2697 return mContainer->needsGeometry() || mIndex->needsGeometry();
2698}
2699
2701{
2702 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2703 cloneTo( copy );
2704 return copy;
2705}
2706
2708{
2709 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2710}
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
void setCachedValue(const QString &key, const QVariant &value) const
Sets a value to cache within the expression context.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
QVariant cachedValue(const QString &key) const
Returns the matching cached value, if set.
bool hasFeature() const
Returns true if the context has a feature associated with it.
Represents a single parameter passed to a function.
QVariant defaultValue() const
Returns the default value for the parameter.
QString name() const
Returns the name of the parameter.
An abstract base class for defining QgsExpression functions.
QList< QgsExpressionFunction::Parameter > ParameterList
List of parameters, used for function definition.
virtual QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)
Evaluates the function, first evaluating all required arguments before passing them to the function's...
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
bool negate() const
Returns true if the predicate is an exclusion test (NOT BETWEEN).
QgsExpressionNode * lowerBound() const
Returns the lower bound expression node of the range.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * higherBound() const
Returns the higher bound expression node of the range.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeBetweenOperator(QgsExpressionNode *node, QgsExpressionNode *nodeLowerBound, QgsExpressionNode *nodeHigherBound, bool negate=false)
This node tests if the result of node is between the result of nodeLowerBound and nodeHigherBound nod...
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
A binary expression operator, which operates on two values.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
bool leftAssociative() const
Returns true if the operator is left-associative.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
int precedence() const
Returns the precedence index for the operator.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
QgsExpressionNodeBinaryOperator(QgsExpressionNodeBinaryOperator::BinaryOperator op, QgsExpressionNode *opLeft, QgsExpressionNode *opRight)
Binary combination of the left and the right with op.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
An expression node which takes its value from a feature's field.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNodeColumnRef(const QString &name)
Constructor for QgsExpressionNodeColumnRef, referencing the column with the specified name.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
Represents a "WHEN... THEN..." portation of a CASE WHEN clause in an expression.
WhenThen(QgsExpressionNode *whenExp, QgsExpressionNode *thenExp)
A combination of when and then.
QgsExpressionNode * thenExp() const
The expression node that makes the THEN result part of the condition.
QgsExpressionNode * whenExp() const
The expression that makes the WHEN part of the condition.
QgsExpressionNodeCondition::WhenThen * clone() const
Gets a deep copy of this WhenThen combination.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QList< QgsExpressionNodeCondition::WhenThen * > WhenThenList
QgsExpressionNodeCondition(QgsExpressionNodeCondition::WhenThenList *conditions, QgsExpressionNode *elseExp=nullptr)
Create a new node with the given list of conditions and an optional elseExp expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
WhenThenList conditions() const
The list of WHEN THEN expression parts of the expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
int fnIndex() const
Returns the index of the node's function.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
std::shared_ptr< QgsExpressionFunction > function() const
Returns a reference to the node's function.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNodeFunction(int fnIndex, QgsExpressionNode::NodeList *args)
A function node consists of an index of the function in the global function array and a list of argum...
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
static bool validateParams(int fnIndex, QgsExpressionNode::NodeList *args, QString &error)
Tests whether the provided argument list is valid for the matching function.
An expression node for value IN or NOT IN clauses.
QgsExpressionNode * node() const
Returns the expression node.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QgsExpressionNodeInOperator(QgsExpressionNode *node, QgsExpressionNode::NodeList *list, bool notin=false)
This node tests if the result of node is in the result of list.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsExpressionNodeIndexOperator(QgsExpressionNode *container, QgsExpressionNode *index)
Constructor for QgsExpressionNodeIndexOperator.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QgsExpressionNode * index() const
Returns the index node, representing an array element index or map key.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * container() const
Returns the container node, representing an array or map value.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
An expression node for literal values.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString valueAsString() const
Returns a string representation of the node's literal value.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QVariant value() const
The value of the literal.
QgsExpressionNodeLiteral(const QVariant &value)
Constructor for QgsExpressionNodeLiteral, with the specified literal value.
A unary node is either negative as in boolean (not) or as in numbers (minus).
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNodeUnaryOperator::UnaryOperator op() const
Returns the unary operator.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeUnaryOperator(QgsExpressionNodeUnaryOperator::UnaryOperator op, QgsExpressionNode *operand)
A node unary operator is modifying the value of operand by negating it with op.
QString text() const
Returns a the name of this operator without the operands.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
A list of expression nodes.
virtual QString dump() const
Returns a string dump of the expression node.
QgsExpressionNode::NodeList * clone() const
Creates a deep copy of this list. Ownership is transferred to the caller.
void append(QgsExpressionNode *node)
Takes ownership of the provided node.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
QVariant eval(QgsExpression *parent, const QgsExpressionContext *context)
Evaluate this node with the given context and parent.
virtual QgsExpressionNode * clone() const =0
Generate a clone of this node.
bool mHasCachedValue
true if the node has a static, precalculated value.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
QgsExpressionNode()=default
std::unique_ptr< QgsExpressionNode > mCompiledSimplifiedNode
Contains a compiled node which represents a simplified version of this node as a result of compilatio...
NodeType
Known node types.
@ ntBetweenOperator
Between operator.
@ ntIndexOperator
Index operator.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
Handles parsing and evaluation of expressions (formerly called "search strings").
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes).
std::shared_ptr< const SharedFunctionPtrList > FunctionListSnapshot
static const FunctionListSnapshot getFunctionsSnapshot()
Returns a thread-safe snapshot of all registered functions.
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions).
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
std::shared_ptr< QgsExpressionFunction > SharedFunctionPtr
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Container of fields for a vector layer.
Definition qgsfields.h:45
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A representation of the interval between two datetime values.
Definition qgsinterval.h:52
double seconds() const
Returns the interval duration in seconds.
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:7650
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7743
bool compareOp(T diff, QgsExpressionNodeBinaryOperator::BinaryOperator op)
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.