QGIS API Documentation 4.1.0-Master (31622b25bb0)
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
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 return mOperand->isStatic( parent, context );
208}
209
211{
212 return UNARY_OPERATOR_TEXT[mOp];
213}
214
215//
216
218{
219 switch ( op )
220 {
222 return diff == 0;
224 return diff != 0;
226 return diff < 0;
228 return diff > 0;
230 return diff <= 0;
232 return diff >= 0;
233 default:
234 Q_ASSERT( false );
235 return false;
236 }
237}
238
240{
241 switch ( op )
242 {
244 return qgsDoubleNear( diff, 0.0 );
246 return !qgsDoubleNear( diff, 0.0 );
248 return diff < 0;
250 return diff > 0;
252 return diff <= 0;
254 return diff >= 0;
255 default:
256 Q_ASSERT( false );
257 return false;
258 }
259}
260
261QVariant QgsExpressionNodeBinaryOperator::compareNonNullValues( QgsExpression *parent, const QgsExpressionContext *, const QVariant &vL, const QVariant &vR, BinaryOperator op )
262{
263 if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
264 {
265 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
267 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
269
270 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
271 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
272 // results (due to different hidden timezones), we force all datetime comparisons to treat
273 // all datetime values as having the same time zone
274 dL.setTimeSpec( Qt::UTC );
275 dR.setTimeSpec( Qt::UTC );
276
277 return compareOp<qint64>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
278 }
279 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
280 {
281 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
283 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
285 return compareOp<qint64>( dR.daysTo( dL ), op ) ? TVL_True : TVL_False;
286 }
287 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
288 {
289 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
291 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
293 return compareOp<int>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
294 }
295 else if ( ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
296 {
297 // do numeric comparison if both operators can be converted to numbers,
298 // and they aren't both string
299 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
301 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
303 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
304 }
305
306 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
307 {
308 // Documented behavior of QVariant::toBool() for each userType:
309 //
310 // For variant with userType():
311 //
312 // QMetaType::Bool:
313 // true if value is true
314 // false otherwise
315 //
316 // QMetaType::QChar, QMetaType::Double, QMetaType::Int,
317 // QMetaType::LongLong, QMetaType::UInt, and QMetaType::ULongLong:
318 // true if the value is non-zero
319 // false otherwise
320 //
321 // QMetaType::QString and QMetaType::QByteArray:
322 // false if its lower-case content is empty, "0" or "false"
323 // true otherwise
324 //
325 // All other variants always return false.
326
327 // Note: Boolean logical operators behave the same in C++ and SQL.
328 const bool vLBool = vL.toBool();
329 const bool vRBool = vR.toBool();
330 switch ( op )
331 {
332 case boEQ:
333 return vLBool == vRBool ? TVL_True : TVL_False;
334 case boNE:
335 return vLBool != vRBool ? TVL_True : TVL_False;
336 case boLT:
337 return vLBool < vRBool ? TVL_True : TVL_False;
338 case boLE:
339 return vLBool <= vRBool ? TVL_True : TVL_False;
340 case boGT:
341 return vLBool > vRBool ? TVL_True : TVL_False;
342 case boGE:
343 return vLBool >= vRBool ? TVL_True : TVL_False;
344 case boOr:
345 case boAnd:
346 case boRegexp:
347 case boLike:
348 case boNotLike:
349 case boILike:
350 case boNotILike:
351 case boIs:
352 case boIsNot:
353 case boPlus:
354 case boMinus:
355 case boMul:
356 case boDiv:
357 case boIntDiv:
358 case boMod:
359 case boPow:
360 case boConcat:
361 // should not happen
362 break;
363 }
364 return TVL_Unknown;
365 }
366
367 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
368 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
369 {
370 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
372 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
374 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
375 }
376 else
377 {
378 // do string comparison otherwise
379 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
381 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
383 int diff = QString::compare( sL, sR );
384 return compareOp<int>( diff, op ) ? TVL_True : TVL_False;
385 }
386}
387
389{
390 QVariant vL = mOpLeft->eval( parent, context );
392
393 if ( mOp == boAnd || mOp == boOr )
394 {
395 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
397 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
398 return TVL_False; // shortcut -- no need to evaluate right-hand side
399 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
400 return TVL_True; // shortcut -- no need to evaluate right-hand side
401 }
402
403 QVariant vR = mOpRight->eval( parent, context );
405
406 switch ( mOp )
407 {
408 case boPlus:
409 if ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
410 {
411 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
413 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
415 return QVariant( sL + sR );
416 }
417 //intentional fall-through
418 [[fallthrough]];
419 case boMinus:
420 case boMul:
421 case boDiv:
422 case boMod:
423 {
424 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
425 return QVariant();
426 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
427 {
428 // both are integers - let's use integer arithmetic
429 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
431 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
433
434 if ( mOp == boMod && iR == 0 )
435 return QVariant();
436
437 return QVariant( computeInt( iL, iR ) );
438 }
439 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
440 {
441 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
443 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
445 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
446 {
447 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
448 return QVariant();
449 }
450 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
451 }
452 else if ( mOp == boPlus
453 && ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) || ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
454 {
455 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
457 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
459 QDateTime dt = QDateTime( date, time );
460 return QVariant( dt );
461 }
462 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
463 {
464 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
466 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
468 return date1 - date2;
469 }
470 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
471 {
472 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
474 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
476 return time1 - time2;
477 }
478 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
479 {
480 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
482 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
484 return QgsInterval( datetime1 - datetime2 );
485 }
486 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv ) && vL.userType() == QMetaType::Type::QColor && vR.userType() == QMetaType::Type::QColor )
487 {
488 bool isQColor = false;
489 const QColor colorL = QgsExpressionUtils::getColorValue( vL, parent, isQColor );
491 const QColor colorR = QgsExpressionUtils::getColorValue( vR, parent, isQColor );
493
494 if ( !colorL.isValid() || !colorR.isValid() )
495 {
496 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
497 return QVariant();
498 }
499
500 QColor::Spec colorLSpec = colorL.spec();
501 QColor::Spec colorRSpec = colorR.spec();
502
503 switch ( colorLSpec )
504 {
505 case QColor::Cmyk:
506 {
507 if ( colorRSpec != QColor::Cmyk )
508 {
509 parent->setEvalErrorString( tr( "Cannot combine a CMYK color with a non-CMYK color" ) );
510 return QVariant();
511 }
512
513 float lc, lm, ly, lk, la, rc, rm, ry, rk, ra;
514 colorL.getCmykF( &lc, &lm, &ly, &lk, &la );
515 colorR.getCmykF( &rc, &rm, &ry, &rk, &ra );
516 return QColor::fromCmykF(
517 static_cast<float>( std::clamp( computeDouble( lc, rc ), 0.0, 1.0 ) ),
518 static_cast<float>( std::clamp( computeDouble( lm, rm ), 0.0, 1.0 ) ),
519 static_cast<float>( std::clamp( computeDouble( ly, ry ), 0.0, 1.0 ) ),
520 static_cast<float>( std::clamp( computeDouble( lk, rk ), 0.0, 1.0 ) ),
521 la
522 );
523 }
524 case QColor::Hsl:
525 case QColor::Hsv:
526 case QColor::Rgb:
527 case QColor::ExtendedRgb:
528 {
529 if ( colorRSpec == QColor::Cmyk )
530 {
531 parent->setEvalErrorString( tr( "Cannot combine a non-CMYK color with a CMYK color" ) );
532 return QVariant();
533 }
534
535 float lr, lg, lb, la, rr, rg, rb, ra;
536 colorL.getRgbF( &lr, &lg, &lb, &la );
537 colorR.getRgbF( &rr, &rg, &rb, &ra );
538 QColor result = QColor::
539 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 );
540 return result;
541 }
542 default:
543 return QVariant();
544 }
545 }
546 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv )
547 && ( ( ( vL.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vR ) ) || ( ( vR.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vL ) ) ) )
548 {
549 const bool colorLeft = vL.userType() == QMetaType::Type::QColor;
550 bool isQColor = false;
551 const QColor color = QgsExpressionUtils::getColorValue( colorLeft ? vL : vR, parent, isQColor );
553
554 if ( !color.isValid() )
555 {
556 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
557 return QVariant();
558 }
559
560 const double value = QgsExpressionUtils::getDoubleValue( colorLeft ? vR : vL, parent );
562
563 if ( mOp == boDiv && value == 0.0 )
564 {
565 return QVariant();
566 }
567
568 // let's not divide with color
569 if ( !colorLeft && mOp == boDiv )
570 {
571 parent->setEvalErrorString( tr( "Can't perform / with a color value on the right" ) );
572 return QVariant();
573 }
574
575 switch ( color.spec() )
576 {
577 case QColor::Cmyk:
578 {
579 float c, m, y, k, a;
580 color.getCmykF( &c, &m, &y, &k, &a );
581 const double dc = static_cast<double>( c );
582 const double dm = static_cast<double>( m );
583 const double dy = static_cast<double>( y );
584 const double dk = static_cast<double>( k );
585
586 return QColor::fromCmykF(
587 static_cast<float>( std::clamp( computeDouble( colorLeft ? dc : value, colorLeft ? value : dc ), 0.0, 1.0 ) ),
588 static_cast<float>( std::clamp( computeDouble( colorLeft ? dm : value, colorLeft ? value : dm ), 0.0, 1.0 ) ),
589 static_cast<float>( std::clamp( computeDouble( colorLeft ? dy : value, colorLeft ? value : dy ), 0.0, 1.0 ) ),
590 static_cast<float>( std::clamp( computeDouble( colorLeft ? dk : value, colorLeft ? value : dk ), 0.0, 1.0 ) ),
591 a
592 );
593 }
594 case QColor::Hsl:
595 case QColor::Hsv:
596 case QColor::Rgb:
597 case QColor::ExtendedRgb: // color_rgbf constructor clamps it to 0-1, so we do the same here
598 {
599 float r, g, b, a;
600 color.getRgbF( &r, &g, &b, &a );
601 const double dr = static_cast<double>( r );
602 const double dg = static_cast<double>( g );
603 const double db = static_cast<double>( b );
604
605 return QColor::fromRgbF(
606 static_cast<float>( std::clamp( computeDouble( colorLeft ? dr : value, colorLeft ? value : dr ), 0.0, 1.0 ) ),
607 static_cast<float>( std::clamp( computeDouble( colorLeft ? dg : value, colorLeft ? value : dg ), 0.0, 1.0 ) ),
608 static_cast<float>( std::clamp( computeDouble( colorLeft ? db : value, colorLeft ? value : db ), 0.0, 1.0 ) ),
609 a
610 );
611 }
612 default:
613 return QVariant();
614 }
615 }
616 else
617 {
618 // general floating point arithmetic
619 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
621 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
623 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
624 return QVariant(); // silently handle division by zero and return NULL
625 return QVariant( computeDouble( fL, fR ) );
626 }
627 }
628 case boIntDiv:
629 {
630 //integer division
631 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
633 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
635 if ( fR == 0. )
636 return QVariant(); // silently handle division by zero and return NULL
637 return QVariant( qlonglong( std::floor( fL / fR ) ) );
638 }
639 case boPow:
640 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
641 return QVariant();
642 else
643 {
644 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
646 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
648 return QVariant( std::pow( fL, fR ) );
649 }
650
651 case boAnd:
652 {
653 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
655 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
656 }
657
658 case boOr:
659 {
660 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
662 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
663 }
664
665 case boEQ:
666 case boNE:
667 case boLT:
668 case boGT:
669 case boLE:
670 case boGE:
671 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
672 {
673 return TVL_Unknown;
674 }
675 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
676 {
677 // verify that we have two lists
678 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
679 return TVL_Unknown;
680
681 // and search for not equal respective items
682 QVariantList lL = vL.toList();
683 QVariantList lR = vR.toList();
684 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
685 {
686 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
687 continue; // same behavior as PostgreSQL
688
689 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
690 {
691 switch ( mOp )
692 {
693 case boEQ:
694 return false;
695 case boNE:
696 return true;
697 case boLT:
698 case boLE:
699 return QgsExpressionUtils::isNull( lR.at( i ) );
700 case boGT:
701 case boGE:
702 return QgsExpressionUtils::isNull( lL.at( i ) );
703 default:
704 Q_ASSERT( false );
705 return TVL_Unknown;
706 }
707 }
708
709 QgsExpressionNodeLiteral nL( lL.at( i ) );
710 QgsExpressionNodeLiteral nR( lR.at( i ) );
711 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
712 QVariant eq = eqNode.eval( parent, context );
714 if ( eq == TVL_False )
715 {
716 // return the two items comparison
717 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
718 QVariant v = node.eval( parent, context );
720 return v;
721 }
722 }
723
724 // default to length comparison
725 switch ( mOp )
726 {
727 case boEQ:
728 return lL.length() == lR.length();
729 case boNE:
730 return lL.length() != lR.length();
731 case boLT:
732 return lL.length() < lR.length();
733 case boGT:
734 return lL.length() > lR.length();
735 case boLE:
736 return lL.length() <= lR.length();
737 case boGE:
738 return lL.length() >= lR.length();
739 default:
740 Q_ASSERT( false );
741 return TVL_Unknown;
742 }
743 }
744 else
745 {
746 return compareNonNullValues( parent, context, vL, vR, mOp );
747 }
748
749 case boIs:
750 case boIsNot:
751 {
752 const bool vLNull = QgsExpressionUtils::isNull( vL );
753 const bool vRNull = QgsExpressionUtils::isNull( vR );
754 if ( vLNull && vRNull ) // both operators null
755 return ( mOp == boIs ? TVL_True : TVL_False );
756 else if ( vLNull || vRNull ) // one operator null
757 return ( mOp == boIs ? TVL_False : TVL_True );
758 else // both operators non-null
759 {
760 return compareNonNullValues( parent, context, vL, vR, mOp == boIs ? boEQ : boNE );
761 }
762 }
763
764 case boRegexp:
765 case boLike:
766 case boNotLike:
767 case boILike:
768 case boNotILike:
769 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
770 return TVL_Unknown;
771 else
772 {
773 QString str = QgsExpressionUtils::getStringValue( vL, parent );
775 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
777 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
778 bool matches;
779 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
780 {
781 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
782 // manage escape % and _
783 if ( esc_regexp.startsWith( '%' ) )
784 {
785 esc_regexp.replace( 0, 1, u".*"_s );
786 }
787 const thread_local QRegularExpression rx1( u"[^\\\\](%)"_s );
788 int pos = 0;
789 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
790 {
791 esc_regexp.replace( pos + 1, 1, u".*"_s );
792 pos += 1;
793 }
794 const thread_local QRegularExpression rx2( u"\\\\%"_s );
795 esc_regexp.replace( rx2, u"%"_s );
796 if ( esc_regexp.startsWith( '_' ) )
797 {
798 esc_regexp.replace( 0, 1, u"."_s );
799 }
800 const thread_local QRegularExpression rx3( u"[^\\\\](_)"_s );
801 pos = 0;
802 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
803 {
804 esc_regexp.replace( pos + 1, 1, '.' );
805 pos += 1;
806 }
807 esc_regexp.replace( "\\\\_"_L1, "_"_L1 );
808
809 matches
810 = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption )
811 .match( str )
812 .hasMatch();
813 }
814 else
815 {
816 matches = QRegularExpression( regexp ).match( str ).hasMatch();
817 }
818
819 if ( mOp == boNotLike || mOp == boNotILike )
820 {
821 matches = !matches;
822 }
823
824 return matches ? TVL_True : TVL_False;
825 }
826
827 case boConcat:
828 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
829 return QVariant();
830 else
831 {
832 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
834 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
836 return QVariant( sL + sR );
837 }
838 }
839 Q_ASSERT( false );
840 return QVariant();
841}
842
843qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
844{
845 switch ( mOp )
846 {
847 case boPlus:
848 return x + y;
849 case boMinus:
850 return x - y;
851 case boMul:
852 return x * y;
853 case boDiv:
854 return x / y;
855 case boMod:
856 return x % y;
857 default:
858 Q_ASSERT( false );
859 return 0;
860 }
861}
862
863QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
864{
865 switch ( mOp )
866 {
867 case boPlus:
868 return d.addSecs( i->seconds() );
869 case boMinus:
870 return d.addSecs( -i->seconds() );
871 default:
872 Q_ASSERT( false );
873 return QDateTime();
874 }
875}
876
877double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
878{
879 switch ( mOp )
880 {
881 case boPlus:
882 return x + y;
883 case boMinus:
884 return x - y;
885 case boMul:
886 return x * y;
887 case boDiv:
888 return x / y;
889 case boMod:
890 return std::fmod( x, y );
891 default:
892 Q_ASSERT( false );
893 return 0;
894 }
895}
896
901
903{
904 // if this is an OR, try to collapse the OR expression into an IN node
905 if ( mOp == boOr )
906 {
907 // First step: flatten OR chain and collect values
908 QMap<QString, QgsExpressionNode::NodeList> orValuesMap;
909 QList<QString> orFieldNames;
910
911 // Get a list of all the OR and IN nodes chained together
912 std::function<bool( QgsExpressionNode * )> visitOrNodes = [&visitOrNodes, &orValuesMap, &orFieldNames]( QgsExpressionNode *node ) -> bool {
914 {
915 if ( op->op() != boOr && op->op() != boEQ )
916 {
917 return false;
918 }
919
920 if ( op->op() == boEQ )
921 {
922 // If left is a column ref and right is a literal, collect
923 if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opLeft() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opRight() ) ) )
924 {
925 const QString fieldName = op->opLeft()->dump();
926 if ( !orValuesMap.contains( fieldName ) )
927 {
928 orFieldNames.append( fieldName );
929 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
930 }
931 orValuesMap[fieldName].append( op->opRight()->clone() );
932 return true;
933 }
934 else if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opRight() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opLeft() ) ) )
935 {
936 const QString fieldName = op->opRight()->dump();
937 if ( !orValuesMap.contains( fieldName ) )
938 {
939 orFieldNames.append( fieldName );
940 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
941 }
942 orValuesMap[fieldName].append( op->opLeft()->clone() );
943 return true;
944 }
945 return false;
946 }
947
948 if ( visitOrNodes( op->opLeft() ) && visitOrNodes( op->opRight() ) )
949 {
950 return true;
951 }
952 }
953 else if ( QgsExpressionNodeInOperator *inOp = dynamic_cast<QgsExpressionNodeInOperator *>( node ) )
954 {
955 if ( inOp->isNotIn() || inOp->node()->nodeType() != QgsExpressionNode::ntColumnRef )
956 {
957 return false;
958 }
959
960 const QString fieldName = inOp->node()->dump();
961
962 // Check if all nodes are literals
963 const auto nodes = inOp->list()->list();
964 for ( const auto &valueNode : std::as_const( nodes ) )
965 {
966 if ( valueNode->nodeType() != QgsExpressionNode::ntLiteral )
967 {
968 return false;
969 }
970 }
971
972 if ( !orValuesMap.contains( fieldName ) )
973 {
974 orFieldNames.append( fieldName );
975 orValuesMap.insert( fieldName, *inOp->list()->clone() );
976 }
977 else
978 {
979 for ( const auto &valueNode : std::as_const( nodes ) )
980 {
981 orValuesMap[fieldName].append( valueNode->clone() );
982 }
983 }
984
985 return true;
986 }
987 return false;
988 };
989
990
991 // Second step: build the OR chain of IN operators
992 if ( visitOrNodes( this ) && !orValuesMap.empty() )
993 {
994 std::unique_ptr<QgsExpressionNode> currentNode;
995 for ( const auto &fieldName : std::as_const( orFieldNames ) )
996 {
997 auto orValuesIt = orValuesMap.find( fieldName );
998 if ( orValuesIt.value().count() == 1 )
999 {
1000 auto eqNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boEQ, new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().at( 0 )->clone() );
1001 if ( currentNode )
1002 {
1003 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), eqNode.release() );
1004 }
1005 else
1006 {
1007 currentNode = std::move( eqNode );
1008 }
1009 }
1010 else
1011 {
1012 auto inNode = std::make_unique<QgsExpressionNodeInOperator>( new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().clone() );
1013 if ( currentNode )
1014 {
1015 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), inNode.release() );
1016 }
1017 else
1018 {
1019 currentNode = std::move( inNode );
1020 }
1021 }
1022 }
1023
1024
1025 if ( currentNode )
1026 {
1027 mCompiledSimplifiedNode = std::move( currentNode );
1028 }
1029 }
1030 }
1031
1032 bool resL = mOpLeft->prepare( parent, context );
1033 bool resR = mOpRight->prepare( parent, context );
1034 return resL && resR;
1035}
1036
1038{
1039 // see left/right in qgsexpressionparser.yy
1040 switch ( mOp )
1041 {
1042 case boOr:
1043 return 1;
1044
1045 case boAnd:
1046 return 2;
1047
1048 case boEQ:
1049 case boNE:
1050 case boLE:
1051 case boGE:
1052 case boLT:
1053 case boGT:
1054 case boRegexp:
1055 case boLike:
1056 case boILike:
1057 case boNotLike:
1058 case boNotILike:
1059 case boIs:
1060 case boIsNot:
1061 return 3;
1062
1063 case boPlus:
1064 case boMinus:
1065 return 4;
1066
1067 case boMul:
1068 case boDiv:
1069 case boIntDiv:
1070 case boMod:
1071 return 5;
1072
1073 case boPow:
1074 return 6;
1075
1076 case boConcat:
1077 return 7;
1078 }
1079 Q_ASSERT( false && "unexpected binary operator" );
1080 return -1;
1081}
1082
1084{
1085 // see left/right in qgsexpressionparser.yy
1086 switch ( mOp )
1087 {
1088 case boOr:
1089 case boAnd:
1090 case boEQ:
1091 case boNE:
1092 case boLE:
1093 case boGE:
1094 case boLT:
1095 case boGT:
1096 case boRegexp:
1097 case boLike:
1098 case boILike:
1099 case boNotLike:
1100 case boNotILike:
1101 case boIs:
1102 case boIsNot:
1103 case boPlus:
1104 case boMinus:
1105 case boMul:
1106 case boDiv:
1107 case boIntDiv:
1108 case boMod:
1109 case boConcat:
1110 return true;
1111
1112 case boPow:
1113 return false;
1114 }
1115 Q_ASSERT( false && "unexpected binary operator" );
1116 return false;
1117}
1118
1120{
1121 QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft.get() );
1122 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight.get() );
1123 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight.get() );
1124
1125 QString rdump( mOpRight->dump() );
1126
1127 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
1128 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
1129 {
1130 rdump.prepend( '(' ).append( ')' );
1131 }
1132
1133 QString fmt;
1134 if ( leftAssociative() )
1135 {
1136 fmt += lOp && ( lOp->precedence() < precedence() ) ? u"(%1)"_s : u"%1"_s;
1137 fmt += " %2 "_L1;
1138 fmt += rOp && ( rOp->precedence() <= precedence() ) ? u"(%3)"_s : u"%3"_s;
1139 }
1140 else
1141 {
1142 fmt += lOp && ( lOp->precedence() <= precedence() ) ? u"(%1)"_s : u"%1"_s;
1143 fmt += " %2 "_L1;
1144 fmt += rOp && ( rOp->precedence() < precedence() ) ? u"(%3)"_s : u"%3"_s;
1145 }
1146
1147 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
1148}
1149
1151{
1152 if ( hasCachedStaticValue() )
1153 return QSet< QString >();
1154
1155 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
1156}
1157
1159{
1160 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
1161}
1162
1164{
1165 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
1166}
1167
1168QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
1169{
1170 QList<const QgsExpressionNode *> lst;
1171 lst << this;
1172 lst += mOpLeft->nodes() + mOpRight->nodes();
1173 return lst;
1174}
1175
1177{
1178 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
1179}
1180
1182{
1183 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
1184 cloneTo( copy );
1185 return copy;
1186}
1187
1189{
1190 const bool leftStatic = mOpLeft->isStatic( parent, context );
1191 const bool rightStatic = mOpRight->isStatic( parent, context );
1192
1193 if ( leftStatic && rightStatic )
1194 return true;
1195
1196 // special logic for certain ops...
1197 switch ( mOp )
1198 {
1200 {
1201 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
1202 // of the value of the other node!
1203 if ( leftStatic )
1204 {
1205 mOpLeft->prepare( parent, context );
1206 if ( mOpLeft->hasCachedStaticValue() )
1207 {
1208 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1209 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1210 {
1211 mCachedStaticValue = true;
1212 mHasCachedValue = true;
1213 return true;
1214 }
1215 }
1216 }
1217 else if ( rightStatic )
1218 {
1219 mOpRight->prepare( parent, context );
1220 if ( mOpRight->hasCachedStaticValue() )
1221 {
1222 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1223 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1224 {
1225 mCachedStaticValue = true;
1226 mHasCachedValue = true;
1227 return true;
1228 }
1229 }
1230 }
1231
1232 break;
1233 }
1235 {
1236 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
1237 // of the value of the other node!
1238
1239 if ( leftStatic )
1240 {
1241 mOpLeft->prepare( parent, context );
1242 if ( mOpLeft->hasCachedStaticValue() )
1243 {
1244 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1245 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1246 {
1247 mCachedStaticValue = false;
1248 mHasCachedValue = true;
1249 return true;
1250 }
1251 }
1252 }
1253 else if ( rightStatic )
1254 {
1255 mOpRight->prepare( parent, context );
1256 if ( mOpRight->hasCachedStaticValue() )
1257 {
1258 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1259 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1260 {
1261 mCachedStaticValue = false;
1262 mHasCachedValue = true;
1263 return true;
1264 }
1265 }
1266 }
1267
1268 break;
1269 }
1270
1292 break;
1293 }
1294
1295 return false;
1296}
1297
1298//
1299
1301{
1302 if ( mList->count() == 0 )
1303 return mNotIn ? TVL_True : TVL_False;
1304 QVariant v1 = mNode->eval( parent, context );
1306 if ( QgsExpressionUtils::isNull( v1 ) )
1307 return TVL_Unknown;
1308
1309 bool listHasNull = false;
1310
1311 const QList< QgsExpressionNode * > nodeList = mList->list();
1312 for ( QgsExpressionNode *n : nodeList )
1313 {
1314 QVariant v2 = n->eval( parent, context );
1316 if ( QgsExpressionUtils::isNull( v2 ) )
1317 listHasNull = true;
1318 else
1319 {
1320 bool equal = false;
1321 // check whether they are equal
1322 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
1323 {
1324 // do numeric comparison if both operators can be converted to numbers,
1325 // and they aren't both string
1326 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
1328 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
1330 equal = qgsDoubleNear( f1, f2 );
1331 }
1332 else
1333 {
1334 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1336 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1338 equal = QString::compare( s1, s2 ) == 0;
1339 }
1340
1341 if ( equal ) // we know the result
1342 return mNotIn ? TVL_False : TVL_True;
1343 }
1344 }
1345
1346 // item not found
1347 if ( listHasNull )
1348 return TVL_Unknown;
1349 else
1350 return mNotIn ? TVL_True : TVL_False;
1351}
1352
1355
1360
1362{
1363 bool res = mNode->prepare( parent, context );
1364 const QList< QgsExpressionNode * > nodeList = mList->list();
1365 for ( QgsExpressionNode *n : nodeList )
1366 {
1367 res = res && n->prepare( parent, context );
1368 }
1369 return res;
1370}
1371
1373{
1374 return u"%1 %2 IN (%3)"_s.arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1375}
1376
1378{
1379 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1380 cloneTo( copy );
1381 return copy;
1382}
1383
1385{
1386 if ( !mNode->isStatic( parent, context ) )
1387 return false;
1388
1389 const QList< QgsExpressionNode * > nodeList = mList->list();
1390 for ( QgsExpressionNode *n : nodeList )
1391 {
1392 if ( !n->isStatic( parent, context ) )
1393 return false;
1394 }
1395
1396 return true;
1397}
1398
1399//
1400
1402{
1403 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1404 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1405
1406 QVariant res = fd->run( mArgs.get(), context, parent, this );
1408
1409 // everything went fine
1410 return res;
1411}
1412
1414 : mFnIndex( fnIndex )
1415{
1416 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1417 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1418 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1419 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1420
1421 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1422 const int functionParamsSize = functionParams.size();
1423 if ( functionParams.isEmpty() )
1424 {
1425 // function does not support parameters
1426 mArgs.reset( args );
1427 }
1428 else if ( !args )
1429 {
1430 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1431 mArgs = std::make_unique<NodeList>();
1432 mArgs->reserve( functionParamsSize );
1433 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1434 {
1435 // insert default value for QgsExpressionFunction::Parameter
1436 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1437 }
1438 }
1439 else
1440 {
1441 mArgs = std::make_unique<NodeList>();
1442 mArgs->reserve( functionParamsSize );
1443
1444 int idx = 0;
1445 const QStringList argNames = args->names();
1446 const QList<QgsExpressionNode *> argList = args->list();
1447 //first loop through unnamed arguments
1448 {
1449 const int argNamesSize = argNames.size();
1450 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1451 {
1452 mArgs->append( argList.at( idx )->clone() );
1453 idx++;
1454 }
1455 }
1456
1457 //next copy named QgsExpressionFunction::Parameters in order expected by function
1458 for ( ; idx < functionParamsSize; ++idx )
1459 {
1460 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1461 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1462 if ( nodeIdx < 0 )
1463 {
1464 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1465 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1466 }
1467 else
1468 {
1469 mArgs->append( argList.at( nodeIdx )->clone() );
1470 }
1471 }
1472
1473 delete args;
1474 }
1475}
1476
1479
1484
1486{
1487 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1488
1489 bool res = fd->prepare( this, parent, context );
1490 if ( mArgs && !fd->lazyEval() )
1491 {
1492 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1493 for ( QgsExpressionNode *n : nodeList )
1494 {
1495 res = res && n->prepare( parent, context );
1496 }
1497 }
1498 return res;
1499}
1500
1502{
1503 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1504 if ( fd->params() == 0 )
1505 return u"%1%2"_s.arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : u"()"_s ); // special column
1506 else
1507 return u"%1(%2)"_s.arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1508}
1509
1511{
1512 if ( hasCachedStaticValue() )
1513 return QSet< QString >();
1514
1515 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1516 QSet<QString> functionColumns = fd->referencedColumns( this );
1517
1518 if ( !mArgs )
1519 {
1520 //no referenced columns in arguments, just return function's referenced columns
1521 return functionColumns;
1522 }
1523
1524 int paramIndex = 0;
1525 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1526 for ( QgsExpressionNode *n : nodeList )
1527 {
1528 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1529 functionColumns.unite( n->referencedColumns() );
1530 paramIndex++;
1531 }
1532
1533 return functionColumns;
1534}
1535
1537{
1538 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1539 if ( fd->name() == "var"_L1 )
1540 {
1541 if ( !mArgs->list().isEmpty() )
1542 {
1543 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1544 if ( var )
1545 return QSet<QString>() << var->value().toString();
1546 }
1547 return QSet<QString>() << QString();
1548 }
1549 else
1550 {
1551 QSet<QString> functionVariables = QSet<QString>();
1552
1553 if ( !mArgs )
1554 return functionVariables;
1555
1556 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1557 for ( QgsExpressionNode *n : nodeList )
1558 {
1559 functionVariables.unite( n->referencedVariables() );
1560 }
1561
1562 return functionVariables;
1563 }
1564}
1565
1567{
1568 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1569 QSet<QString> functions = QSet<QString>();
1570 functions.insert( fd->name() );
1571
1572 if ( !mArgs )
1573 return functions;
1574
1575 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1576 for ( QgsExpressionNode *n : nodeList )
1577 {
1578 functions.unite( n->referencedFunctions() );
1579 }
1580 return functions;
1581}
1582
1583QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1584{
1585 QList<const QgsExpressionNode *> lst;
1586 lst << this;
1587 if ( !mArgs )
1588 return lst;
1589
1590 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1591 for ( QgsExpressionNode *n : nodeList )
1592 {
1593 lst += n->nodes();
1594 }
1595 return lst;
1596}
1597
1599{
1600 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1601 if ( mArgs )
1602 {
1603 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1604 for ( QgsExpressionNode *n : nodeList )
1605 needs |= n->needsGeometry();
1606 }
1607 return needs;
1608}
1609
1611{
1612 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1613 cloneTo( copy );
1614 return copy;
1615}
1616
1618{
1619 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1620}
1621
1623{
1624 if ( !args || !args->hasNamedNodes() )
1625 return true;
1626
1627 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1628 if ( functionParams.isEmpty() )
1629 {
1630 error = u"%1 does not support named QgsExpressionFunction::Parameters"_s.arg( QgsExpression::Functions()[fnIndex]->name() );
1631 return false;
1632 }
1633 else
1634 {
1635 QSet< int > providedArgs;
1636 QSet< int > handledArgs;
1637 int idx = 0;
1638 //first loop through unnamed arguments
1639 while ( args->names().at( idx ).isEmpty() )
1640 {
1641 providedArgs << idx;
1642 handledArgs << idx;
1643 idx++;
1644 }
1645
1646 //next check named QgsExpressionFunction::Parameters
1647 for ( ; idx < functionParams.count(); ++idx )
1648 {
1649 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1650 if ( nodeIdx < 0 )
1651 {
1652 if ( !functionParams.at( idx ).optional() )
1653 {
1654 error = u"No value specified for QgsExpressionFunction::Parameter '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1655 return false;
1656 }
1657 }
1658 else
1659 {
1660 if ( providedArgs.contains( idx ) )
1661 {
1662 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1663 return false;
1664 }
1665 }
1666 providedArgs << idx;
1667 handledArgs << nodeIdx;
1668 }
1669
1670 //last check for bad names
1671 idx = 0;
1672 const QStringList nameList = args->names();
1673 for ( const QString &name : nameList )
1674 {
1675 if ( !name.isEmpty() && !functionParams.contains( name ) )
1676 {
1677 error = u"Invalid QgsExpressionFunction::Parameter name '%1' for %2"_s.arg( name, QgsExpression::Functions()[fnIndex]->name() );
1678 return false;
1679 }
1680 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1681 {
1682 int functionIdx = functionParams.indexOf( name );
1683 if ( providedArgs.contains( functionIdx ) )
1684 {
1685 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1686 return false;
1687 }
1688 }
1689 idx++;
1690 }
1691 }
1692 return true;
1693}
1694
1695//
1696
1698{
1699 Q_UNUSED( context )
1700 Q_UNUSED( parent )
1701 return mValue;
1702}
1703
1708
1710{
1711 Q_UNUSED( parent )
1712 Q_UNUSED( context )
1713 return true;
1714}
1715
1716
1718{
1719 if ( QgsVariantUtils::isNull( mValue ) )
1720 return u"NULL"_s;
1721
1722 switch ( mValue.userType() )
1723 {
1724 case QMetaType::Type::Int:
1725 return QString::number( mValue.toInt() );
1726 case QMetaType::Type::Double:
1727 return qgsDoubleToString( mValue.toDouble() );
1728 case QMetaType::Type::LongLong:
1729 return QString::number( mValue.toLongLong() );
1730 case QMetaType::Type::QString:
1731 return QgsExpression::quotedString( mValue.toString() );
1732 case QMetaType::Type::QTime:
1733 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1734 case QMetaType::Type::QDate:
1735 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1736 case QMetaType::Type::QDateTime:
1737 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1738 case QMetaType::Type::Bool:
1739 return mValue.toBool() ? u"TRUE"_s : u"FALSE"_s;
1740 default:
1741 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1742 }
1743}
1744
1746{
1747 return valueAsString();
1748}
1749
1751{
1752 return QSet<QString>();
1753}
1754
1756{
1757 return QSet<QString>();
1758}
1759
1761{
1762 return QSet<QString>();
1763}
1764
1765QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1766{
1767 QList<const QgsExpressionNode *> lst;
1768 lst << this;
1769 return lst;
1770}
1771
1773{
1774 return false;
1775}
1776
1778{
1780 cloneTo( copy );
1781 return copy;
1782}
1783
1785{
1786 Q_UNUSED( context )
1787 Q_UNUSED( parent )
1788 return true;
1789}
1790
1791//
1792
1794{
1795 Q_UNUSED( parent )
1796 int index = mIndex;
1797
1798 if ( index < 0 )
1799 {
1800 // have not yet found field index - first check explicitly set fields collection
1801 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1802 {
1803 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1804 index = fields.lookupField( mName );
1805 }
1806 }
1807
1808 if ( context )
1809 {
1810 QgsFeature feature = context->feature();
1811 if ( feature.isValid() )
1812 {
1813 if ( index >= 0 )
1814 return feature.attribute( index );
1815 else
1816 return feature.attribute( mName );
1817 }
1818 else
1819 {
1820 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1821 }
1822 }
1823 if ( index < 0 )
1824 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1825 return QVariant();
1826}
1827
1832
1834{
1835 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1836 return false;
1837
1838 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1839
1840 mIndex = fields.lookupField( mName );
1841
1842 if ( mIndex == -1 && context->hasFeature() )
1843 {
1844 mIndex = context->feature().fieldNameIndex( mName );
1845 }
1846
1847 if ( mIndex == -1 )
1848 {
1849 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1850 return false;
1851 }
1852 return true;
1853}
1854
1856{
1857 const thread_local QRegularExpression re( u"^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$"_s );
1858 const QRegularExpressionMatch match = re.match( mName );
1859 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1860}
1861
1863{
1864 return QSet<QString>() << mName;
1865}
1866
1868{
1869 return QSet<QString>();
1870}
1871
1873{
1874 return QSet<QString>();
1875}
1876
1877QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1878{
1879 QList<const QgsExpressionNode *> result;
1880 result << this;
1881 return result;
1882}
1883
1885{
1886 return false;
1887}
1888
1890{
1892 cloneTo( copy );
1893 return copy;
1894}
1895
1897{
1898 Q_UNUSED( context )
1899 Q_UNUSED( parent )
1900 return false;
1901}
1902
1903//
1904
1911
1913{
1914 qDeleteAll( mConditions );
1915}
1916
1921
1923{
1924 for ( WhenThen *cond : std::as_const( mConditions ) )
1925 {
1926 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1927 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1929 if ( tvl == QgsExpressionUtils::True )
1930 {
1931 QVariant vRes = cond->mThenExp->eval( parent, context );
1933 return vRes;
1934 }
1935 }
1936
1937 if ( mElseExp )
1938 {
1939 QVariant vElse = mElseExp->eval( parent, context );
1941 return vElse;
1942 }
1943
1944 // return NULL if no condition is matching
1945 return QVariant();
1946}
1947
1949{
1950 bool foundAnyNonStaticConditions = false;
1951 for ( WhenThen *cond : std::as_const( mConditions ) )
1952 {
1953 const bool res = cond->mWhenExp->prepare( parent, context ) && cond->mThenExp->prepare( parent, context );
1954 if ( !res )
1955 return false;
1956
1957 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1958 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1959 {
1960 // 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
1961 // value, and the static value for this WHEN clause is True.
1962 if ( cond->mThenExp->hasCachedStaticValue() )
1963 {
1964 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1965 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1966 mHasCachedValue = true;
1967 return true;
1968 }
1969 else
1970 {
1971 // 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
1972 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1973 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1974 return true;
1975 }
1976 }
1977 }
1978
1979 if ( mElseExp )
1980 {
1981 const bool res = mElseExp->prepare( parent, context );
1982 if ( !res )
1983 return false;
1984
1985 if ( !foundAnyNonStaticConditions )
1986 {
1987 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1988 if ( mElseExp->hasCachedStaticValue() )
1989 {
1990 mCachedStaticValue = mElseExp->cachedStaticValue();
1991 mHasCachedValue = true;
1992 return true;
1993 }
1994 else
1995 {
1996 // so even though the ELSE node is non-static we can effectively replace
1997 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1998 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1999 return true;
2000 }
2001 }
2002 }
2003
2004 return true;
2005}
2006
2008{
2009 QString msg( u"CASE"_s );
2010 for ( WhenThen *cond : mConditions )
2011 {
2012 msg += u" WHEN %1 THEN %2"_s.arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
2013 }
2014 if ( mElseExp )
2015 msg += u" ELSE %1"_s.arg( mElseExp->dump() );
2016 msg += " END"_L1;
2017 return msg;
2018}
2019
2021{
2022 if ( hasCachedStaticValue() )
2023 return QSet< QString >();
2024
2025 QSet<QString> lst;
2026 for ( WhenThen *cond : mConditions )
2027 {
2028 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
2029 }
2030
2031 if ( mElseExp )
2032 lst += mElseExp->referencedColumns();
2033
2034 return lst;
2035}
2036
2038{
2039 QSet<QString> lst;
2040 for ( WhenThen *cond : mConditions )
2041 {
2042 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
2043 }
2044
2045 if ( mElseExp )
2046 lst += mElseExp->referencedVariables();
2047
2048 return lst;
2049}
2050
2052{
2053 QSet<QString> lst;
2054 for ( WhenThen *cond : mConditions )
2055 {
2056 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
2057 }
2058
2059 if ( mElseExp )
2060 lst += mElseExp->referencedFunctions();
2061
2062 return lst;
2063}
2064
2065QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
2066{
2067 QList<const QgsExpressionNode *> lst;
2068 lst << this;
2069 for ( WhenThen *cond : mConditions )
2070 {
2071 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
2072 }
2073
2074 if ( mElseExp )
2075 lst += mElseExp->nodes();
2076
2077 return lst;
2078}
2079
2081{
2082 for ( WhenThen *cond : mConditions )
2083 {
2084 if ( cond->mWhenExp->needsGeometry() || cond->mThenExp->needsGeometry() )
2085 return true;
2086 }
2087
2088 return mElseExp && mElseExp->needsGeometry();
2089}
2090
2092{
2094 conditions.reserve( mConditions.size() );
2095 for ( WhenThen *wt : mConditions )
2096 conditions.append( wt->clone() );
2097
2098 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
2099 cloneTo( copy );
2100 return copy;
2101}
2102
2104{
2105 for ( WhenThen *wt : mConditions )
2106 {
2107 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
2108 return false;
2109 }
2110
2111 if ( mElseExp )
2112 return mElseExp->isStatic( parent, context );
2113
2114 return true;
2115}
2116
2118{
2119 if ( hasCachedStaticValue() )
2120 return QSet< QString >();
2121
2122 QSet<QString> lst( mNode->referencedColumns() );
2123 const QList< QgsExpressionNode * > nodeList = mList->list();
2124 for ( const QgsExpressionNode *n : nodeList )
2125 lst.unite( n->referencedColumns() );
2126 return lst;
2127}
2128
2130{
2131 QSet<QString> lst( mNode->referencedVariables() );
2132 const QList< QgsExpressionNode * > nodeList = mList->list();
2133 for ( const QgsExpressionNode *n : nodeList )
2134 lst.unite( n->referencedVariables() );
2135 return lst;
2136}
2137
2139{
2140 QSet<QString> lst( mNode->referencedFunctions() );
2141 const QList< QgsExpressionNode * > nodeList = mList->list();
2142 for ( const QgsExpressionNode *n : nodeList )
2143 lst.unite( n->referencedFunctions() );
2144 return lst;
2145}
2146
2147QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
2148{
2149 QList<const QgsExpressionNode *> lst;
2150 lst << this;
2151 const QList< QgsExpressionNode * > nodeList = mList->list();
2152 for ( const QgsExpressionNode *n : nodeList )
2153 lst += n->nodes();
2154 return lst;
2155}
2156
2157
2160
2165
2167{
2168 bool res = mNode->prepare( parent, context );
2169 res = res && mLowerBound->prepare( parent, context );
2170 res = res && mHigherBound->prepare( parent, context );
2171 return res;
2172}
2173
2175{
2176 const QVariant nodeVal = mNode->eval( parent, context );
2177 if ( QgsVariantUtils::isNull( nodeVal ) )
2178 {
2179 return QVariant();
2180 }
2181
2182 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
2183
2185 const QVariant lowBoundValue = lowBound.eval( parent, context );
2186 const bool lowBoundBool { lowBoundValue.toBool() };
2187
2188 if ( !QgsVariantUtils::isNull( lowBoundValue ) && !lowBoundBool )
2189 {
2190 return QVariant( mNegate );
2191 }
2192
2194 const QVariant highBoundValue = highBound.eval( parent, context );
2195
2196 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2197 {
2198 return QVariant();
2199 }
2200
2201 const bool highBoundBool { highBoundValue.toBool() };
2202
2203 // We already checked if both are nulls
2204 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2205 {
2206 // In this case we can return a boolean
2207 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && !highBoundBool ) || ( QgsVariantUtils::isNull( highBoundValue ) && !lowBoundBool ) )
2208 {
2209 return QVariant( mNegate );
2210 }
2211
2212 // Indetermined
2213 return QVariant();
2214 }
2215
2216 if ( !QgsVariantUtils::isNull( highBoundValue ) && !highBoundBool )
2217 {
2218 return QVariant( mNegate );
2219 }
2220
2221 const bool res { lowBoundBool && highBoundBool };
2222 return mNegate ? QVariant( !res ) : QVariant( res );
2223}
2224
2226{
2227 return u"%1 %2 %3 AND %4"_s.arg( mNode->dump(), mNegate ? u"NOT BETWEEN"_s : u"BETWEEN"_s, mLowerBound->dump(), mHigherBound->dump() );
2228}
2229
2231{
2232 QSet<QString> lst( mNode->referencedVariables() );
2233 lst.unite( mLowerBound->referencedVariables() );
2234 lst.unite( mHigherBound->referencedVariables() );
2235 return lst;
2236}
2237
2239{
2240 QSet<QString> lst( mNode->referencedFunctions() );
2241 lst.unite( mLowerBound->referencedFunctions() );
2242 lst.unite( mHigherBound->referencedFunctions() );
2243 return lst;
2244}
2245
2246QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2247{
2248 return { this, mLowerBound.get(), mHigherBound.get() };
2249}
2250
2252{
2253 QSet<QString> lst( mNode->referencedColumns() );
2254 lst.unite( mLowerBound->referencedColumns() );
2255 lst.unite( mHigherBound->referencedColumns() );
2256 return lst;
2257}
2258
2260{
2261 if ( mNode->needsGeometry() )
2262 return true;
2263
2264 if ( mLowerBound->needsGeometry() )
2265 return true;
2266
2267 if ( mHigherBound->needsGeometry() )
2268 return true;
2269
2270 return false;
2271}
2272
2274{
2275 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2276 cloneTo( copy );
2277 return copy;
2278}
2279
2281{
2282 if ( !mNode->isStatic( parent, context ) )
2283 return false;
2284
2285 if ( !mLowerBound->isStatic( parent, context ) )
2286 return false;
2287
2288 if ( !mHigherBound->isStatic( parent, context ) )
2289 return false;
2290
2291 return true;
2292}
2293
2295{
2296 return mLowerBound.get();
2297}
2298
2300{
2301 return mHigherBound.get();
2302}
2303
2305{
2306 return mNegate;
2307}
2308
2313
2316
2318{
2319 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2320}
2321
2323{
2324 return BINARY_OPERATOR_TEXT[mOp];
2325}
2326
2327//
2328
2330{
2331 const QVariant container = mContainer->eval( parent, context );
2333 const QVariant index = mIndex->eval( parent, context );
2335
2336 switch ( container.userType() )
2337 {
2338 case QMetaType::Type::QVariantMap:
2339 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2340
2341 case QMetaType::Type::QVariantList:
2342 case QMetaType::Type::QStringList:
2343 {
2344 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2345 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2346 if ( pos >= list.length() || pos < -list.length() )
2347 {
2348 return QVariant();
2349 }
2350 if ( pos < 0 )
2351 {
2352 // negative indices are from back of list
2353 pos += list.length();
2354 }
2355
2356 return list.at( pos );
2357 }
2358
2359 default:
2361 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2362 return QVariant();
2363 }
2364}
2365
2370
2372{
2373 bool resC = mContainer->prepare( parent, context );
2374 bool resV = mIndex->prepare( parent, context );
2375 return resC && resV;
2376}
2377
2379{
2380 return u"%1[%2]"_s.arg( mContainer->dump(), mIndex->dump() );
2381}
2382
2384{
2385 if ( hasCachedStaticValue() )
2386 return QSet< QString >();
2387
2388 return mContainer->referencedColumns() + mIndex->referencedColumns();
2389}
2390
2392{
2393 return mContainer->referencedVariables() + mIndex->referencedVariables();
2394}
2395
2397{
2398 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2399}
2400
2401QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2402{
2403 QList<const QgsExpressionNode *> lst;
2404 lst << this;
2405 lst += mContainer->nodes() + mIndex->nodes();
2406 return lst;
2407}
2408
2410{
2411 return mContainer->needsGeometry() || mIndex->needsGeometry();
2412}
2413
2415{
2416 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2417 cloneTo( copy );
2418 return copy;
2419}
2420
2422{
2423 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2424}
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.
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.
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.
int params() const
The number of parameters this function takes.
bool lazyEval() const
true if this function should use lazy evaluation.
QString name() const
The name of the function.
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...
const QgsExpressionFunction::ParameterList & parameters() const
Returns the list of named parameters for the function, if set.
virtual QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const
Returns a set of field names which are required for this function.
virtual bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
This will be called during the prepare step() of an expression if it is not static.
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.
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.
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::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.
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.
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.
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.
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.
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.
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 const QList< QgsExpressionFunction * > & Functions()
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes).
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.
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:46
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:7140
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7222
bool compareOp(T diff, QgsExpressionNodeBinaryOperator::BinaryOperator op)
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.