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