QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
qgsexpressionnodeimpl.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsexpressionnodeimpl.cpp
3 -------------------
4 begin : May 2017
5 copyright : (C) 2017 Matthias Kuhn
6 email : matthias@opengis.ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#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 <QRegularExpression>
26
27const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
28{
29 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
30 "OR", "AND",
31 "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
32 "+", "-", "*", "/", "//", "%", "^",
33 "||"
34};
35
36const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
37{
38 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
39 "NOT", "-"
40};
41
43{
44 bool needs = false;
45 const QList< QgsExpressionNode * > nodeList = mList->list();
46 for ( QgsExpressionNode *n : nodeList )
47 needs |= n->needsGeometry();
48 return needs;
49}
50
52{
53 qDeleteAll( mList );
54}
55
57{
58 mList.append( node->node );
59 mNameList.append( cleanNamedNodeName( node->name ) );
60 mHasNamedNodes = true;
61 delete node;
62}
63
65{
66 NodeList *nl = new NodeList;
67 for ( QgsExpressionNode *node : mList )
68 {
69 nl->mList.append( node->clone() );
70 }
71 nl->mNameList = mNameList;
72
73 return nl;
74}
75
77{
78 QString msg;
79 bool first = true;
80 for ( QgsExpressionNode *n : mList )
81 {
82 if ( !first ) msg += QLatin1String( ", " );
83 else first = false;
84 msg += n->dump();
85 }
86 return msg;
87}
88
89QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
90{
91 QString cleaned = name.toLower();
92
93 // upgrade older argument names to standard versions
94 if ( cleaned == QLatin1String( "geom" ) )
95 cleaned = QStringLiteral( "geometry" );
96 else if ( cleaned == QLatin1String( "val" ) )
97 cleaned = QStringLiteral( "value" );
98 else if ( cleaned == QLatin1String( "geometry a" ) )
99 cleaned = QStringLiteral( "geometry1" );
100 else if ( cleaned == QLatin1String( "geometry b" ) )
101 cleaned = QStringLiteral( "geometry2" );
102
103 return cleaned;
104}
105
106
107//
108
110{
111 QVariant val = mOperand->eval( parent, context );
113
114 switch ( mOp )
115 {
116 case uoNot:
117 {
118 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
120 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
121 }
122
123 case uoMinus:
124 if ( QgsExpressionUtils::isIntSafe( val ) )
125 return QVariant( - QgsExpressionUtils::getIntValue( val, parent ) );
126 else if ( QgsExpressionUtils::isDoubleSafe( val ) )
127 return QVariant( - QgsExpressionUtils::getDoubleValue( val, parent ) );
128 else
129 SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
130 }
131 return QVariant();
132}
133
138
140{
141 return mOperand->prepare( parent, context );
142}
143
145{
146 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand ) )
147 return QStringLiteral( "%1 ( %2 )" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
148 else
149 return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
150}
151
153{
154 if ( hasCachedStaticValue() )
155 return QSet< QString >();
156
157 return mOperand->referencedColumns();
158}
159
161{
162 return mOperand->referencedVariables();
163}
164
166{
167 return mOperand->referencedFunctions();
168}
169
170QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
171{
172 QList<const QgsExpressionNode *> lst;
173 lst.append( this );
174 lst += mOperand->nodes();
175 return lst;
176}
177
179{
180 return mOperand->needsGeometry();
181}
182
184{
185 QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
186 cloneTo( copy );
187 return copy;
188}
189
191{
192 return mOperand->isStatic( parent, context );
193}
194
196{
197 return UNARY_OPERATOR_TEXT[mOp];
198}
199
200//
201
203{
204 QVariant vL = mOpLeft->eval( parent, context );
206
207 if ( mOp == boAnd || mOp == boOr )
208 {
209 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
211 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
212 return TVL_False; // shortcut -- no need to evaluate right-hand side
213 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
214 return TVL_True; // shortcut -- no need to evaluate right-hand side
215 }
216
217 QVariant vR = mOpRight->eval( parent, context );
219
220 switch ( mOp )
221 {
222 case boPlus:
223 if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
224 {
225 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
227 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
229 return QVariant( sL + sR );
230 }
231 //intentional fall-through
233 case boMinus:
234 case boMul:
235 case boDiv:
236 case boMod:
237 {
238 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
239 return QVariant();
240 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
241 {
242 // both are integers - let's use integer arithmetic
243 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
245 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
247
248 if ( mOp == boMod && iR == 0 )
249 return QVariant();
250
251 return QVariant( computeInt( iL, iR ) );
252 }
253 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
254 {
255 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
257 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
259 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
260 {
261 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
262 return QVariant();
263 }
264 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
265 }
266 else if ( mOp == boPlus && ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
267 ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
268 {
269 QDate date = QgsExpressionUtils::getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
271 QTime time = QgsExpressionUtils::getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
273 QDateTime dt = QDateTime( date, time );
274 return QVariant( dt );
275 }
276 else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
277 {
278 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
280 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
282 return date1 - date2;
283 }
284 else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
285 {
286 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
288 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
290 return time1 - time2;
291 }
292 else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
293 {
294 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
296 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
298 return datetime1 - datetime2;
299 }
300 else
301 {
302 // general floating point arithmetic
303 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
305 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
307 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
308 return QVariant(); // silently handle division by zero and return NULL
309 return QVariant( computeDouble( fL, fR ) );
310 }
311 }
312 case boIntDiv:
313 {
314 //integer division
315 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
317 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
319 if ( fR == 0. )
320 return QVariant(); // silently handle division by zero and return NULL
321 return QVariant( qlonglong( std::floor( fL / fR ) ) );
322 }
323 case boPow:
324 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
325 return QVariant();
326 else
327 {
328 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
330 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
332 return QVariant( std::pow( fL, fR ) );
333 }
334
335 case boAnd:
336 {
337 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
339 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
340 }
341
342 case boOr:
343 {
344 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
346 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
347 }
348
349 case boEQ:
350 case boNE:
351 case boLT:
352 case boGT:
353 case boLE:
354 case boGE:
355 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
356 {
357 return TVL_Unknown;
358 }
359 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
360 {
361 // verify that we have two lists
362 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
363 return TVL_Unknown;
364
365 // and search for not equal respective items
366 QVariantList lL = vL.toList();
367 QVariantList lR = vR.toList();
368 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
369 {
370 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
371 continue; // same behavior as PostgreSQL
372
373 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
374 {
375 switch ( mOp )
376 {
377 case boEQ:
378 return false;
379 case boNE:
380 return true;
381 case boLT:
382 case boLE:
383 return QgsExpressionUtils::isNull( lR.at( i ) );
384 case boGT:
385 case boGE:
386 return QgsExpressionUtils::isNull( lL.at( i ) );
387 default:
388 Q_ASSERT( false );
389 return TVL_Unknown;
390 }
391 }
392
393 QgsExpressionNodeLiteral nL( lL.at( i ) );
394 QgsExpressionNodeLiteral nR( lR.at( i ) );
395 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
396 QVariant eq = eqNode.eval( parent, context );
398 if ( eq == TVL_False )
399 {
400 // return the two items comparison
401 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
402 QVariant v = node.eval( parent, context );
404 return v;
405 }
406 }
407
408 // default to length comparison
409 switch ( mOp )
410 {
411 case boEQ:
412 return lL.length() == lR.length();
413 case boNE:
414 return lL.length() != lR.length();
415 case boLT:
416 return lL.length() < lR.length();
417 case boGT:
418 return lL.length() > lR.length();
419 case boLE:
420 return lL.length() <= lR.length();
421 case boGE:
422 return lL.length() >= lR.length();
423 default:
424 Q_ASSERT( false );
425 return TVL_Unknown;
426 }
427 }
428 else if ( ( vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime ) )
429 {
430 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
432 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
434
435 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
436 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
437 // results (due to different hidden timezones), we force all datetime comparisons to treat
438 // all datetime values as having the same time zone
439 dL.setTimeSpec( Qt::UTC );
440 dR.setTimeSpec( Qt::UTC );
441
442 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
443 }
444 else if ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Date ) )
445 {
446 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
448 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
450 return compare( dR.daysTo( dL ) ) ? TVL_True : TVL_False;
451 }
452 else if ( ( vL.type() == QVariant::Time && vR.type() == QVariant::Time ) )
453 {
454 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
456 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
458 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
459 }
460 else if ( ( vL.type() != QVariant::String || vR.type() != QVariant::String ) &&
461 QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
462 {
463 // do numeric comparison if both operators can be converted to numbers,
464 // and they aren't both string
465 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
467 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
469 return compare( fL - fR ) ? TVL_True : TVL_False;
470 }
471 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
472 else if ( vL.userType() == QMetaType::type( "QgsInterval" ) && vR.userType() == QMetaType::type( "QgsInterval" ) )
473 {
474 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
476 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
478 return compare( fL - fR ) ? TVL_True : TVL_False;
479 }
480 else
481 {
482 // do string comparison otherwise
483 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
485 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
487 int diff = QString::compare( sL, sR );
488 return compare( diff ) ? TVL_True : TVL_False;
489 }
490
491 case boIs:
492 case boIsNot:
493 if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
494 return ( mOp == boIs ? TVL_True : TVL_False );
495 else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
496 return ( mOp == boIs ? TVL_False : TVL_True );
497 else // both operators non-null
498 {
499 bool equal = false;
500 if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
501 ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
502 {
503 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
505 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
507 equal = qgsDoubleNear( fL, fR );
508 }
509 else
510 {
511 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
513 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
515 equal = QString::compare( sL, sR ) == 0;
516 }
517 if ( equal )
518 return mOp == boIs ? TVL_True : TVL_False;
519 else
520 return mOp == boIs ? TVL_False : TVL_True;
521 }
522
523 case boRegexp:
524 case boLike:
525 case boNotLike:
526 case boILike:
527 case boNotILike:
528 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
529 return TVL_Unknown;
530 else
531 {
532 QString str = QgsExpressionUtils::getStringValue( vL, parent );
534 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
536 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
537 bool matches;
538 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
539 {
540 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
541 // manage escape % and _
542 if ( esc_regexp.startsWith( '%' ) )
543 {
544 esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
545 }
546 const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
547 int pos = 0;
548 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
549 {
550 esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
551 pos += 1;
552 }
553 const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
554 esc_regexp.replace( rx2, QStringLiteral( "%" ) );
555 if ( esc_regexp.startsWith( '_' ) )
556 {
557 esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
558 }
559 const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
560 pos = 0;
561 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
562 {
563 esc_regexp.replace( pos + 1, 1, '.' );
564 pos += 1;
565 }
566 esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
567
568 matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
569 }
570 else
571 {
572 matches = QRegularExpression( regexp ).match( str ).hasMatch();
573 }
574
575 if ( mOp == boNotLike || mOp == boNotILike )
576 {
577 matches = !matches;
578 }
579
580 return matches ? TVL_True : TVL_False;
581 }
582
583 case boConcat:
584 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
585 return QVariant();
586 else
587 {
588 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
590 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
592 return QVariant( sL + sR );
593 }
594 }
595 Q_ASSERT( false );
596 return QVariant();
597}
598
599bool QgsExpressionNodeBinaryOperator::compare( double diff )
600{
601 switch ( mOp )
602 {
603 case boEQ:
604 return qgsDoubleNear( diff, 0.0 );
605 case boNE:
606 return !qgsDoubleNear( diff, 0.0 );
607 case boLT:
608 return diff < 0;
609 case boGT:
610 return diff > 0;
611 case boLE:
612 return diff <= 0;
613 case boGE:
614 return diff >= 0;
615 default:
616 Q_ASSERT( false );
617 return false;
618 }
619}
620
621qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
622{
623 switch ( mOp )
624 {
625 case boPlus:
626 return x + y;
627 case boMinus:
628 return x - y;
629 case boMul:
630 return x * y;
631 case boDiv:
632 return x / y;
633 case boMod:
634 return x % y;
635 default:
636 Q_ASSERT( false );
637 return 0;
638 }
639}
640
641QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
642{
643 switch ( mOp )
644 {
645 case boPlus:
646 return d.addSecs( i->seconds() );
647 case boMinus:
648 return d.addSecs( -i->seconds() );
649 default:
650 Q_ASSERT( false );
651 return QDateTime();
652 }
653}
654
655double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
656{
657 switch ( mOp )
658 {
659 case boPlus:
660 return x + y;
661 case boMinus:
662 return x - y;
663 case boMul:
664 return x * y;
665 case boDiv:
666 return x / y;
667 case boMod:
668 return std::fmod( x, y );
669 default:
670 Q_ASSERT( false );
671 return 0;
672 }
673}
674
679
681{
682 bool resL = mOpLeft->prepare( parent, context );
683 bool resR = mOpRight->prepare( parent, context );
684 return resL && resR;
685}
686
688{
689 // see left/right in qgsexpressionparser.yy
690 switch ( mOp )
691 {
692 case boOr:
693 return 1;
694
695 case boAnd:
696 return 2;
697
698 case boEQ:
699 case boNE:
700 case boLE:
701 case boGE:
702 case boLT:
703 case boGT:
704 case boRegexp:
705 case boLike:
706 case boILike:
707 case boNotLike:
708 case boNotILike:
709 case boIs:
710 case boIsNot:
711 return 3;
712
713 case boPlus:
714 case boMinus:
715 return 4;
716
717 case boMul:
718 case boDiv:
719 case boIntDiv:
720 case boMod:
721 return 5;
722
723 case boPow:
724 return 6;
725
726 case boConcat:
727 return 7;
728 }
729 Q_ASSERT( false && "unexpected binary operator" );
730 return -1;
731}
732
734{
735 // see left/right in qgsexpressionparser.yy
736 switch ( mOp )
737 {
738 case boOr:
739 case boAnd:
740 case boEQ:
741 case boNE:
742 case boLE:
743 case boGE:
744 case boLT:
745 case boGT:
746 case boRegexp:
747 case boLike:
748 case boILike:
749 case boNotLike:
750 case boNotILike:
751 case boIs:
752 case boIsNot:
753 case boPlus:
754 case boMinus:
755 case boMul:
756 case boDiv:
757 case boIntDiv:
758 case boMod:
759 case boConcat:
760 return true;
761
762 case boPow:
763 return false;
764 }
765 Q_ASSERT( false && "unexpected binary operator" );
766 return false;
767}
768
770{
772 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
773 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
774
775 QString rdump( mOpRight->dump() );
776
777 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
778 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
779 {
780 rdump.prepend( '(' ).append( ')' );
781 }
782
783 QString fmt;
784 if ( leftAssociative() )
785 {
786 fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
787 fmt += QLatin1String( " %2 " );
788 fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
789 }
790 else
791 {
792 fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
793 fmt += QLatin1String( " %2 " );
794 fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
795 }
796
797 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
798}
799
801{
802 if ( hasCachedStaticValue() )
803 return QSet< QString >();
804
805 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
806}
807
809{
810 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
811}
812
814{
815 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
816}
817
818QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
819{
820 QList<const QgsExpressionNode *> lst;
821 lst << this;
822 lst += mOpLeft->nodes() + mOpRight->nodes();
823 return lst;
824}
825
827{
828 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
829}
830
832{
833 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
834 cloneTo( copy );
835 return copy;
836}
837
839{
840 const bool leftStatic = mOpLeft->isStatic( parent, context );
841 const bool rightStatic = mOpRight->isStatic( parent, context );
842
843 if ( leftStatic && rightStatic )
844 return true;
845
846 // special logic for certain ops...
847 switch ( mOp )
848 {
850 {
851 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
852 // of the value of the other node!
853 if ( leftStatic )
854 {
855 mOpLeft->prepare( parent, context );
856 if ( mOpLeft->hasCachedStaticValue() )
857 {
858 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
859 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
860 {
861 mCachedStaticValue = true;
862 mHasCachedValue = true;
863 return true;
864 }
865 }
866 }
867 else if ( rightStatic )
868 {
869 mOpRight->prepare( parent, context );
870 if ( mOpRight->hasCachedStaticValue() )
871 {
872 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
873 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
874 {
875 mCachedStaticValue = true;
876 mHasCachedValue = true;
877 return true;
878 }
879 }
880 }
881
882 break;
883 }
885 {
886 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
887 // of the value of the other node!
888
889 if ( leftStatic )
890 {
891 mOpLeft->prepare( parent, context );
892 if ( mOpLeft->hasCachedStaticValue() )
893 {
894 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
895 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
896 {
897 mCachedStaticValue = false;
898 mHasCachedValue = true;
899 return true;
900 }
901 }
902 }
903 else if ( rightStatic )
904 {
905 mOpRight->prepare( parent, context );
906 if ( mOpRight->hasCachedStaticValue() )
907 {
908 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
909 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
910 {
911 mCachedStaticValue = false;
912 mHasCachedValue = true;
913 return true;
914 }
915 }
916 }
917
918 break;
919 }
920
942 break;
943 }
944
945 return false;
946}
947
948//
949
951{
952 if ( mList->count() == 0 )
953 return mNotIn ? TVL_True : TVL_False;
954 QVariant v1 = mNode->eval( parent, context );
956 if ( QgsExpressionUtils::isNull( v1 ) )
957 return TVL_Unknown;
958
959 bool listHasNull = false;
960
961 const QList< QgsExpressionNode * > nodeList = mList->list();
962 for ( QgsExpressionNode *n : nodeList )
963 {
964 QVariant v2 = n->eval( parent, context );
966 if ( QgsExpressionUtils::isNull( v2 ) )
967 listHasNull = true;
968 else
969 {
970 bool equal = false;
971 // check whether they are equal
972 if ( ( v1.type() != QVariant::String || v2.type() != QVariant::String ) &&
973 QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
974 {
975 // do numeric comparison if both operators can be converted to numbers,
976 // and they aren't both string
977 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
979 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
981 equal = qgsDoubleNear( f1, f2 );
982 }
983 else
984 {
985 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
987 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
989 equal = QString::compare( s1, s2 ) == 0;
990 }
991
992 if ( equal ) // we know the result
993 return mNotIn ? TVL_False : TVL_True;
994 }
995 }
996
997 // item not found
998 if ( listHasNull )
999 return TVL_Unknown;
1000 else
1001 return mNotIn ? TVL_True : TVL_False;
1002}
1003
1005{
1006 delete mNode;
1007 delete mList;
1008}
1009
1014
1016{
1017 bool res = mNode->prepare( parent, context );
1018 const QList< QgsExpressionNode * > nodeList = mList->list();
1019 for ( QgsExpressionNode *n : nodeList )
1020 {
1021 res = res && n->prepare( parent, context );
1022 }
1023 return res;
1024}
1025
1027{
1028 return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1029}
1030
1032{
1033 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1034 cloneTo( copy );
1035 return copy;
1036}
1037
1039{
1040 if ( !mNode->isStatic( parent, context ) )
1041 return false;
1042
1043 const QList< QgsExpressionNode * > nodeList = mList->list();
1044 for ( QgsExpressionNode *n : nodeList )
1045 {
1046 if ( !n->isStatic( parent, context ) )
1047 return false;
1048 }
1049
1050 return true;
1051}
1052
1053//
1054
1056{
1057 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1058 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1059
1060 QVariant res = fd->run( mArgs, context, parent, this );
1062
1063 // everything went fine
1064 return res;
1065}
1066
1068 : mFnIndex( fnIndex )
1069{
1070 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1071 if ( functionParams.isEmpty() )
1072 {
1073 // function does not support parameters
1074 mArgs = args;
1075 }
1076 else if ( !args )
1077 {
1078 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1079 mArgs = new NodeList();
1080 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1081 {
1082 // insert default value for QgsExpressionFunction::Parameter
1083 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1084 }
1085 }
1086 else
1087 {
1088 mArgs = new NodeList();
1089
1090 int idx = 0;
1091 //first loop through unnamed arguments
1092 while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
1093 {
1094 mArgs->append( args->list().at( idx )->clone() );
1095 idx++;
1096 }
1097
1098 //next copy named QgsExpressionFunction::Parameters in order expected by function
1099 for ( ; idx < functionParams.count(); ++idx )
1100 {
1101 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1102 if ( nodeIdx < 0 )
1103 {
1104 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1105 mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
1106 }
1107 else
1108 {
1109 mArgs->append( args->list().at( nodeIdx )->clone() );
1110 }
1111 }
1112
1113 delete args;
1114 }
1115}
1116
1121
1126
1128{
1129 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1130
1131 bool res = fd->prepare( this, parent, context );
1132 if ( mArgs && !fd->lazyEval() )
1133 {
1134 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1135 for ( QgsExpressionNode *n : nodeList )
1136 {
1137 res = res && n->prepare( parent, context );
1138 }
1139 }
1140 return res;
1141}
1142
1144{
1145 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1146 if ( fd->params() == 0 )
1147 return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1148 else
1149 return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1150}
1151
1153{
1154 if ( hasCachedStaticValue() )
1155 return QSet< QString >();
1156
1157 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1158 QSet<QString> functionColumns = fd->referencedColumns( this );
1159
1160 if ( !mArgs )
1161 {
1162 //no referenced columns in arguments, just return function's referenced columns
1163 return functionColumns;
1164 }
1165
1166 int paramIndex = 0;
1167 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1168 for ( QgsExpressionNode *n : nodeList )
1169 {
1170 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1171 functionColumns.unite( n->referencedColumns() );
1172 paramIndex++;
1173 }
1174
1175 return functionColumns;
1176}
1177
1179{
1180 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1181 if ( fd->name() == QLatin1String( "var" ) )
1182 {
1183 if ( !mArgs->list().isEmpty() )
1184 {
1185 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1186 if ( var )
1187 return QSet<QString>() << var->value().toString();
1188 }
1189 return QSet<QString>() << QString();
1190 }
1191 else
1192 {
1193 QSet<QString> functionVariables = QSet<QString>();
1194
1195 if ( !mArgs )
1196 return functionVariables;
1197
1198 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1199 for ( QgsExpressionNode *n : nodeList )
1200 {
1201 functionVariables.unite( n->referencedVariables() );
1202 }
1203
1204 return functionVariables;
1205 }
1206}
1207
1209{
1210 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1211 QSet<QString> functions = QSet<QString>();
1212 functions.insert( fd->name() );
1213
1214 if ( !mArgs )
1215 return functions;
1216
1217 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1218 for ( QgsExpressionNode *n : nodeList )
1219 {
1220 functions.unite( n->referencedFunctions() );
1221 }
1222 return functions;
1223}
1224
1225QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1226{
1227 QList<const QgsExpressionNode *> lst;
1228 lst << this;
1229 if ( !mArgs )
1230 return lst;
1231
1232 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1233 for ( QgsExpressionNode *n : nodeList )
1234 {
1235 lst += n->nodes();
1236 }
1237 return lst;
1238}
1239
1241{
1242 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1243 if ( mArgs )
1244 {
1245 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1246 for ( QgsExpressionNode *n : nodeList )
1247 needs |= n->needsGeometry();
1248 }
1249 return needs;
1250}
1251
1253{
1254 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1255 cloneTo( copy );
1256 return copy;
1257}
1258
1260{
1261 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1262}
1263
1265{
1266 if ( !args || !args->hasNamedNodes() )
1267 return true;
1268
1269 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1270 if ( functionParams.isEmpty() )
1271 {
1272 error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1273 return false;
1274 }
1275 else
1276 {
1277 QSet< int > providedArgs;
1278 QSet< int > handledArgs;
1279 int idx = 0;
1280 //first loop through unnamed arguments
1281 while ( args->names().at( idx ).isEmpty() )
1282 {
1283 providedArgs << idx;
1284 handledArgs << idx;
1285 idx++;
1286 }
1287
1288 //next check named QgsExpressionFunction::Parameters
1289 for ( ; idx < functionParams.count(); ++idx )
1290 {
1291 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1292 if ( nodeIdx < 0 )
1293 {
1294 if ( !functionParams.at( idx ).optional() )
1295 {
1296 error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1297 return false;
1298 }
1299 }
1300 else
1301 {
1302 if ( providedArgs.contains( idx ) )
1303 {
1304 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1305 return false;
1306 }
1307 }
1308 providedArgs << idx;
1309 handledArgs << nodeIdx;
1310 }
1311
1312 //last check for bad names
1313 idx = 0;
1314 const QStringList nameList = args->names();
1315 for ( const QString &name : nameList )
1316 {
1317 if ( !name.isEmpty() && !functionParams.contains( name ) )
1318 {
1319 error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1320 return false;
1321 }
1322 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1323 {
1324 int functionIdx = functionParams.indexOf( name );
1325 if ( providedArgs.contains( functionIdx ) )
1326 {
1327 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1328 return false;
1329 }
1330 }
1331 idx++;
1332 }
1333
1334 }
1335 return true;
1336}
1337
1338//
1339
1341{
1342 Q_UNUSED( context )
1343 Q_UNUSED( parent )
1344 return mValue;
1345}
1346
1351
1353{
1354 Q_UNUSED( parent )
1355 Q_UNUSED( context )
1356 return true;
1357}
1358
1359
1361{
1362 if ( QgsVariantUtils::isNull( mValue ) )
1363 return QStringLiteral( "NULL" );
1364
1365 switch ( mValue.type() )
1366 {
1367 case QVariant::Int:
1368 return QString::number( mValue.toInt() );
1369 case QVariant::Double:
1370 return QString::number( mValue.toDouble() );
1371 case QVariant::LongLong:
1372 return QString::number( mValue.toLongLong() );
1373 case QVariant::String:
1374 return QgsExpression::quotedString( mValue.toString() );
1375 case QVariant::Time:
1376 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1377 case QVariant::Date:
1378 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1379 case QVariant::DateTime:
1380 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1381 case QVariant::Bool:
1382 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1383 default:
1384 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1385 }
1386}
1387
1389{
1390 return valueAsString();
1391}
1392
1394{
1395 return QSet<QString>();
1396}
1397
1399{
1400 return QSet<QString>();
1401}
1402
1404{
1405 return QSet<QString>();
1406}
1407
1408QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1409{
1410 QList<const QgsExpressionNode *> lst;
1411 lst << this;
1412 return lst;
1413}
1414
1416{
1417 return false;
1418}
1419
1421{
1423 cloneTo( copy );
1424 return copy;
1425}
1426
1428{
1429 Q_UNUSED( context )
1430 Q_UNUSED( parent )
1431 return true;
1432}
1433
1434//
1435
1437{
1438 Q_UNUSED( parent )
1439 int index = mIndex;
1440
1441 if ( index < 0 )
1442 {
1443 // have not yet found field index - first check explicitly set fields collection
1444 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1445 {
1446 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1447 index = fields.lookupField( mName );
1448 }
1449 }
1450
1451 if ( context )
1452 {
1453 QgsFeature feature = context->feature();
1454 if ( feature.isValid() )
1455 {
1456 if ( index >= 0 )
1457 return feature.attribute( index );
1458 else
1459 return feature.attribute( mName );
1460 }
1461 else
1462 {
1463 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1464 }
1465 }
1466 if ( index < 0 )
1467 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1468 return QVariant();
1469}
1470
1475
1477{
1478 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1479 return false;
1480
1481 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1482
1483 mIndex = fields.lookupField( mName );
1484
1485 if ( mIndex == -1 && context->hasFeature() )
1486 {
1487 mIndex = context->feature().fieldNameIndex( mName );
1488 }
1489
1490 if ( mIndex == -1 )
1491 {
1492 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1493 return false;
1494 }
1495 return true;
1496}
1497
1499{
1500 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" ) );
1501 const QRegularExpressionMatch match = re.match( mName );
1502 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1503}
1504
1506{
1507 return QSet<QString>() << mName;
1508}
1509
1511{
1512 return QSet<QString>();
1513}
1514
1516{
1517 return QSet<QString>();
1518}
1519
1520QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1521{
1522 QList<const QgsExpressionNode *> result;
1523 result << this;
1524 return result;
1525}
1526
1528{
1529 return false;
1530}
1531
1533{
1535 cloneTo( copy );
1536 return copy;
1537}
1538
1540{
1541 Q_UNUSED( context )
1542 Q_UNUSED( parent )
1543 return false;
1544}
1545
1546//
1547
1549 : mConditions( *conditions )
1550 , mElseExp( elseExp )
1551{
1552 delete conditions;
1553}
1554
1556{
1557 delete mElseExp;
1558 qDeleteAll( mConditions );
1559}
1560
1565
1567{
1568 for ( WhenThen *cond : std::as_const( mConditions ) )
1569 {
1570 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1571 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1573 if ( tvl == QgsExpressionUtils::True )
1574 {
1575 QVariant vRes = cond->mThenExp->eval( parent, context );
1577 return vRes;
1578 }
1579 }
1580
1581 if ( mElseExp )
1582 {
1583 QVariant vElse = mElseExp->eval( parent, context );
1585 return vElse;
1586 }
1587
1588 // return NULL if no condition is matching
1589 return QVariant();
1590}
1591
1593{
1594 bool foundAnyNonStaticConditions = false;
1595 for ( WhenThen *cond : std::as_const( mConditions ) )
1596 {
1597 const bool res = cond->mWhenExp->prepare( parent, context )
1598 && cond->mThenExp->prepare( parent, context );
1599 if ( !res )
1600 return false;
1601
1602 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1603 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1604 {
1605 // 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
1606 // value, and the static value for this WHEN clause is True.
1607 if ( cond->mThenExp->hasCachedStaticValue() )
1608 {
1609 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1610 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1611 mHasCachedValue = true;
1612 return true;
1613 }
1614 else
1615 {
1616 // 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
1617 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1618 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1619 return true;
1620 }
1621 }
1622 }
1623
1624 if ( mElseExp )
1625 {
1626 const bool res = mElseExp->prepare( parent, context );
1627 if ( !res )
1628 return false;
1629
1630 if ( !foundAnyNonStaticConditions )
1631 {
1632 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1633 if ( mElseExp->hasCachedStaticValue() )
1634 {
1636 mHasCachedValue = true;
1637 return true;
1638 }
1639 else
1640 {
1641 // so even though the ELSE node is non-static we can effectively replace
1642 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1643 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1644 return true;
1645 }
1646 }
1647 }
1648
1649 return true;
1650}
1651
1653{
1654 QString msg( QStringLiteral( "CASE" ) );
1655 for ( WhenThen *cond : mConditions )
1656 {
1657 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1658 }
1659 if ( mElseExp )
1660 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1661 msg += QLatin1String( " END" );
1662 return msg;
1663}
1664
1666{
1667 if ( hasCachedStaticValue() )
1668 return QSet< QString >();
1669
1670 QSet<QString> lst;
1671 for ( WhenThen *cond : mConditions )
1672 {
1673 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1674 }
1675
1676 if ( mElseExp )
1677 lst += mElseExp->referencedColumns();
1678
1679 return lst;
1680}
1681
1683{
1684 QSet<QString> lst;
1685 for ( WhenThen *cond : mConditions )
1686 {
1687 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1688 }
1689
1690 if ( mElseExp )
1691 lst += mElseExp->referencedVariables();
1692
1693 return lst;
1694}
1695
1697{
1698 QSet<QString> lst;
1699 for ( WhenThen *cond : mConditions )
1700 {
1701 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1702 }
1703
1704 if ( mElseExp )
1705 lst += mElseExp->referencedFunctions();
1706
1707 return lst;
1708}
1709
1710QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1711{
1712 QList<const QgsExpressionNode *> lst;
1713 lst << this;
1714 for ( WhenThen *cond : mConditions )
1715 {
1716 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1717 }
1718
1719 if ( mElseExp )
1720 lst += mElseExp->nodes();
1721
1722 return lst;
1723}
1724
1726{
1727 for ( WhenThen *cond : mConditions )
1728 {
1729 if ( cond->mWhenExp->needsGeometry() ||
1730 cond->mThenExp->needsGeometry() )
1731 return true;
1732 }
1733
1734 return mElseExp && mElseExp->needsGeometry();
1735}
1736
1738{
1740 conditions.reserve( mConditions.size() );
1741 for ( WhenThen *wt : mConditions )
1742 conditions.append( wt->clone() );
1743
1744 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1745 cloneTo( copy );
1746 return copy;
1747}
1748
1750{
1751 for ( WhenThen *wt : mConditions )
1752 {
1753 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1754 return false;
1755 }
1756
1757 if ( mElseExp )
1758 return mElseExp->isStatic( parent, context );
1759
1760 return true;
1761}
1762
1764{
1765 if ( hasCachedStaticValue() )
1766 return QSet< QString >();
1767
1768 QSet<QString> lst( mNode->referencedColumns() );
1769 const QList< QgsExpressionNode * > nodeList = mList->list();
1770 for ( const QgsExpressionNode *n : nodeList )
1771 lst.unite( n->referencedColumns() );
1772 return lst;
1773}
1774
1776{
1777 QSet<QString> lst( mNode->referencedVariables() );
1778 const QList< QgsExpressionNode * > nodeList = mList->list();
1779 for ( const QgsExpressionNode *n : nodeList )
1780 lst.unite( n->referencedVariables() );
1781 return lst;
1782}
1783
1785{
1786 QSet<QString> lst( mNode->referencedFunctions() );
1787 const QList< QgsExpressionNode * > nodeList = mList->list();
1788 for ( const QgsExpressionNode *n : nodeList )
1789 lst.unite( n->referencedFunctions() );
1790 return lst;
1791}
1792
1793QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1794{
1795 QList<const QgsExpressionNode *> lst;
1796 lst << this;
1797 const QList< QgsExpressionNode * > nodeList = mList->list();
1798 for ( const QgsExpressionNode *n : nodeList )
1799 lst += n->nodes();
1800 return lst;
1801}
1802
1803
1805{
1806 delete mNode;
1807 delete mLowerBound;
1808 delete mHigherBound;
1809}
1810
1815
1817{
1818 bool res = mNode->prepare( parent, context );
1819 res = res && mLowerBound->prepare( parent, context );
1820 res = res && mHigherBound->prepare( parent, context );
1821 return res;
1822}
1823
1825{
1826 const QVariant nodeVal = mNode->eval( parent, context );
1827 if ( QgsVariantUtils::isNull( nodeVal ) )
1828 {
1829 return QVariant();
1830 }
1831
1832 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1833
1835 const QVariant lowBoundValue = lowBound.eval( parent, context );
1836 const bool lowBoundBool { lowBoundValue.toBool() };
1837
1838 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
1839 {
1840 return QVariant( mNegate );
1841 }
1842
1844 const QVariant highBoundValue = highBound.eval( parent, context );
1845
1846 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
1847 {
1848 return QVariant();
1849 }
1850
1851 const bool highBoundBool { highBoundValue.toBool() };
1852
1853 // We already checked if both are nulls
1854 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
1855 {
1856
1857 // In this case we can return a boolean
1858 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
1859 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
1860 {
1861 return QVariant( mNegate );
1862 }
1863
1864 // Indetermined
1865 return QVariant();
1866
1867 }
1868
1869 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
1870 {
1871 return QVariant( mNegate );
1872 }
1873
1874 const bool res { lowBoundBool &&highBoundBool };
1875 return mNegate ? QVariant( ! res ) : QVariant( res );
1876
1877}
1878
1880{
1881 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
1882}
1883
1885{
1886 QSet<QString> lst( mNode->referencedVariables() );
1887 lst.unite( mLowerBound->referencedVariables() );
1888 lst.unite( mHigherBound->referencedVariables() );
1889 return lst;
1890}
1891
1893{
1894 QSet<QString> lst( mNode->referencedFunctions() );
1895 lst.unite( mLowerBound->referencedFunctions() );
1896 lst.unite( mHigherBound->referencedFunctions() );
1897 return lst;
1898}
1899
1900QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
1901{
1902 return { this, mLowerBound, mHigherBound };
1903}
1904
1906{
1907 QSet<QString> lst( mNode->referencedColumns() );
1908 lst.unite( mLowerBound->referencedColumns() );
1909 lst.unite( mHigherBound->referencedColumns() );
1910 return lst;
1911}
1912
1914{
1915 if ( mNode->needsGeometry() )
1916 return true;
1917
1918 if ( mLowerBound->needsGeometry() )
1919 return true;
1920
1921 if ( mHigherBound->needsGeometry() )
1922 return true;
1923
1924 return false;
1925}
1926
1928{
1929 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
1930 cloneTo( copy );
1931 return copy;
1932}
1933
1935{
1936 if ( !mNode->isStatic( parent, context ) )
1937 return false;
1938
1939 if ( !mLowerBound->isStatic( parent, context ) )
1940 return false;
1941
1942 if ( !mHigherBound->isStatic( parent, context ) )
1943 return false;
1944
1945 return true;
1946}
1947
1949{
1950 return mLowerBound;
1951}
1952
1954{
1955 return mHigherBound;
1956}
1957
1959{
1960 return mNegate;
1961}
1962
1964 : mWhenExp( whenExp )
1965 , mThenExp( thenExp )
1966{
1967}
1968
1970{
1971 delete mWhenExp;
1972 delete mThenExp;
1973}
1974
1976{
1977 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1978}
1979
1981{
1982 return BINARY_OPERATOR_TEXT[mOp];
1983}
1984
1985//
1986
1988{
1989 const QVariant container = mContainer->eval( parent, context );
1991 const QVariant index = mIndex->eval( parent, context );
1993
1994 switch ( container.type() )
1995 {
1996 case QVariant::Map:
1997 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1998
1999 case QVariant::List:
2000 case QVariant::StringList:
2001 {
2002 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2003 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2004 if ( pos >= list.length() || pos < -list.length() )
2005 {
2006 return QVariant();
2007 }
2008 if ( pos < 0 )
2009 {
2010 // negative indices are from back of list
2011 pos += list.length();
2012 }
2013
2014 return list.at( pos );
2015 }
2016
2017 default:
2018 if ( !QgsVariantUtils::isNull( container ) )
2019 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
2020 return QVariant();
2021 }
2022}
2023
2028
2030{
2031 bool resC = mContainer->prepare( parent, context );
2032 bool resV = mIndex->prepare( parent, context );
2033 return resC && resV;
2034}
2035
2037{
2038 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2039}
2040
2042{
2043 if ( hasCachedStaticValue() )
2044 return QSet< QString >();
2045
2046 return mContainer->referencedColumns() + mIndex->referencedColumns();
2047}
2048
2050{
2051 return mContainer->referencedVariables() + mIndex->referencedVariables();
2052}
2053
2055{
2056 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2057}
2058
2059QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2060{
2061 QList<const QgsExpressionNode *> lst;
2062 lst << this;
2063 lst += mContainer->nodes() + mIndex->nodes();
2064 return lst;
2065}
2066
2068{
2069 return mContainer->needsGeometry() || mIndex->needsGeometry();
2070}
2071
2073{
2074 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2075 cloneTo( copy );
2076 return copy;
2077}
2078
2080{
2081 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2082}
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.
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.
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.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
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.
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.
bool isValid() const
Returns the validity of this feature.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
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.
A representation of the interval between two datetime values.
Definition qgsinterval.h:42
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)
Returns true if the specified variant should be considered a NULL value.
#define str(x)
Definition qgis.cpp:37
#define FALLTHROUGH
Definition qgis.h:3088
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:2527
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.