QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
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.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
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.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) ||
270 ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
271 {
272 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
274 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
276 QDateTime dt = QDateTime( date, time );
277 return QVariant( dt );
278 }
279 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
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.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
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.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
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.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
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.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
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.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
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.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) &&
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
475 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
476 {
477 // if one of value is boolean, then the other must also be boolean,
478 // in order to avoid confusion between different expression evaluations
479 // amongst providers and QVariant, that can consider or not the string
480 // 'false' as boolean or text
481 if ( vL.userType() == QMetaType::Type::Bool && vR.userType() == QMetaType::Type::Bool )
482 return vL.toBool() == vR.toBool() ? TVL_True : TVL_False;
483 return TVL_False;
484 }
485
486 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
487 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
488 {
489 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
491 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
493 return compare( fL - fR ) ? TVL_True : TVL_False;
494 }
495 else
496 {
497 // do string comparison otherwise
498 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
500 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
502 int diff = QString::compare( sL, sR );
503 return compare( diff ) ? TVL_True : TVL_False;
504 }
505
506 case boIs:
507 case boIsNot:
508 if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
509 return ( mOp == boIs ? TVL_True : TVL_False );
510 else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
511 return ( mOp == boIs ? TVL_False : TVL_True );
512 else // both operators non-null
513 {
514 bool equal = false;
515 if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
516 ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) )
517 {
518 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
520 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
522 equal = qgsDoubleNear( fL, fR );
523 }
524 else
525 {
526 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
528 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
530 equal = QString::compare( sL, sR ) == 0;
531 }
532 if ( equal )
533 return mOp == boIs ? TVL_True : TVL_False;
534 else
535 return mOp == boIs ? TVL_False : TVL_True;
536 }
537
538 case boRegexp:
539 case boLike:
540 case boNotLike:
541 case boILike:
542 case boNotILike:
543 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
544 return TVL_Unknown;
545 else
546 {
547 QString str = QgsExpressionUtils::getStringValue( vL, parent );
549 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
551 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
552 bool matches;
553 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
554 {
555 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
556 // manage escape % and _
557 if ( esc_regexp.startsWith( '%' ) )
558 {
559 esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
560 }
561 const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
562 int pos = 0;
563 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
564 {
565 esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
566 pos += 1;
567 }
568 const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
569 esc_regexp.replace( rx2, QStringLiteral( "%" ) );
570 if ( esc_regexp.startsWith( '_' ) )
571 {
572 esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
573 }
574 const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
575 pos = 0;
576 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
577 {
578 esc_regexp.replace( pos + 1, 1, '.' );
579 pos += 1;
580 }
581 esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
582
583 matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
584 }
585 else
586 {
587 matches = QRegularExpression( regexp ).match( str ).hasMatch();
588 }
589
590 if ( mOp == boNotLike || mOp == boNotILike )
591 {
592 matches = !matches;
593 }
594
595 return matches ? TVL_True : TVL_False;
596 }
597
598 case boConcat:
599 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
600 return QVariant();
601 else
602 {
603 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
605 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
607 return QVariant( sL + sR );
608 }
609 }
610 Q_ASSERT( false );
611 return QVariant();
612}
613
614bool QgsExpressionNodeBinaryOperator::compare( double diff )
615{
616 switch ( mOp )
617 {
618 case boEQ:
619 return qgsDoubleNear( diff, 0.0 );
620 case boNE:
621 return !qgsDoubleNear( diff, 0.0 );
622 case boLT:
623 return diff < 0;
624 case boGT:
625 return diff > 0;
626 case boLE:
627 return diff <= 0;
628 case boGE:
629 return diff >= 0;
630 default:
631 Q_ASSERT( false );
632 return false;
633 }
634}
635
636qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
637{
638 switch ( mOp )
639 {
640 case boPlus:
641 return x + y;
642 case boMinus:
643 return x - y;
644 case boMul:
645 return x * y;
646 case boDiv:
647 return x / y;
648 case boMod:
649 return x % y;
650 default:
651 Q_ASSERT( false );
652 return 0;
653 }
654}
655
656QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
657{
658 switch ( mOp )
659 {
660 case boPlus:
661 return d.addSecs( i->seconds() );
662 case boMinus:
663 return d.addSecs( -i->seconds() );
664 default:
665 Q_ASSERT( false );
666 return QDateTime();
667 }
668}
669
670double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
671{
672 switch ( mOp )
673 {
674 case boPlus:
675 return x + y;
676 case boMinus:
677 return x - y;
678 case boMul:
679 return x * y;
680 case boDiv:
681 return x / y;
682 case boMod:
683 return std::fmod( x, y );
684 default:
685 Q_ASSERT( false );
686 return 0;
687 }
688}
689
694
696{
697 bool resL = mOpLeft->prepare( parent, context );
698 bool resR = mOpRight->prepare( parent, context );
699 return resL && resR;
700}
701
703{
704 // see left/right in qgsexpressionparser.yy
705 switch ( mOp )
706 {
707 case boOr:
708 return 1;
709
710 case boAnd:
711 return 2;
712
713 case boEQ:
714 case boNE:
715 case boLE:
716 case boGE:
717 case boLT:
718 case boGT:
719 case boRegexp:
720 case boLike:
721 case boILike:
722 case boNotLike:
723 case boNotILike:
724 case boIs:
725 case boIsNot:
726 return 3;
727
728 case boPlus:
729 case boMinus:
730 return 4;
731
732 case boMul:
733 case boDiv:
734 case boIntDiv:
735 case boMod:
736 return 5;
737
738 case boPow:
739 return 6;
740
741 case boConcat:
742 return 7;
743 }
744 Q_ASSERT( false && "unexpected binary operator" );
745 return -1;
746}
747
749{
750 // see left/right in qgsexpressionparser.yy
751 switch ( mOp )
752 {
753 case boOr:
754 case boAnd:
755 case boEQ:
756 case boNE:
757 case boLE:
758 case boGE:
759 case boLT:
760 case boGT:
761 case boRegexp:
762 case boLike:
763 case boILike:
764 case boNotLike:
765 case boNotILike:
766 case boIs:
767 case boIsNot:
768 case boPlus:
769 case boMinus:
770 case boMul:
771 case boDiv:
772 case boIntDiv:
773 case boMod:
774 case boConcat:
775 return true;
776
777 case boPow:
778 return false;
779 }
780 Q_ASSERT( false && "unexpected binary operator" );
781 return false;
782}
783
785{
787 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
788 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
789
790 QString rdump( mOpRight->dump() );
791
792 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
793 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
794 {
795 rdump.prepend( '(' ).append( ')' );
796 }
797
798 QString fmt;
799 if ( leftAssociative() )
800 {
801 fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
802 fmt += QLatin1String( " %2 " );
803 fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
804 }
805 else
806 {
807 fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
808 fmt += QLatin1String( " %2 " );
809 fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
810 }
811
812 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
813}
814
816{
817 if ( hasCachedStaticValue() )
818 return QSet< QString >();
819
820 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
821}
822
824{
825 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
826}
827
829{
830 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
831}
832
833QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
834{
835 QList<const QgsExpressionNode *> lst;
836 lst << this;
837 lst += mOpLeft->nodes() + mOpRight->nodes();
838 return lst;
839}
840
842{
843 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
844}
845
847{
848 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
849 cloneTo( copy );
850 return copy;
851}
852
854{
855 const bool leftStatic = mOpLeft->isStatic( parent, context );
856 const bool rightStatic = mOpRight->isStatic( parent, context );
857
858 if ( leftStatic && rightStatic )
859 return true;
860
861 // special logic for certain ops...
862 switch ( mOp )
863 {
865 {
866 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
867 // of the value of the other node!
868 if ( leftStatic )
869 {
870 mOpLeft->prepare( parent, context );
871 if ( mOpLeft->hasCachedStaticValue() )
872 {
873 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
874 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
875 {
876 mCachedStaticValue = true;
877 mHasCachedValue = true;
878 return true;
879 }
880 }
881 }
882 else if ( rightStatic )
883 {
884 mOpRight->prepare( parent, context );
885 if ( mOpRight->hasCachedStaticValue() )
886 {
887 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
888 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
889 {
890 mCachedStaticValue = true;
891 mHasCachedValue = true;
892 return true;
893 }
894 }
895 }
896
897 break;
898 }
900 {
901 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
902 // of the value of the other node!
903
904 if ( leftStatic )
905 {
906 mOpLeft->prepare( parent, context );
907 if ( mOpLeft->hasCachedStaticValue() )
908 {
909 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
910 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
911 {
912 mCachedStaticValue = false;
913 mHasCachedValue = true;
914 return true;
915 }
916 }
917 }
918 else if ( rightStatic )
919 {
920 mOpRight->prepare( parent, context );
921 if ( mOpRight->hasCachedStaticValue() )
922 {
923 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
924 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
925 {
926 mCachedStaticValue = false;
927 mHasCachedValue = true;
928 return true;
929 }
930 }
931 }
932
933 break;
934 }
935
957 break;
958 }
959
960 return false;
961}
962
963//
964
966{
967 if ( mList->count() == 0 )
968 return mNotIn ? TVL_True : TVL_False;
969 QVariant v1 = mNode->eval( parent, context );
971 if ( QgsExpressionUtils::isNull( v1 ) )
972 return TVL_Unknown;
973
974 bool listHasNull = false;
975
976 const QList< QgsExpressionNode * > nodeList = mList->list();
977 for ( QgsExpressionNode *n : nodeList )
978 {
979 QVariant v2 = n->eval( parent, context );
981 if ( QgsExpressionUtils::isNull( v2 ) )
982 listHasNull = true;
983 else
984 {
985 bool equal = false;
986 // check whether they are equal
987 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) &&
988 QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
989 {
990 // do numeric comparison if both operators can be converted to numbers,
991 // and they aren't both string
992 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
994 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
996 equal = qgsDoubleNear( f1, f2 );
997 }
998 else
999 {
1000 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1002 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1004 equal = QString::compare( s1, s2 ) == 0;
1005 }
1006
1007 if ( equal ) // we know the result
1008 return mNotIn ? TVL_False : TVL_True;
1009 }
1010 }
1011
1012 // item not found
1013 if ( listHasNull )
1014 return TVL_Unknown;
1015 else
1016 return mNotIn ? TVL_True : TVL_False;
1017}
1018
1020{
1021 delete mNode;
1022 delete mList;
1023}
1024
1029
1031{
1032 bool res = mNode->prepare( parent, context );
1033 const QList< QgsExpressionNode * > nodeList = mList->list();
1034 for ( QgsExpressionNode *n : nodeList )
1035 {
1036 res = res && n->prepare( parent, context );
1037 }
1038 return res;
1039}
1040
1042{
1043 return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1044}
1045
1047{
1048 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1049 cloneTo( copy );
1050 return copy;
1051}
1052
1054{
1055 if ( !mNode->isStatic( parent, context ) )
1056 return false;
1057
1058 const QList< QgsExpressionNode * > nodeList = mList->list();
1059 for ( QgsExpressionNode *n : nodeList )
1060 {
1061 if ( !n->isStatic( parent, context ) )
1062 return false;
1063 }
1064
1065 return true;
1066}
1067
1068//
1069
1071{
1072 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1073 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1074
1075 QVariant res = fd->run( mArgs, context, parent, this );
1077
1078 // everything went fine
1079 return res;
1080}
1081
1083 : mFnIndex( fnIndex )
1084{
1085 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1086 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1087 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1088 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1089
1090 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1091 const int functionParamsSize = functionParams.size();
1092 if ( functionParams.isEmpty() )
1093 {
1094 // function does not support parameters
1095 mArgs = args;
1096 }
1097 else if ( !args )
1098 {
1099 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1100 mArgs = new NodeList();
1101 mArgs->reserve( functionParamsSize );
1102 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1103 {
1104 // insert default value for QgsExpressionFunction::Parameter
1105 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1106 }
1107 }
1108 else
1109 {
1110 mArgs = new NodeList();
1111 mArgs->reserve( functionParamsSize );
1112
1113 int idx = 0;
1114 const QStringList argNames = args->names();
1115 const QList<QgsExpressionNode *> argList = args->list();
1116 //first loop through unnamed arguments
1117 {
1118 const int argNamesSize = argNames.size();
1119 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1120 {
1121 mArgs->append( argList.at( idx )->clone() );
1122 idx++;
1123 }
1124 }
1125
1126 //next copy named QgsExpressionFunction::Parameters in order expected by function
1127 for ( ; idx < functionParamsSize; ++idx )
1128 {
1129 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1130 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1131 if ( nodeIdx < 0 )
1132 {
1133 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1134 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1135 }
1136 else
1137 {
1138 mArgs->append( argList.at( nodeIdx )->clone() );
1139 }
1140 }
1141
1142 delete args;
1143 }
1144}
1145
1150
1155
1157{
1158 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1159
1160 bool res = fd->prepare( this, parent, context );
1161 if ( mArgs && !fd->lazyEval() )
1162 {
1163 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1164 for ( QgsExpressionNode *n : nodeList )
1165 {
1166 res = res && n->prepare( parent, context );
1167 }
1168 }
1169 return res;
1170}
1171
1173{
1174 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1175 if ( fd->params() == 0 )
1176 return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1177 else
1178 return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1179}
1180
1182{
1183 if ( hasCachedStaticValue() )
1184 return QSet< QString >();
1185
1186 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1187 QSet<QString> functionColumns = fd->referencedColumns( this );
1188
1189 if ( !mArgs )
1190 {
1191 //no referenced columns in arguments, just return function's referenced columns
1192 return functionColumns;
1193 }
1194
1195 int paramIndex = 0;
1196 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1197 for ( QgsExpressionNode *n : nodeList )
1198 {
1199 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1200 functionColumns.unite( n->referencedColumns() );
1201 paramIndex++;
1202 }
1203
1204 return functionColumns;
1205}
1206
1208{
1209 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1210 if ( fd->name() == QLatin1String( "var" ) )
1211 {
1212 if ( !mArgs->list().isEmpty() )
1213 {
1214 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1215 if ( var )
1216 return QSet<QString>() << var->value().toString();
1217 }
1218 return QSet<QString>() << QString();
1219 }
1220 else
1221 {
1222 QSet<QString> functionVariables = QSet<QString>();
1223
1224 if ( !mArgs )
1225 return functionVariables;
1226
1227 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1228 for ( QgsExpressionNode *n : nodeList )
1229 {
1230 functionVariables.unite( n->referencedVariables() );
1231 }
1232
1233 return functionVariables;
1234 }
1235}
1236
1238{
1239 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1240 QSet<QString> functions = QSet<QString>();
1241 functions.insert( fd->name() );
1242
1243 if ( !mArgs )
1244 return functions;
1245
1246 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1247 for ( QgsExpressionNode *n : nodeList )
1248 {
1249 functions.unite( n->referencedFunctions() );
1250 }
1251 return functions;
1252}
1253
1254QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1255{
1256 QList<const QgsExpressionNode *> lst;
1257 lst << this;
1258 if ( !mArgs )
1259 return lst;
1260
1261 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1262 for ( QgsExpressionNode *n : nodeList )
1263 {
1264 lst += n->nodes();
1265 }
1266 return lst;
1267}
1268
1270{
1271 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1272 if ( mArgs )
1273 {
1274 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1275 for ( QgsExpressionNode *n : nodeList )
1276 needs |= n->needsGeometry();
1277 }
1278 return needs;
1279}
1280
1282{
1283 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1284 cloneTo( copy );
1285 return copy;
1286}
1287
1289{
1290 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1291}
1292
1294{
1295 if ( !args || !args->hasNamedNodes() )
1296 return true;
1297
1298 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1299 if ( functionParams.isEmpty() )
1300 {
1301 error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1302 return false;
1303 }
1304 else
1305 {
1306 QSet< int > providedArgs;
1307 QSet< int > handledArgs;
1308 int idx = 0;
1309 //first loop through unnamed arguments
1310 while ( args->names().at( idx ).isEmpty() )
1311 {
1312 providedArgs << idx;
1313 handledArgs << idx;
1314 idx++;
1315 }
1316
1317 //next check named QgsExpressionFunction::Parameters
1318 for ( ; idx < functionParams.count(); ++idx )
1319 {
1320 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1321 if ( nodeIdx < 0 )
1322 {
1323 if ( !functionParams.at( idx ).optional() )
1324 {
1325 error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1326 return false;
1327 }
1328 }
1329 else
1330 {
1331 if ( providedArgs.contains( idx ) )
1332 {
1333 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1334 return false;
1335 }
1336 }
1337 providedArgs << idx;
1338 handledArgs << nodeIdx;
1339 }
1340
1341 //last check for bad names
1342 idx = 0;
1343 const QStringList nameList = args->names();
1344 for ( const QString &name : nameList )
1345 {
1346 if ( !name.isEmpty() && !functionParams.contains( name ) )
1347 {
1348 error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1349 return false;
1350 }
1351 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1352 {
1353 int functionIdx = functionParams.indexOf( name );
1354 if ( providedArgs.contains( functionIdx ) )
1355 {
1356 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1357 return false;
1358 }
1359 }
1360 idx++;
1361 }
1362
1363 }
1364 return true;
1365}
1366
1367//
1368
1370{
1371 Q_UNUSED( context )
1372 Q_UNUSED( parent )
1373 return mValue;
1374}
1375
1380
1382{
1383 Q_UNUSED( parent )
1384 Q_UNUSED( context )
1385 return true;
1386}
1387
1388
1390{
1391 if ( QgsVariantUtils::isNull( mValue ) )
1392 return QStringLiteral( "NULL" );
1393
1394 switch ( mValue.userType() )
1395 {
1396 case QMetaType::Type::Int:
1397 return QString::number( mValue.toInt() );
1398 case QMetaType::Type::Double:
1399 return QString::number( mValue.toDouble() );
1400 case QMetaType::Type::LongLong:
1401 return QString::number( mValue.toLongLong() );
1402 case QMetaType::Type::QString:
1403 return QgsExpression::quotedString( mValue.toString() );
1404 case QMetaType::Type::QTime:
1405 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1406 case QMetaType::Type::QDate:
1407 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1408 case QMetaType::Type::QDateTime:
1409 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1410 case QMetaType::Type::Bool:
1411 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1412 default:
1413 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1414 }
1415}
1416
1418{
1419 return valueAsString();
1420}
1421
1423{
1424 return QSet<QString>();
1425}
1426
1428{
1429 return QSet<QString>();
1430}
1431
1433{
1434 return QSet<QString>();
1435}
1436
1437QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1438{
1439 QList<const QgsExpressionNode *> lst;
1440 lst << this;
1441 return lst;
1442}
1443
1445{
1446 return false;
1447}
1448
1450{
1452 cloneTo( copy );
1453 return copy;
1454}
1455
1457{
1458 Q_UNUSED( context )
1459 Q_UNUSED( parent )
1460 return true;
1461}
1462
1463//
1464
1466{
1467 Q_UNUSED( parent )
1468 int index = mIndex;
1469
1470 if ( index < 0 )
1471 {
1472 // have not yet found field index - first check explicitly set fields collection
1473 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1474 {
1475 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1476 index = fields.lookupField( mName );
1477 }
1478 }
1479
1480 if ( context )
1481 {
1482 QgsFeature feature = context->feature();
1483 if ( feature.isValid() )
1484 {
1485 if ( index >= 0 )
1486 return feature.attribute( index );
1487 else
1488 return feature.attribute( mName );
1489 }
1490 else
1491 {
1492 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1493 }
1494 }
1495 if ( index < 0 )
1496 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1497 return QVariant();
1498}
1499
1504
1506{
1507 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1508 return false;
1509
1510 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1511
1512 mIndex = fields.lookupField( mName );
1513
1514 if ( mIndex == -1 && context->hasFeature() )
1515 {
1516 mIndex = context->feature().fieldNameIndex( mName );
1517 }
1518
1519 if ( mIndex == -1 )
1520 {
1521 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1522 return false;
1523 }
1524 return true;
1525}
1526
1528{
1529 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" ) );
1530 const QRegularExpressionMatch match = re.match( mName );
1531 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1532}
1533
1535{
1536 return QSet<QString>() << mName;
1537}
1538
1540{
1541 return QSet<QString>();
1542}
1543
1545{
1546 return QSet<QString>();
1547}
1548
1549QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1550{
1551 QList<const QgsExpressionNode *> result;
1552 result << this;
1553 return result;
1554}
1555
1557{
1558 return false;
1559}
1560
1562{
1564 cloneTo( copy );
1565 return copy;
1566}
1567
1569{
1570 Q_UNUSED( context )
1571 Q_UNUSED( parent )
1572 return false;
1573}
1574
1575//
1576
1578 : mConditions( *conditions )
1579 , mElseExp( elseExp )
1580{
1581 delete conditions;
1582}
1583
1585{
1586 delete mElseExp;
1587 qDeleteAll( mConditions );
1588}
1589
1594
1596{
1597 for ( WhenThen *cond : std::as_const( mConditions ) )
1598 {
1599 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1600 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1602 if ( tvl == QgsExpressionUtils::True )
1603 {
1604 QVariant vRes = cond->mThenExp->eval( parent, context );
1606 return vRes;
1607 }
1608 }
1609
1610 if ( mElseExp )
1611 {
1612 QVariant vElse = mElseExp->eval( parent, context );
1614 return vElse;
1615 }
1616
1617 // return NULL if no condition is matching
1618 return QVariant();
1619}
1620
1622{
1623 bool foundAnyNonStaticConditions = false;
1624 for ( WhenThen *cond : std::as_const( mConditions ) )
1625 {
1626 const bool res = cond->mWhenExp->prepare( parent, context )
1627 && cond->mThenExp->prepare( parent, context );
1628 if ( !res )
1629 return false;
1630
1631 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1632 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1633 {
1634 // 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
1635 // value, and the static value for this WHEN clause is True.
1636 if ( cond->mThenExp->hasCachedStaticValue() )
1637 {
1638 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1639 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1640 mHasCachedValue = true;
1641 return true;
1642 }
1643 else
1644 {
1645 // 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
1646 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1647 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1648 return true;
1649 }
1650 }
1651 }
1652
1653 if ( mElseExp )
1654 {
1655 const bool res = mElseExp->prepare( parent, context );
1656 if ( !res )
1657 return false;
1658
1659 if ( !foundAnyNonStaticConditions )
1660 {
1661 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1662 if ( mElseExp->hasCachedStaticValue() )
1663 {
1665 mHasCachedValue = true;
1666 return true;
1667 }
1668 else
1669 {
1670 // so even though the ELSE node is non-static we can effectively replace
1671 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1672 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1673 return true;
1674 }
1675 }
1676 }
1677
1678 return true;
1679}
1680
1682{
1683 QString msg( QStringLiteral( "CASE" ) );
1684 for ( WhenThen *cond : mConditions )
1685 {
1686 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1687 }
1688 if ( mElseExp )
1689 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1690 msg += QLatin1String( " END" );
1691 return msg;
1692}
1693
1695{
1696 if ( hasCachedStaticValue() )
1697 return QSet< QString >();
1698
1699 QSet<QString> lst;
1700 for ( WhenThen *cond : mConditions )
1701 {
1702 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1703 }
1704
1705 if ( mElseExp )
1706 lst += mElseExp->referencedColumns();
1707
1708 return lst;
1709}
1710
1712{
1713 QSet<QString> lst;
1714 for ( WhenThen *cond : mConditions )
1715 {
1716 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1717 }
1718
1719 if ( mElseExp )
1720 lst += mElseExp->referencedVariables();
1721
1722 return lst;
1723}
1724
1726{
1727 QSet<QString> lst;
1728 for ( WhenThen *cond : mConditions )
1729 {
1730 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1731 }
1732
1733 if ( mElseExp )
1734 lst += mElseExp->referencedFunctions();
1735
1736 return lst;
1737}
1738
1739QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1740{
1741 QList<const QgsExpressionNode *> lst;
1742 lst << this;
1743 for ( WhenThen *cond : mConditions )
1744 {
1745 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1746 }
1747
1748 if ( mElseExp )
1749 lst += mElseExp->nodes();
1750
1751 return lst;
1752}
1753
1755{
1756 for ( WhenThen *cond : mConditions )
1757 {
1758 if ( cond->mWhenExp->needsGeometry() ||
1759 cond->mThenExp->needsGeometry() )
1760 return true;
1761 }
1762
1763 return mElseExp && mElseExp->needsGeometry();
1764}
1765
1767{
1769 conditions.reserve( mConditions.size() );
1770 for ( WhenThen *wt : mConditions )
1771 conditions.append( wt->clone() );
1772
1773 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1774 cloneTo( copy );
1775 return copy;
1776}
1777
1779{
1780 for ( WhenThen *wt : mConditions )
1781 {
1782 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1783 return false;
1784 }
1785
1786 if ( mElseExp )
1787 return mElseExp->isStatic( parent, context );
1788
1789 return true;
1790}
1791
1793{
1794 if ( hasCachedStaticValue() )
1795 return QSet< QString >();
1796
1797 QSet<QString> lst( mNode->referencedColumns() );
1798 const QList< QgsExpressionNode * > nodeList = mList->list();
1799 for ( const QgsExpressionNode *n : nodeList )
1800 lst.unite( n->referencedColumns() );
1801 return lst;
1802}
1803
1805{
1806 QSet<QString> lst( mNode->referencedVariables() );
1807 const QList< QgsExpressionNode * > nodeList = mList->list();
1808 for ( const QgsExpressionNode *n : nodeList )
1809 lst.unite( n->referencedVariables() );
1810 return lst;
1811}
1812
1814{
1815 QSet<QString> lst( mNode->referencedFunctions() );
1816 const QList< QgsExpressionNode * > nodeList = mList->list();
1817 for ( const QgsExpressionNode *n : nodeList )
1818 lst.unite( n->referencedFunctions() );
1819 return lst;
1820}
1821
1822QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1823{
1824 QList<const QgsExpressionNode *> lst;
1825 lst << this;
1826 const QList< QgsExpressionNode * > nodeList = mList->list();
1827 for ( const QgsExpressionNode *n : nodeList )
1828 lst += n->nodes();
1829 return lst;
1830}
1831
1832
1834{
1835 delete mNode;
1836 delete mLowerBound;
1837 delete mHigherBound;
1838}
1839
1844
1846{
1847 bool res = mNode->prepare( parent, context );
1848 res = res && mLowerBound->prepare( parent, context );
1849 res = res && mHigherBound->prepare( parent, context );
1850 return res;
1851}
1852
1854{
1855 const QVariant nodeVal = mNode->eval( parent, context );
1856 if ( QgsVariantUtils::isNull( nodeVal ) )
1857 {
1858 return QVariant();
1859 }
1860
1861 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1862
1864 const QVariant lowBoundValue = lowBound.eval( parent, context );
1865 const bool lowBoundBool { lowBoundValue.toBool() };
1866
1867 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
1868 {
1869 return QVariant( mNegate );
1870 }
1871
1873 const QVariant highBoundValue = highBound.eval( parent, context );
1874
1875 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
1876 {
1877 return QVariant();
1878 }
1879
1880 const bool highBoundBool { highBoundValue.toBool() };
1881
1882 // We already checked if both are nulls
1883 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
1884 {
1885
1886 // In this case we can return a boolean
1887 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
1888 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
1889 {
1890 return QVariant( mNegate );
1891 }
1892
1893 // Indetermined
1894 return QVariant();
1895
1896 }
1897
1898 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
1899 {
1900 return QVariant( mNegate );
1901 }
1902
1903 const bool res { lowBoundBool &&highBoundBool };
1904 return mNegate ? QVariant( ! res ) : QVariant( res );
1905
1906}
1907
1909{
1910 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
1911}
1912
1914{
1915 QSet<QString> lst( mNode->referencedVariables() );
1916 lst.unite( mLowerBound->referencedVariables() );
1917 lst.unite( mHigherBound->referencedVariables() );
1918 return lst;
1919}
1920
1922{
1923 QSet<QString> lst( mNode->referencedFunctions() );
1924 lst.unite( mLowerBound->referencedFunctions() );
1925 lst.unite( mHigherBound->referencedFunctions() );
1926 return lst;
1927}
1928
1929QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
1930{
1931 return { this, mLowerBound, mHigherBound };
1932}
1933
1935{
1936 QSet<QString> lst( mNode->referencedColumns() );
1937 lst.unite( mLowerBound->referencedColumns() );
1938 lst.unite( mHigherBound->referencedColumns() );
1939 return lst;
1940}
1941
1943{
1944 if ( mNode->needsGeometry() )
1945 return true;
1946
1947 if ( mLowerBound->needsGeometry() )
1948 return true;
1949
1950 if ( mHigherBound->needsGeometry() )
1951 return true;
1952
1953 return false;
1954}
1955
1957{
1958 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
1959 cloneTo( copy );
1960 return copy;
1961}
1962
1964{
1965 if ( !mNode->isStatic( parent, context ) )
1966 return false;
1967
1968 if ( !mLowerBound->isStatic( parent, context ) )
1969 return false;
1970
1971 if ( !mHigherBound->isStatic( parent, context ) )
1972 return false;
1973
1974 return true;
1975}
1976
1978{
1979 return mLowerBound;
1980}
1981
1983{
1984 return mHigherBound;
1985}
1986
1988{
1989 return mNegate;
1990}
1991
1993 : mWhenExp( whenExp )
1994 , mThenExp( thenExp )
1995{
1996}
1997
1999{
2000 delete mWhenExp;
2001 delete mThenExp;
2002}
2003
2005{
2006 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2007}
2008
2010{
2011 return BINARY_OPERATOR_TEXT[mOp];
2012}
2013
2014//
2015
2017{
2018 const QVariant container = mContainer->eval( parent, context );
2020 const QVariant index = mIndex->eval( parent, context );
2022
2023 switch ( container.userType() )
2024 {
2025 case QMetaType::Type::QVariantMap:
2026 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2027
2028 case QMetaType::Type::QVariantList:
2029 case QMetaType::Type::QStringList:
2030 {
2031 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2032 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2033 if ( pos >= list.length() || pos < -list.length() )
2034 {
2035 return QVariant();
2036 }
2037 if ( pos < 0 )
2038 {
2039 // negative indices are from back of list
2040 pos += list.length();
2041 }
2042
2043 return list.at( pos );
2044 }
2045
2046 default:
2047 if ( !QgsVariantUtils::isNull( container ) )
2048 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2049 return QVariant();
2050 }
2051}
2052
2057
2059{
2060 bool resC = mContainer->prepare( parent, context );
2061 bool resV = mIndex->prepare( parent, context );
2062 return resC && resV;
2063}
2064
2066{
2067 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2068}
2069
2071{
2072 if ( hasCachedStaticValue() )
2073 return QSet< QString >();
2074
2075 return mContainer->referencedColumns() + mIndex->referencedColumns();
2076}
2077
2079{
2080 return mContainer->referencedVariables() + mIndex->referencedVariables();
2081}
2082
2084{
2085 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2086}
2087
2088QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2089{
2090 QList<const QgsExpressionNode *> lst;
2091 lst << this;
2092 lst += mContainer->nodes() + mIndex->nodes();
2093 return lst;
2094}
2095
2097{
2098 return mContainer->needsGeometry() || mIndex->needsGeometry();
2099}
2100
2102{
2103 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2104 cloneTo( copy );
2105 return copy;
2106}
2107
2109{
2110 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2111}
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:58
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Container of fields for a vector layer.
Definition qgsfields.h:46
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A representation of the interval between two datetime values.
Definition qgsinterval.h: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, bool silenceNullWarnings=false)
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:5917
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.