QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 <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
135{
136 return ntUnaryOperator;
137}
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
676{
677 return ntBinaryOperator;
678}
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
1011{
1012 return ntInOperator;
1013}
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
1118{
1119 delete mArgs;
1120}
1121
1123{
1124 return ntFunction;
1125}
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
1348{
1349 return ntLiteral;
1350}
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::Bool:
1376 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1377 default:
1378 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1379 }
1380}
1381
1383{
1384 return valueAsString();
1385}
1386
1388{
1389 return QSet<QString>();
1390}
1391
1393{
1394 return QSet<QString>();
1395}
1396
1398{
1399 return QSet<QString>();
1400}
1401
1402QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1403{
1404 QList<const QgsExpressionNode *> lst;
1405 lst << this;
1406 return lst;
1407}
1408
1410{
1411 return false;
1412}
1413
1415{
1417 cloneTo( copy );
1418 return copy;
1419}
1420
1422{
1423 Q_UNUSED( context )
1424 Q_UNUSED( parent )
1425 return true;
1426}
1427
1428//
1429
1431{
1432 Q_UNUSED( parent )
1433 int index = mIndex;
1434
1435 if ( index < 0 )
1436 {
1437 // have not yet found field index - first check explicitly set fields collection
1438 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1439 {
1440 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1441 index = fields.lookupField( mName );
1442 }
1443 }
1444
1445 if ( context )
1446 {
1447 QgsFeature feature = context->feature();
1448 if ( feature.isValid() )
1449 {
1450 if ( index >= 0 )
1451 return feature.attribute( index );
1452 else
1453 return feature.attribute( mName );
1454 }
1455 else
1456 {
1457 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1458 }
1459 }
1460 if ( index < 0 )
1461 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1462 return QVariant();
1463}
1464
1466{
1467 return ntColumnRef;
1468}
1469
1471{
1472 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1473 return false;
1474
1475 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1476
1477 mIndex = fields.lookupField( mName );
1478
1479 if ( mIndex == -1 && context->hasFeature() )
1480 {
1481 mIndex = context->feature().fieldNameIndex( mName );
1482 }
1483
1484 if ( mIndex == -1 )
1485 {
1486 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1487 return false;
1488 }
1489 return true;
1490}
1491
1493{
1494 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
1495 const QRegularExpressionMatch match = re.match( mName );
1496 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1497}
1498
1500{
1501 return QSet<QString>() << mName;
1502}
1503
1505{
1506 return QSet<QString>();
1507}
1508
1510{
1511 return QSet<QString>();
1512}
1513
1514QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1515{
1516 QList<const QgsExpressionNode *> result;
1517 result << this;
1518 return result;
1519}
1520
1522{
1523 return false;
1524}
1525
1527{
1529 cloneTo( copy );
1530 return copy;
1531}
1532
1534{
1535 Q_UNUSED( context )
1536 Q_UNUSED( parent )
1537 return false;
1538}
1539
1540//
1541
1543 : mConditions( *conditions )
1544 , mElseExp( elseExp )
1545{
1546 delete conditions;
1547}
1548
1550{
1551 delete mElseExp;
1552 qDeleteAll( mConditions );
1553}
1554
1556{
1557 return ntCondition;
1558}
1559
1561{
1562 for ( WhenThen *cond : std::as_const( mConditions ) )
1563 {
1564 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1565 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1567 if ( tvl == QgsExpressionUtils::True )
1568 {
1569 QVariant vRes = cond->mThenExp->eval( parent, context );
1571 return vRes;
1572 }
1573 }
1574
1575 if ( mElseExp )
1576 {
1577 QVariant vElse = mElseExp->eval( parent, context );
1579 return vElse;
1580 }
1581
1582 // return NULL if no condition is matching
1583 return QVariant();
1584}
1585
1587{
1588 bool foundAnyNonStaticConditions = false;
1589 for ( WhenThen *cond : std::as_const( mConditions ) )
1590 {
1591 const bool res = cond->mWhenExp->prepare( parent, context )
1592 && cond->mThenExp->prepare( parent, context );
1593 if ( !res )
1594 return false;
1595
1596 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1597 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1598 {
1599 // 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
1600 // value, and the static value for this WHEN clause is True.
1601 if ( cond->mThenExp->hasCachedStaticValue() )
1602 {
1603 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1604 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1605 mHasCachedValue = true;
1606 return true;
1607 }
1608 else
1609 {
1610 // 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
1611 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1612 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1613 return true;
1614 }
1615 }
1616 }
1617
1618 if ( mElseExp )
1619 {
1620 const bool res = mElseExp->prepare( parent, context );
1621 if ( !res )
1622 return false;
1623
1624 if ( !foundAnyNonStaticConditions )
1625 {
1626 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1627 if ( mElseExp->hasCachedStaticValue() )
1628 {
1630 mHasCachedValue = true;
1631 return true;
1632 }
1633 else
1634 {
1635 // so even though the ELSE node is non-static we can effectively replace
1636 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1637 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1638 return true;
1639 }
1640 }
1641 }
1642
1643 return true;
1644}
1645
1647{
1648 QString msg( QStringLiteral( "CASE" ) );
1649 for ( WhenThen *cond : mConditions )
1650 {
1651 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1652 }
1653 if ( mElseExp )
1654 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1655 msg += QLatin1String( " END" );
1656 return msg;
1657}
1658
1660{
1661 if ( hasCachedStaticValue() )
1662 return QSet< QString >();
1663
1664 QSet<QString> lst;
1665 for ( WhenThen *cond : mConditions )
1666 {
1667 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1668 }
1669
1670 if ( mElseExp )
1671 lst += mElseExp->referencedColumns();
1672
1673 return lst;
1674}
1675
1677{
1678 QSet<QString> lst;
1679 for ( WhenThen *cond : mConditions )
1680 {
1681 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1682 }
1683
1684 if ( mElseExp )
1685 lst += mElseExp->referencedVariables();
1686
1687 return lst;
1688}
1689
1691{
1692 QSet<QString> lst;
1693 for ( WhenThen *cond : mConditions )
1694 {
1695 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1696 }
1697
1698 if ( mElseExp )
1699 lst += mElseExp->referencedFunctions();
1700
1701 return lst;
1702}
1703
1704QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1705{
1706 QList<const QgsExpressionNode *> lst;
1707 lst << this;
1708 for ( WhenThen *cond : mConditions )
1709 {
1710 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1711 }
1712
1713 if ( mElseExp )
1714 lst += mElseExp->nodes();
1715
1716 return lst;
1717}
1718
1720{
1721 for ( WhenThen *cond : mConditions )
1722 {
1723 if ( cond->mWhenExp->needsGeometry() ||
1724 cond->mThenExp->needsGeometry() )
1725 return true;
1726 }
1727
1728 return mElseExp && mElseExp->needsGeometry();
1729}
1730
1732{
1734 conditions.reserve( mConditions.size() );
1735 for ( WhenThen *wt : mConditions )
1736 conditions.append( wt->clone() );
1737
1738 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1739 cloneTo( copy );
1740 return copy;
1741}
1742
1744{
1745 for ( WhenThen *wt : mConditions )
1746 {
1747 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1748 return false;
1749 }
1750
1751 if ( mElseExp )
1752 return mElseExp->isStatic( parent, context );
1753
1754 return true;
1755}
1756
1758{
1759 if ( hasCachedStaticValue() )
1760 return QSet< QString >();
1761
1762 QSet<QString> lst( mNode->referencedColumns() );
1763 const QList< QgsExpressionNode * > nodeList = mList->list();
1764 for ( const QgsExpressionNode *n : nodeList )
1765 lst.unite( n->referencedColumns() );
1766 return lst;
1767}
1768
1770{
1771 QSet<QString> lst( mNode->referencedVariables() );
1772 const QList< QgsExpressionNode * > nodeList = mList->list();
1773 for ( const QgsExpressionNode *n : nodeList )
1774 lst.unite( n->referencedVariables() );
1775 return lst;
1776}
1777
1779{
1780 QSet<QString> lst( mNode->referencedFunctions() );
1781 const QList< QgsExpressionNode * > nodeList = mList->list();
1782 for ( const QgsExpressionNode *n : nodeList )
1783 lst.unite( n->referencedFunctions() );
1784 return lst;
1785}
1786
1787QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1788{
1789 QList<const QgsExpressionNode *> lst;
1790 lst << this;
1791 const QList< QgsExpressionNode * > nodeList = mList->list();
1792 for ( const QgsExpressionNode *n : nodeList )
1793 lst += n->nodes();
1794 return lst;
1795}
1796
1797
1799{
1800 delete mNode;
1801 delete mLowerBound;
1802 delete mHigherBound;
1803}
1804
1806{
1807 return ntBetweenOperator;
1808}
1809
1811{
1812 bool res = mNode->prepare( parent, context );
1813 res = res && mLowerBound->prepare( parent, context );
1814 res = res && mHigherBound->prepare( parent, context );
1815 return res;
1816}
1817
1819{
1820 const QVariant nodeVal = mNode->eval( parent, context );
1821 if ( QgsVariantUtils::isNull( nodeVal ) )
1822 {
1823 return QVariant();
1824 }
1825
1826 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1827
1828 QgsExpressionNodeBinaryOperator lowBound { QgsExpressionNodeBinaryOperator::BinaryOperator::boGE, nodeValNode.clone(), mLowerBound->clone() };
1829 const QVariant lowBoundValue = lowBound.eval( parent, context );
1830 const bool lowBoundBool { lowBoundValue.toBool() };
1831
1832 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
1833 {
1834 return QVariant( mNegate );
1835 }
1836
1837 QgsExpressionNodeBinaryOperator highBound { QgsExpressionNodeBinaryOperator::BinaryOperator::boLE, nodeValNode.clone(), mHigherBound->clone() };
1838 const QVariant highBoundValue = highBound.eval( parent, context );
1839
1840 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
1841 {
1842 return QVariant();
1843 }
1844
1845 const bool highBoundBool { highBoundValue.toBool() };
1846
1847 // We already checked if both are nulls
1848 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
1849 {
1850
1851 // In this case we can return a boolean
1852 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
1853 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
1854 {
1855 return QVariant( mNegate );
1856 }
1857
1858 // Indetermined
1859 return QVariant();
1860
1861 }
1862
1863 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
1864 {
1865 return QVariant( mNegate );
1866 }
1867
1868 const bool res { lowBoundBool &&highBoundBool };
1869 return mNegate ? QVariant( ! res ) : QVariant( res );
1870
1871}
1872
1874{
1875 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
1876}
1877
1879{
1880 QSet<QString> lst( mNode->referencedVariables() );
1881 lst.unite( mLowerBound->referencedVariables() );
1882 lst.unite( mHigherBound->referencedVariables() );
1883 return lst;
1884}
1885
1887{
1888 QSet<QString> lst( mNode->referencedFunctions() );
1889 lst.unite( mLowerBound->referencedFunctions() );
1890 lst.unite( mHigherBound->referencedFunctions() );
1891 return lst;
1892}
1893
1894QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
1895{
1896 return { this, mLowerBound, mHigherBound };
1897}
1898
1900{
1901 QSet<QString> lst( mNode->referencedColumns() );
1902 lst.unite( mLowerBound->referencedColumns() );
1903 lst.unite( mHigherBound->referencedColumns() );
1904 return lst;
1905}
1906
1908{
1909 if ( mNode->needsGeometry() )
1910 return true;
1911
1912 if ( mLowerBound->needsGeometry() )
1913 return true;
1914
1915 if ( mHigherBound->needsGeometry() )
1916 return true;
1917
1918 return false;
1919}
1920
1922{
1923 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
1924 cloneTo( copy );
1925 return copy;
1926}
1927
1929{
1930 if ( !mNode->isStatic( parent, context ) )
1931 return false;
1932
1933 if ( !mLowerBound->isStatic( parent, context ) )
1934 return false;
1935
1936 if ( !mHigherBound->isStatic( parent, context ) )
1937 return false;
1938
1939 return true;
1940}
1941
1943{
1944 return mLowerBound;
1945}
1946
1948{
1949 return mHigherBound;
1950}
1951
1953{
1954 return mNegate;
1955}
1956
1958 : mWhenExp( whenExp )
1959 , mThenExp( thenExp )
1960{
1961}
1962
1964{
1965 delete mWhenExp;
1966 delete mThenExp;
1967}
1968
1970{
1971 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1972}
1973
1975{
1976 return BINARY_OPERATOR_TEXT[mOp];
1977}
1978
1979//
1980
1982{
1983 const QVariant container = mContainer->eval( parent, context );
1985 const QVariant index = mIndex->eval( parent, context );
1987
1988 switch ( container.type() )
1989 {
1990 case QVariant::Map:
1991 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1992
1993 case QVariant::List:
1994 case QVariant::StringList:
1995 {
1996 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
1997 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
1998 if ( pos >= list.length() || pos < -list.length() )
1999 {
2000 return QVariant();
2001 }
2002 if ( pos < 0 )
2003 {
2004 // negative indices are from back of list
2005 pos += list.length();
2006 }
2007
2008 return list.at( pos );
2009 }
2010
2011 default:
2012 if ( !QgsVariantUtils::isNull( container ) )
2013 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
2014 return QVariant();
2015 }
2016}
2017
2019{
2020 return ntIndexOperator;
2021}
2022
2024{
2025 bool resC = mContainer->prepare( parent, context );
2026 bool resV = mIndex->prepare( parent, context );
2027 return resC && resV;
2028}
2029
2031{
2032 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2033}
2034
2036{
2037 if ( hasCachedStaticValue() )
2038 return QSet< QString >();
2039
2040 return mContainer->referencedColumns() + mIndex->referencedColumns();
2041}
2042
2044{
2045 return mContainer->referencedVariables() + mIndex->referencedVariables();
2046}
2047
2049{
2050 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2051}
2052
2053QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2054{
2055 QList<const QgsExpressionNode *> lst;
2056 lst << this;
2057 lst += mContainer->nodes() + mIndex->nodes();
2058 return lst;
2059}
2060
2062{
2063 return mContainer->needsGeometry() || mIndex->needsGeometry();
2064}
2065
2067{
2068 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2069 cloneTo( copy );
2070 return copy;
2071}
2072
2074{
2075 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2076}
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:349
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:236
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)
const QString & typeName
QgsExpressionNode * node
Node.