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