QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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#include "qgsexpressionutils.h"
18#include "qgsexpression.h"
19
20#include "qgsgeometry.h"
21#include "qgsfeaturerequest.h"
22#include "qgsstringutils.h"
23#include "qgsvariantutils.h"
24
25#include <QDate>
26#include <QDateTime>
27#include <QTime>
28#include <QRegularExpression>
29
30const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
31{
32 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
33 "OR", "AND",
34 "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
35 "+", "-", "*", "/", "//", "%", "^",
36 "||"
37};
38
39const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
40{
41 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
42 "NOT", "-"
43};
44
46{
47 bool needs = false;
48 const QList< QgsExpressionNode * > nodeList = mList->list();
49 for ( QgsExpressionNode *n : nodeList )
50 needs |= n->needsGeometry();
51 return needs;
52}
53
55{
56 qDeleteAll( mList );
57}
58
60{
61 mList.append( node->node );
62 mNameList.append( cleanNamedNodeName( node->name ) );
63 mHasNamedNodes = true;
64 delete node;
65}
66
68{
69 NodeList *nl = new NodeList;
70 for ( QgsExpressionNode *node : mList )
71 {
72 nl->mList.append( node->clone() );
73 }
74 nl->mNameList = mNameList;
75
76 return nl;
77}
78
80{
81 QString msg;
82 bool first = true;
83 for ( QgsExpressionNode *n : mList )
84 {
85 if ( !first ) msg += QLatin1String( ", " );
86 else 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 == QLatin1String( "geom" ) )
98 cleaned = QStringLiteral( "geometry" );
99 else if ( cleaned == QLatin1String( "val" ) )
100 cleaned = QStringLiteral( "value" );
101 else if ( cleaned == QLatin1String( "geometry a" ) )
102 cleaned = QStringLiteral( "geometry1" );
103 else if ( cleaned == QLatin1String( "geometry b" ) )
104 cleaned = QStringLiteral( "geometry2" );
105 else if ( cleaned == QLatin1String( "i" ) )
106 cleaned = QStringLiteral( "vertex" );
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
140{
141 return ntUnaryOperator;
142}
143
145{
146 return mOperand->prepare( parent, context );
147}
148
150{
151 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand ) )
152 return QStringLiteral( "%1 ( %2 )" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
153 else
154 return QStringLiteral( "%1 %2" ).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 QVariant vL = mOpLeft->eval( parent, context );
211
212 if ( mOp == boAnd || mOp == boOr )
213 {
214 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
216 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
217 return TVL_False; // shortcut -- no need to evaluate right-hand side
218 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
219 return TVL_True; // shortcut -- no need to evaluate right-hand side
220 }
221
222 QVariant vR = mOpRight->eval( parent, context );
224
225 switch ( mOp )
226 {
227 case boPlus:
228 if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
229 {
230 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
232 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
234 return QVariant( sL + sR );
235 }
236 //intentional fall-through
238 case boMinus:
239 case boMul:
240 case boDiv:
241 case boMod:
242 {
243 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
244 return QVariant();
245 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
246 {
247 // both are integers - let's use integer arithmetic
248 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
250 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
252
253 if ( mOp == boMod && iR == 0 )
254 return QVariant();
255
256 return QVariant( computeInt( iL, iR ) );
257 }
258 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
259 {
260 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
262 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
264 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
265 {
266 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
267 return QVariant();
268 }
269 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
270 }
271 else if ( mOp == boPlus && ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
272 ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
273 {
274 QDate date = QgsExpressionUtils::getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
276 QTime time = QgsExpressionUtils::getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
278 QDateTime dt = QDateTime( date, time );
279 return QVariant( dt );
280 }
281 else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
282 {
283 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
285 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
287 return date1 - date2;
288 }
289 else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
290 {
291 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
293 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
295 return time1 - time2;
296 }
297 else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
298 {
299 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
301 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
303 return QgsInterval( datetime1 - datetime2 );
304 }
305 else
306 {
307 // general floating point arithmetic
308 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
310 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
312 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
313 return QVariant(); // silently handle division by zero and return NULL
314 return QVariant( computeDouble( fL, fR ) );
315 }
316 }
317 case boIntDiv:
318 {
319 //integer division
320 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
322 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
324 if ( fR == 0. )
325 return QVariant(); // silently handle division by zero and return NULL
326 return QVariant( qlonglong( std::floor( fL / fR ) ) );
327 }
328 case boPow:
329 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
330 return QVariant();
331 else
332 {
333 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
335 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
337 return QVariant( std::pow( fL, fR ) );
338 }
339
340 case boAnd:
341 {
342 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
344 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
345 }
346
347 case boOr:
348 {
349 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
351 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
352 }
353
354 case boEQ:
355 case boNE:
356 case boLT:
357 case boGT:
358 case boLE:
359 case boGE:
360 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
361 {
362 return TVL_Unknown;
363 }
364 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
365 {
366 // verify that we have two lists
367 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
368 return TVL_Unknown;
369
370 // and search for not equal respective items
371 QVariantList lL = vL.toList();
372 QVariantList lR = vR.toList();
373 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
374 {
375 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
376 continue; // same behavior as PostgreSQL
377
378 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
379 {
380 switch ( mOp )
381 {
382 case boEQ:
383 return false;
384 case boNE:
385 return true;
386 case boLT:
387 case boLE:
388 return QgsExpressionUtils::isNull( lR.at( i ) );
389 case boGT:
390 case boGE:
391 return QgsExpressionUtils::isNull( lL.at( i ) );
392 default:
393 Q_ASSERT( false );
394 return TVL_Unknown;
395 }
396 }
397
398 QgsExpressionNodeLiteral nL( lL.at( i ) );
399 QgsExpressionNodeLiteral nR( lR.at( i ) );
400 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
401 QVariant eq = eqNode.eval( parent, context );
403 if ( eq == TVL_False )
404 {
405 // return the two items comparison
406 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
407 QVariant v = node.eval( parent, context );
409 return v;
410 }
411 }
412
413 // default to length comparison
414 switch ( mOp )
415 {
416 case boEQ:
417 return lL.length() == lR.length();
418 case boNE:
419 return lL.length() != lR.length();
420 case boLT:
421 return lL.length() < lR.length();
422 case boGT:
423 return lL.length() > lR.length();
424 case boLE:
425 return lL.length() <= lR.length();
426 case boGE:
427 return lL.length() >= lR.length();
428 default:
429 Q_ASSERT( false );
430 return TVL_Unknown;
431 }
432 }
433 else if ( ( vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime ) )
434 {
435 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
437 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
439
440 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
441 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
442 // results (due to different hidden timezones), we force all datetime comparisons to treat
443 // all datetime values as having the same time zone
444 dL.setTimeSpec( Qt::UTC );
445 dR.setTimeSpec( Qt::UTC );
446
447 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
448 }
449 else if ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Date ) )
450 {
451 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
453 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
455 return compare( dR.daysTo( dL ) ) ? TVL_True : TVL_False;
456 }
457 else if ( ( vL.type() == QVariant::Time && vR.type() == QVariant::Time ) )
458 {
459 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
461 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
463 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
464 }
465 else if ( ( vL.type() != QVariant::String || vR.type() != QVariant::String ) &&
466 QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
467 {
468 // do numeric comparison if both operators can be converted to numbers,
469 // and they aren't both string
470 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
472 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
474 return compare( fL - fR ) ? TVL_True : TVL_False;
475 }
476 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
477 else if ( vL.userType() == QMetaType::type( "QgsInterval" ) && vR.userType() == QMetaType::type( "QgsInterval" ) )
478 {
479 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
481 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
483 return compare( fL - fR ) ? TVL_True : TVL_False;
484 }
485 else
486 {
487 // do string comparison otherwise
488 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
490 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
492 int diff = QString::compare( sL, sR );
493 return compare( diff ) ? TVL_True : TVL_False;
494 }
495
496 case boIs:
497 case boIsNot:
498 if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
499 return ( mOp == boIs ? TVL_True : TVL_False );
500 else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
501 return ( mOp == boIs ? TVL_False : TVL_True );
502 else // both operators non-null
503 {
504 bool equal = false;
505 if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
506 ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
507 {
508 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
510 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
512 equal = qgsDoubleNear( fL, fR );
513 }
514 else
515 {
516 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
518 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
520 equal = QString::compare( sL, sR ) == 0;
521 }
522 if ( equal )
523 return mOp == boIs ? TVL_True : TVL_False;
524 else
525 return mOp == boIs ? TVL_False : TVL_True;
526 }
527
528 case boRegexp:
529 case boLike:
530 case boNotLike:
531 case boILike:
532 case boNotILike:
533 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
534 return TVL_Unknown;
535 else
536 {
537 QString str = QgsExpressionUtils::getStringValue( vL, parent );
539 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
541 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
542 bool matches;
543 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
544 {
545 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
546 // manage escape % and _
547 if ( esc_regexp.startsWith( '%' ) )
548 {
549 esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
550 }
551 const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
552 int pos = 0;
553 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
554 {
555 esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
556 pos += 1;
557 }
558 const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
559 esc_regexp.replace( rx2, QStringLiteral( "%" ) );
560 if ( esc_regexp.startsWith( '_' ) )
561 {
562 esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
563 }
564 const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
565 pos = 0;
566 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
567 {
568 esc_regexp.replace( pos + 1, 1, '.' );
569 pos += 1;
570 }
571 esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
572
573 matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
574 }
575 else
576 {
577 matches = QRegularExpression( regexp ).match( str ).hasMatch();
578 }
579
580 if ( mOp == boNotLike || mOp == boNotILike )
581 {
582 matches = !matches;
583 }
584
585 return matches ? TVL_True : TVL_False;
586 }
587
588 case boConcat:
589 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
590 return QVariant();
591 else
592 {
593 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
595 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
597 return QVariant( sL + sR );
598 }
599 }
600 Q_ASSERT( false );
601 return QVariant();
602}
603
604bool QgsExpressionNodeBinaryOperator::compare( double diff )
605{
606 switch ( mOp )
607 {
608 case boEQ:
609 return qgsDoubleNear( diff, 0.0 );
610 case boNE:
611 return !qgsDoubleNear( diff, 0.0 );
612 case boLT:
613 return diff < 0;
614 case boGT:
615 return diff > 0;
616 case boLE:
617 return diff <= 0;
618 case boGE:
619 return diff >= 0;
620 default:
621 Q_ASSERT( false );
622 return false;
623 }
624}
625
626qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
627{
628 switch ( mOp )
629 {
630 case boPlus:
631 return x + y;
632 case boMinus:
633 return x - y;
634 case boMul:
635 return x * y;
636 case boDiv:
637 return x / y;
638 case boMod:
639 return x % y;
640 default:
641 Q_ASSERT( false );
642 return 0;
643 }
644}
645
646QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
647{
648 switch ( mOp )
649 {
650 case boPlus:
651 return d.addSecs( i->seconds() );
652 case boMinus:
653 return d.addSecs( -i->seconds() );
654 default:
655 Q_ASSERT( false );
656 return QDateTime();
657 }
658}
659
660double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
661{
662 switch ( mOp )
663 {
664 case boPlus:
665 return x + y;
666 case boMinus:
667 return x - y;
668 case boMul:
669 return x * y;
670 case boDiv:
671 return x / y;
672 case boMod:
673 return std::fmod( x, y );
674 default:
675 Q_ASSERT( false );
676 return 0;
677 }
678}
679
681{
682 return ntBinaryOperator;
683}
684
686{
687 bool resL = mOpLeft->prepare( parent, context );
688 bool resR = mOpRight->prepare( parent, context );
689 return resL && resR;
690}
691
693{
694 // see left/right in qgsexpressionparser.yy
695 switch ( mOp )
696 {
697 case boOr:
698 return 1;
699
700 case boAnd:
701 return 2;
702
703 case boEQ:
704 case boNE:
705 case boLE:
706 case boGE:
707 case boLT:
708 case boGT:
709 case boRegexp:
710 case boLike:
711 case boILike:
712 case boNotLike:
713 case boNotILike:
714 case boIs:
715 case boIsNot:
716 return 3;
717
718 case boPlus:
719 case boMinus:
720 return 4;
721
722 case boMul:
723 case boDiv:
724 case boIntDiv:
725 case boMod:
726 return 5;
727
728 case boPow:
729 return 6;
730
731 case boConcat:
732 return 7;
733 }
734 Q_ASSERT( false && "unexpected binary operator" );
735 return -1;
736}
737
739{
740 // see left/right in qgsexpressionparser.yy
741 switch ( mOp )
742 {
743 case boOr:
744 case boAnd:
745 case boEQ:
746 case boNE:
747 case boLE:
748 case boGE:
749 case boLT:
750 case boGT:
751 case boRegexp:
752 case boLike:
753 case boILike:
754 case boNotLike:
755 case boNotILike:
756 case boIs:
757 case boIsNot:
758 case boPlus:
759 case boMinus:
760 case boMul:
761 case boDiv:
762 case boIntDiv:
763 case boMod:
764 case boConcat:
765 return true;
766
767 case boPow:
768 return false;
769 }
770 Q_ASSERT( false && "unexpected binary operator" );
771 return false;
772}
773
775{
777 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
778 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
779
780 QString rdump( mOpRight->dump() );
781
782 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
783 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
784 {
785 rdump.prepend( '(' ).append( ')' );
786 }
787
788 QString fmt;
789 if ( leftAssociative() )
790 {
791 fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
792 fmt += QLatin1String( " %2 " );
793 fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
794 }
795 else
796 {
797 fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
798 fmt += QLatin1String( " %2 " );
799 fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
800 }
801
802 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
803}
804
806{
807 if ( hasCachedStaticValue() )
808 return QSet< QString >();
809
810 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
811}
812
814{
815 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
816}
817
819{
820 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
821}
822
823QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
824{
825 QList<const QgsExpressionNode *> lst;
826 lst << this;
827 lst += mOpLeft->nodes() + mOpRight->nodes();
828 return lst;
829}
830
832{
833 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
834}
835
837{
838 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
839 cloneTo( copy );
840 return copy;
841}
842
844{
845 const bool leftStatic = mOpLeft->isStatic( parent, context );
846 const bool rightStatic = mOpRight->isStatic( parent, context );
847
848 if ( leftStatic && rightStatic )
849 return true;
850
851 // special logic for certain ops...
852 switch ( mOp )
853 {
855 {
856 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
857 // of the value of the other node!
858 if ( leftStatic )
859 {
860 mOpLeft->prepare( parent, context );
861 if ( mOpLeft->hasCachedStaticValue() )
862 {
863 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
864 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
865 {
866 mCachedStaticValue = true;
867 mHasCachedValue = true;
868 return true;
869 }
870 }
871 }
872 else if ( rightStatic )
873 {
874 mOpRight->prepare( parent, context );
875 if ( mOpRight->hasCachedStaticValue() )
876 {
877 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
878 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
879 {
880 mCachedStaticValue = true;
881 mHasCachedValue = true;
882 return true;
883 }
884 }
885 }
886
887 break;
888 }
890 {
891 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
892 // of the value of the other node!
893
894 if ( leftStatic )
895 {
896 mOpLeft->prepare( parent, context );
897 if ( mOpLeft->hasCachedStaticValue() )
898 {
899 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
900 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
901 {
902 mCachedStaticValue = false;
903 mHasCachedValue = true;
904 return true;
905 }
906 }
907 }
908 else if ( rightStatic )
909 {
910 mOpRight->prepare( parent, context );
911 if ( mOpRight->hasCachedStaticValue() )
912 {
913 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
914 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
915 {
916 mCachedStaticValue = false;
917 mHasCachedValue = true;
918 return true;
919 }
920 }
921 }
922
923 break;
924 }
925
947 break;
948 }
949
950 return false;
951}
952
953//
954
956{
957 if ( mList->count() == 0 )
958 return mNotIn ? TVL_True : TVL_False;
959 QVariant v1 = mNode->eval( parent, context );
961 if ( QgsExpressionUtils::isNull( v1 ) )
962 return TVL_Unknown;
963
964 bool listHasNull = false;
965
966 const QList< QgsExpressionNode * > nodeList = mList->list();
967 for ( QgsExpressionNode *n : nodeList )
968 {
969 QVariant v2 = n->eval( parent, context );
971 if ( QgsExpressionUtils::isNull( v2 ) )
972 listHasNull = true;
973 else
974 {
975 bool equal = false;
976 // check whether they are equal
977 if ( ( v1.type() != QVariant::String || v2.type() != QVariant::String ) &&
978 QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
979 {
980 // do numeric comparison if both operators can be converted to numbers,
981 // and they aren't both string
982 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
984 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
986 equal = qgsDoubleNear( f1, f2 );
987 }
988 else
989 {
990 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
992 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
994 equal = QString::compare( s1, s2 ) == 0;
995 }
996
997 if ( equal ) // we know the result
998 return mNotIn ? TVL_False : TVL_True;
999 }
1000 }
1001
1002 // item not found
1003 if ( listHasNull )
1004 return TVL_Unknown;
1005 else
1006 return mNotIn ? TVL_True : TVL_False;
1007}
1008
1010{
1011 delete mNode;
1012 delete mList;
1013}
1014
1016{
1017 return ntInOperator;
1018}
1019
1021{
1022 bool res = mNode->prepare( parent, context );
1023 const QList< QgsExpressionNode * > nodeList = mList->list();
1024 for ( QgsExpressionNode *n : nodeList )
1025 {
1026 res = res && n->prepare( parent, context );
1027 }
1028 return res;
1029}
1030
1032{
1033 return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1034}
1035
1037{
1038 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1039 cloneTo( copy );
1040 return copy;
1041}
1042
1044{
1045 if ( !mNode->isStatic( parent, context ) )
1046 return false;
1047
1048 const QList< QgsExpressionNode * > nodeList = mList->list();
1049 for ( QgsExpressionNode *n : nodeList )
1050 {
1051 if ( !n->isStatic( parent, context ) )
1052 return false;
1053 }
1054
1055 return true;
1056}
1057
1058//
1059
1061{
1062 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1063 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1064
1065 QVariant res = fd->run( mArgs, context, parent, this );
1067
1068 // everything went fine
1069 return res;
1070}
1071
1073 : mFnIndex( fnIndex )
1074{
1075 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1076 if ( functionParams.isEmpty() )
1077 {
1078 // function does not support parameters
1079 mArgs = args;
1080 }
1081 else if ( !args )
1082 {
1083 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1084 mArgs = new NodeList();
1085 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1086 {
1087 // insert default value for QgsExpressionFunction::Parameter
1088 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1089 }
1090 }
1091 else
1092 {
1093 mArgs = new NodeList();
1094
1095 int idx = 0;
1096 //first loop through unnamed arguments
1097 while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
1098 {
1099 mArgs->append( args->list().at( idx )->clone() );
1100 idx++;
1101 }
1102
1103 //next copy named QgsExpressionFunction::Parameters in order expected by function
1104 for ( ; idx < functionParams.count(); ++idx )
1105 {
1106 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1107 if ( nodeIdx < 0 )
1108 {
1109 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1110 mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
1111 }
1112 else
1113 {
1114 mArgs->append( args->list().at( nodeIdx )->clone() );
1115 }
1116 }
1117
1118 delete args;
1119 }
1120}
1121
1123{
1124 delete mArgs;
1125}
1126
1128{
1129 return ntFunction;
1130}
1131
1133{
1134 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1135
1136 bool res = fd->prepare( this, parent, context );
1137 if ( mArgs && !fd->lazyEval() )
1138 {
1139 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1140 for ( QgsExpressionNode *n : nodeList )
1141 {
1142 res = res && n->prepare( parent, context );
1143 }
1144 }
1145 return res;
1146}
1147
1149{
1150 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1151 if ( fd->params() == 0 )
1152 return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1153 else
1154 return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1155}
1156
1158{
1159 if ( hasCachedStaticValue() )
1160 return QSet< QString >();
1161
1162 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1163 QSet<QString> functionColumns = fd->referencedColumns( this );
1164
1165 if ( !mArgs )
1166 {
1167 //no referenced columns in arguments, just return function's referenced columns
1168 return functionColumns;
1169 }
1170
1171 int paramIndex = 0;
1172 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1173 for ( QgsExpressionNode *n : nodeList )
1174 {
1175 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1176 functionColumns.unite( n->referencedColumns() );
1177 paramIndex++;
1178 }
1179
1180 return functionColumns;
1181}
1182
1184{
1185 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1186 if ( fd->name() == QLatin1String( "var" ) )
1187 {
1188 if ( !mArgs->list().isEmpty() )
1189 {
1190 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1191 if ( var )
1192 return QSet<QString>() << var->value().toString();
1193 }
1194 return QSet<QString>() << QString();
1195 }
1196 else
1197 {
1198 QSet<QString> functionVariables = QSet<QString>();
1199
1200 if ( !mArgs )
1201 return functionVariables;
1202
1203 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1204 for ( QgsExpressionNode *n : nodeList )
1205 {
1206 functionVariables.unite( n->referencedVariables() );
1207 }
1208
1209 return functionVariables;
1210 }
1211}
1212
1214{
1215 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1216 QSet<QString> functions = QSet<QString>();
1217 functions.insert( fd->name() );
1218
1219 if ( !mArgs )
1220 return functions;
1221
1222 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1223 for ( QgsExpressionNode *n : nodeList )
1224 {
1225 functions.unite( n->referencedFunctions() );
1226 }
1227 return functions;
1228}
1229
1230QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1231{
1232 QList<const QgsExpressionNode *> lst;
1233 lst << this;
1234 if ( !mArgs )
1235 return lst;
1236
1237 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1238 for ( QgsExpressionNode *n : nodeList )
1239 {
1240 lst += n->nodes();
1241 }
1242 return lst;
1243}
1244
1246{
1247 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1248 if ( mArgs )
1249 {
1250 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1251 for ( QgsExpressionNode *n : nodeList )
1252 needs |= n->needsGeometry();
1253 }
1254 return needs;
1255}
1256
1258{
1259 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1260 cloneTo( copy );
1261 return copy;
1262}
1263
1265{
1266 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1267}
1268
1270{
1271 if ( !args || !args->hasNamedNodes() )
1272 return true;
1273
1274 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1275 if ( functionParams.isEmpty() )
1276 {
1277 error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1278 return false;
1279 }
1280 else
1281 {
1282 QSet< int > providedArgs;
1283 QSet< int > handledArgs;
1284 int idx = 0;
1285 //first loop through unnamed arguments
1286 while ( args->names().at( idx ).isEmpty() )
1287 {
1288 providedArgs << idx;
1289 handledArgs << idx;
1290 idx++;
1291 }
1292
1293 //next check named QgsExpressionFunction::Parameters
1294 for ( ; idx < functionParams.count(); ++idx )
1295 {
1296 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1297 if ( nodeIdx < 0 )
1298 {
1299 if ( !functionParams.at( idx ).optional() )
1300 {
1301 error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1302 return false;
1303 }
1304 }
1305 else
1306 {
1307 if ( providedArgs.contains( idx ) )
1308 {
1309 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1310 return false;
1311 }
1312 }
1313 providedArgs << idx;
1314 handledArgs << nodeIdx;
1315 }
1316
1317 //last check for bad names
1318 idx = 0;
1319 const QStringList nameList = args->names();
1320 for ( const QString &name : nameList )
1321 {
1322 if ( !name.isEmpty() && !functionParams.contains( name ) )
1323 {
1324 error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1325 return false;
1326 }
1327 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1328 {
1329 int functionIdx = functionParams.indexOf( name );
1330 if ( providedArgs.contains( functionIdx ) )
1331 {
1332 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1333 return false;
1334 }
1335 }
1336 idx++;
1337 }
1338
1339 }
1340 return true;
1341}
1342
1343//
1344
1346{
1347 Q_UNUSED( context )
1348 Q_UNUSED( parent )
1349 return mValue;
1350}
1351
1353{
1354 return ntLiteral;
1355}
1356
1358{
1359 Q_UNUSED( parent )
1360 Q_UNUSED( context )
1361 return true;
1362}
1363
1364
1366{
1367 if ( QgsVariantUtils::isNull( mValue ) )
1368 return QStringLiteral( "NULL" );
1369
1370 switch ( mValue.type() )
1371 {
1372 case QVariant::Int:
1373 return QString::number( mValue.toInt() );
1374 case QVariant::Double:
1375 return QString::number( mValue.toDouble() );
1376 case QVariant::LongLong:
1377 return QString::number( mValue.toLongLong() );
1378 case QVariant::String:
1379 return QgsExpression::quotedString( mValue.toString() );
1380 case QVariant::Bool:
1381 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1382 default:
1383 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1384 }
1385}
1386
1388{
1389 return valueAsString();
1390}
1391
1393{
1394 return QSet<QString>();
1395}
1396
1398{
1399 return QSet<QString>();
1400}
1401
1403{
1404 return QSet<QString>();
1405}
1406
1407QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1408{
1409 QList<const QgsExpressionNode *> lst;
1410 lst << this;
1411 return lst;
1412}
1413
1415{
1416 return false;
1417}
1418
1420{
1422 cloneTo( copy );
1423 return copy;
1424}
1425
1427{
1428 Q_UNUSED( context )
1429 Q_UNUSED( parent )
1430 return true;
1431}
1432
1433//
1434
1436{
1437 Q_UNUSED( parent )
1438 int index = mIndex;
1439
1440 if ( index < 0 )
1441 {
1442 // have not yet found field index - first check explicitly set fields collection
1443 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1444 {
1445 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1446 index = fields.lookupField( mName );
1447 }
1448 }
1449
1450 if ( context )
1451 {
1452 QgsFeature feature = context->feature();
1453 if ( feature.isValid() )
1454 {
1455 if ( index >= 0 )
1456 return feature.attribute( index );
1457 else
1458 return feature.attribute( mName );
1459 }
1460 else
1461 {
1462 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1463 }
1464 }
1465 if ( index < 0 )
1466 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1467 return QVariant();
1468}
1469
1471{
1472 return ntColumnRef;
1473}
1474
1476{
1477 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1478 return false;
1479
1480 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1481
1482 mIndex = fields.lookupField( mName );
1483
1484 if ( mIndex == -1 && context->hasFeature() )
1485 {
1486 mIndex = context->feature().fieldNameIndex( mName );
1487 }
1488
1489 if ( mIndex == -1 )
1490 {
1491 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1492 return false;
1493 }
1494 return true;
1495}
1496
1498{
1499 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
1500 const QRegularExpressionMatch match = re.match( mName );
1501 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1502}
1503
1505{
1506 return QSet<QString>() << mName;
1507}
1508
1510{
1511 return QSet<QString>();
1512}
1513
1515{
1516 return QSet<QString>();
1517}
1518
1519QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1520{
1521 QList<const QgsExpressionNode *> result;
1522 result << this;
1523 return result;
1524}
1525
1527{
1528 return false;
1529}
1530
1532{
1534 cloneTo( copy );
1535 return copy;
1536}
1537
1539{
1540 Q_UNUSED( context )
1541 Q_UNUSED( parent )
1542 return false;
1543}
1544
1545//
1546
1548 : mConditions( *conditions )
1549 , mElseExp( elseExp )
1550{
1551 delete conditions;
1552}
1553
1555{
1556 delete mElseExp;
1557 qDeleteAll( mConditions );
1558}
1559
1561{
1562 return ntCondition;
1563}
1564
1566{
1567 for ( WhenThen *cond : std::as_const( mConditions ) )
1568 {
1569 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1570 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1572 if ( tvl == QgsExpressionUtils::True )
1573 {
1574 QVariant vRes = cond->mThenExp->eval( parent, context );
1576 return vRes;
1577 }
1578 }
1579
1580 if ( mElseExp )
1581 {
1582 QVariant vElse = mElseExp->eval( parent, context );
1584 return vElse;
1585 }
1586
1587 // return NULL if no condition is matching
1588 return QVariant();
1589}
1590
1592{
1593 bool foundAnyNonStaticConditions = false;
1594 for ( WhenThen *cond : std::as_const( mConditions ) )
1595 {
1596 const bool res = cond->mWhenExp->prepare( parent, context )
1597 && cond->mThenExp->prepare( parent, context );
1598 if ( !res )
1599 return false;
1600
1601 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1602 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1603 {
1604 // 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
1605 // value, and the static value for this WHEN clause is True.
1606 if ( cond->mThenExp->hasCachedStaticValue() )
1607 {
1608 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1609 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1610 mHasCachedValue = true;
1611 return true;
1612 }
1613 else
1614 {
1615 // 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
1616 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1617 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1618 return true;
1619 }
1620 }
1621 }
1622
1623 if ( mElseExp )
1624 {
1625 const bool res = mElseExp->prepare( parent, context );
1626 if ( !res )
1627 return false;
1628
1629 if ( !foundAnyNonStaticConditions )
1630 {
1631 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1632 if ( mElseExp->hasCachedStaticValue() )
1633 {
1635 mHasCachedValue = true;
1636 return true;
1637 }
1638 else
1639 {
1640 // so even though the ELSE node is non-static we can effectively replace
1641 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1642 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1643 return true;
1644 }
1645 }
1646 }
1647
1648 return true;
1649}
1650
1652{
1653 QString msg( QStringLiteral( "CASE" ) );
1654 for ( WhenThen *cond : mConditions )
1655 {
1656 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1657 }
1658 if ( mElseExp )
1659 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1660 msg += QLatin1String( " END" );
1661 return msg;
1662}
1663
1665{
1666 if ( hasCachedStaticValue() )
1667 return QSet< QString >();
1668
1669 QSet<QString> lst;
1670 for ( WhenThen *cond : mConditions )
1671 {
1672 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1673 }
1674
1675 if ( mElseExp )
1676 lst += mElseExp->referencedColumns();
1677
1678 return lst;
1679}
1680
1682{
1683 QSet<QString> lst;
1684 for ( WhenThen *cond : mConditions )
1685 {
1686 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1687 }
1688
1689 if ( mElseExp )
1690 lst += mElseExp->referencedVariables();
1691
1692 return lst;
1693}
1694
1696{
1697 QSet<QString> lst;
1698 for ( WhenThen *cond : mConditions )
1699 {
1700 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1701 }
1702
1703 if ( mElseExp )
1704 lst += mElseExp->referencedFunctions();
1705
1706 return lst;
1707}
1708
1709QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1710{
1711 QList<const QgsExpressionNode *> lst;
1712 lst << this;
1713 for ( WhenThen *cond : mConditions )
1714 {
1715 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1716 }
1717
1718 if ( mElseExp )
1719 lst += mElseExp->nodes();
1720
1721 return lst;
1722}
1723
1725{
1726 for ( WhenThen *cond : mConditions )
1727 {
1728 if ( cond->mWhenExp->needsGeometry() ||
1729 cond->mThenExp->needsGeometry() )
1730 return true;
1731 }
1732
1733 return mElseExp && mElseExp->needsGeometry();
1734}
1735
1737{
1739 conditions.reserve( mConditions.size() );
1740 for ( WhenThen *wt : mConditions )
1741 conditions.append( wt->clone() );
1742
1743 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1744 cloneTo( copy );
1745 return copy;
1746}
1747
1749{
1750 for ( WhenThen *wt : mConditions )
1751 {
1752 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1753 return false;
1754 }
1755
1756 if ( mElseExp )
1757 return mElseExp->isStatic( parent, context );
1758
1759 return true;
1760}
1761
1763{
1764 if ( hasCachedStaticValue() )
1765 return QSet< QString >();
1766
1767 QSet<QString> lst( mNode->referencedColumns() );
1768 const QList< QgsExpressionNode * > nodeList = mList->list();
1769 for ( const QgsExpressionNode *n : nodeList )
1770 lst.unite( n->referencedColumns() );
1771 return lst;
1772}
1773
1775{
1776 QSet<QString> lst( mNode->referencedVariables() );
1777 const QList< QgsExpressionNode * > nodeList = mList->list();
1778 for ( const QgsExpressionNode *n : nodeList )
1779 lst.unite( n->referencedVariables() );
1780 return lst;
1781}
1782
1784{
1785 QSet<QString> lst( mNode->referencedFunctions() );
1786 const QList< QgsExpressionNode * > nodeList = mList->list();
1787 for ( const QgsExpressionNode *n : nodeList )
1788 lst.unite( n->referencedFunctions() );
1789 return lst;
1790}
1791
1792QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1793{
1794 QList<const QgsExpressionNode *> lst;
1795 lst << this;
1796 const QList< QgsExpressionNode * > nodeList = mList->list();
1797 for ( const QgsExpressionNode *n : nodeList )
1798 lst += n->nodes();
1799 return lst;
1800}
1801
1802
1804{
1805 delete mNode;
1806 delete mLowerBound;
1807 delete mHigherBound;
1808}
1809
1811{
1812 return ntBetweenOperator;
1813}
1814
1816{
1817 bool res = mNode->prepare( parent, context );
1818 res = res && mLowerBound->prepare( parent, context );
1819 res = res && mHigherBound->prepare( parent, context );
1820 return res;
1821}
1822
1824{
1825 const QVariant nodeVal = mNode->eval( parent, context );
1826 if ( QgsVariantUtils::isNull( nodeVal ) )
1827 {
1828 return QVariant();
1829 }
1830
1831 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1832
1833 QgsExpressionNodeBinaryOperator lowBound { QgsExpressionNodeBinaryOperator::BinaryOperator::boGE, nodeValNode.clone(), mLowerBound->clone() };
1834 const QVariant lowBoundValue = lowBound.eval( parent, context );
1835 const bool lowBoundBool { lowBoundValue.toBool() };
1836
1837 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
1838 {
1839 return QVariant( mNegate );
1840 }
1841
1842 QgsExpressionNodeBinaryOperator highBound { QgsExpressionNodeBinaryOperator::BinaryOperator::boLE, nodeValNode.clone(), mHigherBound->clone() };
1843 const QVariant highBoundValue = highBound.eval( parent, context );
1844
1845 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
1846 {
1847 return QVariant();
1848 }
1849
1850 const bool highBoundBool { highBoundValue.toBool() };
1851
1852 // We already checked if both are nulls
1853 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
1854 {
1855
1856 // In this case we can return a boolean
1857 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
1858 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
1859 {
1860 return QVariant( mNegate );
1861 }
1862
1863 // Indetermined
1864 return QVariant();
1865
1866 }
1867
1868 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
1869 {
1870 return QVariant( mNegate );
1871 }
1872
1873 const bool res { lowBoundBool &&highBoundBool };
1874 return mNegate ? QVariant( ! res ) : QVariant( res );
1875
1876}
1877
1879{
1880 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
1881}
1882
1884{
1885 QSet<QString> lst( mNode->referencedVariables() );
1886 lst.unite( mLowerBound->referencedVariables() );
1887 lst.unite( mHigherBound->referencedVariables() );
1888 return lst;
1889}
1890
1892{
1893 QSet<QString> lst( mNode->referencedFunctions() );
1894 lst.unite( mLowerBound->referencedFunctions() );
1895 lst.unite( mHigherBound->referencedFunctions() );
1896 return lst;
1897}
1898
1899QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
1900{
1901 return { this, mLowerBound, mHigherBound };
1902}
1903
1905{
1906 QSet<QString> lst( mNode->referencedColumns() );
1907 lst.unite( mLowerBound->referencedColumns() );
1908 lst.unite( mHigherBound->referencedColumns() );
1909 return lst;
1910}
1911
1913{
1914 if ( mNode->needsGeometry() )
1915 return true;
1916
1917 if ( mLowerBound->needsGeometry() )
1918 return true;
1919
1920 if ( mHigherBound->needsGeometry() )
1921 return true;
1922
1923 return false;
1924}
1925
1927{
1928 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
1929 cloneTo( copy );
1930 return copy;
1931}
1932
1934{
1935 if ( !mNode->isStatic( parent, context ) )
1936 return false;
1937
1938 if ( !mLowerBound->isStatic( parent, context ) )
1939 return false;
1940
1941 if ( !mHigherBound->isStatic( parent, context ) )
1942 return false;
1943
1944 return true;
1945}
1946
1948{
1949 return mLowerBound;
1950}
1951
1953{
1954 return mHigherBound;
1955}
1956
1958{
1959 return mNegate;
1960}
1961
1963 : mWhenExp( whenExp )
1964 , mThenExp( thenExp )
1965{
1966}
1967
1969{
1970 delete mWhenExp;
1971 delete mThenExp;
1972}
1973
1975{
1976 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1977}
1978
1980{
1981 return BINARY_OPERATOR_TEXT[mOp];
1982}
1983
1984//
1985
1987{
1988 const QVariant container = mContainer->eval( parent, context );
1990 const QVariant index = mIndex->eval( parent, context );
1992
1993 switch ( container.type() )
1994 {
1995 case QVariant::Map:
1996 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1997
1998 case QVariant::List:
1999 case QVariant::StringList:
2000 {
2001 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2002 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2003 if ( pos >= list.length() || pos < -list.length() )
2004 {
2005 return QVariant();
2006 }
2007 if ( pos < 0 )
2008 {
2009 // negative indices are from back of list
2010 pos += list.length();
2011 }
2012
2013 return list.at( pos );
2014 }
2015
2016 default:
2017 if ( !QgsVariantUtils::isNull( container ) )
2018 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
2019 return QVariant();
2020 }
2021}
2022
2024{
2025 return ntIndexOperator;
2026}
2027
2029{
2030 bool resC = mContainer->prepare( parent, context );
2031 bool resV = mIndex->prepare( parent, context );
2032 return resC && resV;
2033}
2034
2036{
2037 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2038}
2039
2041{
2042 if ( hasCachedStaticValue() )
2043 return QSet< QString >();
2044
2045 return mContainer->referencedColumns() + mIndex->referencedColumns();
2046}
2047
2049{
2050 return mContainer->referencedVariables() + mIndex->referencedVariables();
2051}
2052
2054{
2055 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2056}
2057
2058QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2059{
2060 QList<const QgsExpressionNode *> lst;
2061 lst << this;
2062 lst += mContainer->nodes() + mIndex->nodes();
2063 return lst;
2064}
2065
2067{
2068 return mContainer->needsGeometry() || mIndex->needsGeometry();
2069}
2070
2072{
2073 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2074 cloneTo( copy );
2075 return copy;
2076}
2077
2079{
2080 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2081}
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.
A 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.
SQL-like BETWEEN and NOT BETWEEN predicates.
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.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
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 it 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.
QgsExpressionNodeCondition::WhenThen * clone() const
Gets a deep copy of this WhenThen combination.
An expression node for CASE WHEN clauses.
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.
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.
An expression node for expression functions.
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.
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.
A indexing expression operator, which allows use of square brackets [] to reference map and array ite...
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.
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.
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.
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.
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.
bool hasNamedNodes() const
Returns true if list contains any named nodes.
virtual QString dump() const
Returns a string dump of the expression node.
QStringList names() const
Returns a list of names for nodes.
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.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Abstract base class for all nodes that can appear in an expression.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
virtual QString dump() const =0
Dump this node into a serialized (part) of an expression.
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.
virtual bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const =0
Returns true if this node can be evaluated for a static value.
bool prepare(QgsExpression *parent, const QgsExpressionContext *context)
Prepare this node for evaluation.
virtual QSet< QString > referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node.
bool mHasCachedValue
true if the node has a static, precalculated value.
const QgsExpressionNode * effectiveNode() const
Returns a reference to the simplest node which represents this node, after any compilation optimizati...
QVariant cachedStaticValue() const
Returns the node's static cached value.
virtual QSet< QString > referencedVariables() const =0
Returns a set of all variables which are used in this expression.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
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.
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression.
virtual QList< const QgsExpressionNode * > nodes() const =0
Returns a list of all nodes which are used in this expression.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
virtual QSet< QString > referencedFunctions() const =0
Returns a set of all functions which are used in this expression.
Class for 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:56
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:353
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:219
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:338
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:242
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
#define str(x)
Definition: qgis.cpp:37
#define FALLTHROUGH
Definition: qgis.h:4120
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3509
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
const QString & typeName
QgsExpressionNode * node
Node.