QGIS API Documentation 3.99.0-Master (d270888f95f)
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
18#include "qgsexpression.h"
19#include "qgsexpressionutils.h"
20#include "qgsstringutils.h"
21#include "qgsvariantutils.h"
22
23#include <QDate>
24#include <QDateTime>
25#include <QRegularExpression>
26#include <QString>
27#include <QTime>
28
29using namespace Qt::StringLiterals;
30
31const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
32{
33 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
34 "OR", "AND",
35 "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
36 "+", "-", "*", "/", "//", "%", "^",
37 "||"
38};
39
40const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
41{
42 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
43 "NOT", "-"
44};
45
47{
48 bool needs = false;
49 const QList< QgsExpressionNode * > nodeList = mList->list();
50 for ( QgsExpressionNode *n : nodeList )
51 needs |= n->needsGeometry();
52 return needs;
53}
54
56{
57 qDeleteAll( mList );
58}
59
61{
62 mList.append( node->node );
63 mNameList.append( cleanNamedNodeName( node->name ) );
64 mHasNamedNodes = true;
65 delete node;
66}
67
69{
70 NodeList *nl = new NodeList;
71 for ( QgsExpressionNode *node : mList )
72 {
73 nl->mList.append( node->clone() );
74 }
75 nl->mNameList = mNameList;
76
77 return nl;
78}
79
81{
82 QString msg;
83 bool first = true;
84 for ( QgsExpressionNode *n : mList )
85 {
86 if ( !first ) msg += ", "_L1;
87 else first = false;
88 msg += n->dump();
89 }
90 return msg;
91}
92
93QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
94{
95 QString cleaned = name.toLower();
96
97 // upgrade older argument names to standard versions
98 if ( cleaned == "geom"_L1 )
99 cleaned = u"geometry"_s;
100 else if ( cleaned == "val"_L1 )
101 cleaned = u"value"_s;
102 else if ( cleaned == "geometry a"_L1 )
103 cleaned = u"geometry1"_s;
104 else if ( cleaned == "geometry b"_L1 )
105 cleaned = u"geometry2"_s;
106 else if ( cleaned == "i"_L1 )
107 cleaned = u"vertex"_s;
108
109 return cleaned;
110}
111
112
113//
114
116{
117 QVariant val = mOperand->eval( parent, context );
119
120 switch ( mOp )
121 {
122 case uoNot:
123 {
124 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
126 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
127 }
128
129 case uoMinus:
130 if ( QgsExpressionUtils::isIntSafe( val ) )
131 return QVariant( - QgsExpressionUtils::getIntValue( val, parent ) );
132 else if ( QgsExpressionUtils::isDoubleSafe( val ) )
133 return QVariant( - QgsExpressionUtils::getDoubleValue( val, parent ) );
134 else
135 SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
136 }
137 return QVariant();
138}
139
144
146{
147 return mOperand->prepare( parent, context );
148}
149
151{
152 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand.get() ) )
153 return u"%1 ( %2 )"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
154 else
155 return u"%1 %2"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
156}
157
159{
160 if ( hasCachedStaticValue() )
161 return QSet< QString >();
162
163 return mOperand->referencedColumns();
164}
165
167{
168 return mOperand->referencedVariables();
169}
170
172{
173 return mOperand->referencedFunctions();
174}
175
176QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
177{
178 QList<const QgsExpressionNode *> lst;
179 lst.append( this );
180 lst += mOperand->nodes();
181 return lst;
182}
183
185{
186 return mOperand->needsGeometry();
187}
188
190{
191 QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
192 cloneTo( copy );
193 return copy;
194}
195
197{
198 return mOperand->isStatic( parent, context );
199}
200
202{
203 return UNARY_OPERATOR_TEXT[mOp];
204}
205
206//
207
208template<class T>
210{
211 switch ( op )
212 {
214 return diff == 0;
216 return diff != 0;
218 return diff < 0;
220 return diff > 0;
222 return diff <= 0;
224 return diff >= 0;
225 default:
226 Q_ASSERT( false );
227 return false;
228 }
229}
230
231template<>
233{
234 switch ( op )
235 {
237 return qgsDoubleNear( diff, 0.0 );
239 return !qgsDoubleNear( diff, 0.0 );
241 return diff < 0;
243 return diff > 0;
245 return diff <= 0;
247 return diff >= 0;
248 default:
249 Q_ASSERT( false );
250 return false;
251 }
252}
253
254QVariant QgsExpressionNodeBinaryOperator::compareNonNullValues( QgsExpression *parent, const QgsExpressionContext *, const QVariant &vL, const QVariant &vR, BinaryOperator op )
255{
256 if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
257 {
258 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
260 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
262
263 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
264 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
265 // results (due to different hidden timezones), we force all datetime comparisons to treat
266 // all datetime values as having the same time zone
267 dL.setTimeSpec( Qt::UTC );
268 dR.setTimeSpec( Qt::UTC );
269
270 return compareOp<qint64>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
271 }
272 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
273 {
274 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
276 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
278 return compareOp<qint64>( dR.daysTo( dL ), op ) ? TVL_True : TVL_False;
279 }
280 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
281 {
282 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
284 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
286 return compareOp<int>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
287 }
288 else if ( ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) &&
289 QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
290 {
291 // do numeric comparison if both operators can be converted to numbers,
292 // and they aren't both string
293 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
295 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
297 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
298 }
299
300 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
301 {
302 // Documented behavior of QVariant::toBool() for each userType:
303 //
304 // For variant with userType():
305 //
306 // QMetaType::Bool:
307 // true if value is true
308 // false otherwise
309 //
310 // QMetaType::QChar, QMetaType::Double, QMetaType::Int,
311 // QMetaType::LongLong, QMetaType::UInt, and QMetaType::ULongLong:
312 // true if the value is non-zero
313 // false otherwise
314 //
315 // QMetaType::QString and QMetaType::QByteArray:
316 // false if its lower-case content is empty, "0" or "false"
317 // true otherwise
318 //
319 // All other variants always return false.
320
321 // Note: Boolean logical operators behave the same in C++ and SQL.
322 const bool vLBool = vL.toBool();
323 const bool vRBool = vR.toBool();
324 switch ( op )
325 {
326 case boEQ:
327 return vLBool == vRBool ? TVL_True : TVL_False;
328 case boNE:
329 return vLBool != vRBool ? TVL_True : TVL_False;
330 case boLT:
331 return vLBool < vRBool ? TVL_True : TVL_False;
332 case boLE:
333 return vLBool <= vRBool ? TVL_True : TVL_False;
334 case boGT:
335 return vLBool > vRBool ? TVL_True : TVL_False;
336 case boGE:
337 return vLBool >= vRBool ? TVL_True : TVL_False;
338 case boOr:
339 case boAnd:
340 case boRegexp:
341 case boLike:
342 case boNotLike:
343 case boILike:
344 case boNotILike:
345 case boIs:
346 case boIsNot:
347 case boPlus:
348 case boMinus:
349 case boMul:
350 case boDiv:
351 case boIntDiv:
352 case boMod:
353 case boPow:
354 case boConcat:
355 // should not happen
356 break;
357 }
358 return TVL_Unknown;
359 }
360
361 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
362 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
363 {
364 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
366 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
368 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
369 }
370 else
371 {
372 // do string comparison otherwise
373 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
375 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
377 int diff = QString::compare( sL, sR );
378 return compareOp<int>( diff, op ) ? TVL_True : TVL_False;
379 }
380}
381
383{
384 QVariant vL = mOpLeft->eval( parent, context );
386
387 if ( mOp == boAnd || mOp == boOr )
388 {
389 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
391 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
392 return TVL_False; // shortcut -- no need to evaluate right-hand side
393 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
394 return TVL_True; // shortcut -- no need to evaluate right-hand side
395 }
396
397 QVariant vR = mOpRight->eval( parent, context );
399
400 switch ( mOp )
401 {
402 case boPlus:
403 if ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
404 {
405 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
407 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
409 return QVariant( sL + sR );
410 }
411 //intentional fall-through
412 [[fallthrough]];
413 case boMinus:
414 case boMul:
415 case boDiv:
416 case boMod:
417 {
418 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
419 return QVariant();
420 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
421 {
422 // both are integers - let's use integer arithmetic
423 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
425 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
427
428 if ( mOp == boMod && iR == 0 )
429 return QVariant();
430
431 return QVariant( computeInt( iL, iR ) );
432 }
433 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
434 {
435 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
437 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
439 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
440 {
441 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
442 return QVariant();
443 }
444 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
445 }
446 else if ( mOp == boPlus && ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) ||
447 ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
448 {
449 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
451 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
453 QDateTime dt = QDateTime( date, time );
454 return QVariant( dt );
455 }
456 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
457 {
458 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
460 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
462 return date1 - date2;
463 }
464 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
465 {
466 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
468 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
470 return time1 - time2;
471 }
472 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
473 {
474 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
476 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
478 return QgsInterval( datetime1 - datetime2 );
479 }
480 else
481 {
482 // general floating point arithmetic
483 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
485 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
487 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
488 return QVariant(); // silently handle division by zero and return NULL
489 return QVariant( computeDouble( fL, fR ) );
490 }
491 }
492 case boIntDiv:
493 {
494 //integer division
495 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
497 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
499 if ( fR == 0. )
500 return QVariant(); // silently handle division by zero and return NULL
501 return QVariant( qlonglong( std::floor( fL / fR ) ) );
502 }
503 case boPow:
504 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
505 return QVariant();
506 else
507 {
508 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
510 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
512 return QVariant( std::pow( fL, fR ) );
513 }
514
515 case boAnd:
516 {
517 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
519 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
520 }
521
522 case boOr:
523 {
524 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
526 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
527 }
528
529 case boEQ:
530 case boNE:
531 case boLT:
532 case boGT:
533 case boLE:
534 case boGE:
535 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
536 {
537 return TVL_Unknown;
538 }
539 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
540 {
541 // verify that we have two lists
542 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
543 return TVL_Unknown;
544
545 // and search for not equal respective items
546 QVariantList lL = vL.toList();
547 QVariantList lR = vR.toList();
548 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
549 {
550 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
551 continue; // same behavior as PostgreSQL
552
553 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
554 {
555 switch ( mOp )
556 {
557 case boEQ:
558 return false;
559 case boNE:
560 return true;
561 case boLT:
562 case boLE:
563 return QgsExpressionUtils::isNull( lR.at( i ) );
564 case boGT:
565 case boGE:
566 return QgsExpressionUtils::isNull( lL.at( i ) );
567 default:
568 Q_ASSERT( false );
569 return TVL_Unknown;
570 }
571 }
572
573 QgsExpressionNodeLiteral nL( lL.at( i ) );
574 QgsExpressionNodeLiteral nR( lR.at( i ) );
575 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
576 QVariant eq = eqNode.eval( parent, context );
578 if ( eq == TVL_False )
579 {
580 // return the two items comparison
581 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
582 QVariant v = node.eval( parent, context );
584 return v;
585 }
586 }
587
588 // default to length comparison
589 switch ( mOp )
590 {
591 case boEQ:
592 return lL.length() == lR.length();
593 case boNE:
594 return lL.length() != lR.length();
595 case boLT:
596 return lL.length() < lR.length();
597 case boGT:
598 return lL.length() > lR.length();
599 case boLE:
600 return lL.length() <= lR.length();
601 case boGE:
602 return lL.length() >= lR.length();
603 default:
604 Q_ASSERT( false );
605 return TVL_Unknown;
606 }
607 }
608 else
609 {
610 return compareNonNullValues( parent, context, vL, vR, mOp );
611 }
612
613 case boIs:
614 case boIsNot:
615 {
616 const bool vLNull = QgsExpressionUtils::isNull( vL );
617 const bool vRNull = QgsExpressionUtils::isNull( vR );
618 if ( vLNull && vRNull ) // both operators null
619 return ( mOp == boIs ? TVL_True : TVL_False );
620 else if ( vLNull || vRNull ) // one operator null
621 return ( mOp == boIs ? TVL_False : TVL_True );
622 else // both operators non-null
623 {
624 return compareNonNullValues( parent, context, vL, vR, mOp == boIs ? boEQ : boNE );
625 }
626 }
627
628 case boRegexp:
629 case boLike:
630 case boNotLike:
631 case boILike:
632 case boNotILike:
633 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
634 return TVL_Unknown;
635 else
636 {
637 QString str = QgsExpressionUtils::getStringValue( vL, parent );
639 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
641 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
642 bool matches;
643 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
644 {
645 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
646 // manage escape % and _
647 if ( esc_regexp.startsWith( '%' ) )
648 {
649 esc_regexp.replace( 0, 1, u".*"_s );
650 }
651 const thread_local QRegularExpression rx1( u"[^\\\\](%)"_s );
652 int pos = 0;
653 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
654 {
655 esc_regexp.replace( pos + 1, 1, u".*"_s );
656 pos += 1;
657 }
658 const thread_local QRegularExpression rx2( u"\\\\%"_s );
659 esc_regexp.replace( rx2, u"%"_s );
660 if ( esc_regexp.startsWith( '_' ) )
661 {
662 esc_regexp.replace( 0, 1, u"."_s );
663 }
664 const thread_local QRegularExpression rx3( u"[^\\\\](_)"_s );
665 pos = 0;
666 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
667 {
668 esc_regexp.replace( pos + 1, 1, '.' );
669 pos += 1;
670 }
671 esc_regexp.replace( "\\\\_"_L1, "_"_L1 );
672
673 matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
674 }
675 else
676 {
677 matches = QRegularExpression( regexp ).match( str ).hasMatch();
678 }
679
680 if ( mOp == boNotLike || mOp == boNotILike )
681 {
682 matches = !matches;
683 }
684
685 return matches ? TVL_True : TVL_False;
686 }
687
688 case boConcat:
689 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
690 return QVariant();
691 else
692 {
693 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
695 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
697 return QVariant( sL + sR );
698 }
699 }
700 Q_ASSERT( false );
701 return QVariant();
702}
703
704qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
705{
706 switch ( mOp )
707 {
708 case boPlus:
709 return x + y;
710 case boMinus:
711 return x - y;
712 case boMul:
713 return x * y;
714 case boDiv:
715 return x / y;
716 case boMod:
717 return x % y;
718 default:
719 Q_ASSERT( false );
720 return 0;
721 }
722}
723
724QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
725{
726 switch ( mOp )
727 {
728 case boPlus:
729 return d.addSecs( i->seconds() );
730 case boMinus:
731 return d.addSecs( -i->seconds() );
732 default:
733 Q_ASSERT( false );
734 return QDateTime();
735 }
736}
737
738double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
739{
740 switch ( mOp )
741 {
742 case boPlus:
743 return x + y;
744 case boMinus:
745 return x - y;
746 case boMul:
747 return x * y;
748 case boDiv:
749 return x / y;
750 case boMod:
751 return std::fmod( x, y );
752 default:
753 Q_ASSERT( false );
754 return 0;
755 }
756}
757
762
764{
765
766 // if this is an OR, try to collapse the OR expression into an IN node
767 if ( mOp == boOr )
768 {
769
770 // First step: flatten OR chain and collect values
771 QMap<QString, QgsExpressionNode::NodeList> orValuesMap;
772 QList<QString> orFieldNames;
773
774 // Get a list of all the OR and IN nodes chained together
775 std::function<bool ( QgsExpressionNode * )> visitOrNodes = [&visitOrNodes, &orValuesMap, &orFieldNames]( QgsExpressionNode * node ) -> bool
776 {
778 {
779 if ( op->op() != boOr && op->op() != boEQ )
780 {
781 return false;
782 }
783
784 if ( op->op() == boEQ )
785 {
786 // If left is a column ref and right is a literal, collect
787 if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opLeft() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opRight() ) ) )
788 {
789 const QString fieldName = op->opLeft()->dump();
790 if ( !orValuesMap.contains( fieldName ) )
791 {
792 orFieldNames.append( fieldName );
793 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
794 }
795 orValuesMap[fieldName].append( op->opRight()->clone() );
796 return true;
797 }
798 else if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opRight() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opLeft() ) ) )
799 {
800 const QString fieldName = op->opRight()->dump();
801 if ( !orValuesMap.contains( fieldName ) )
802 {
803 orFieldNames.append( fieldName );
804 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
805 }
806 orValuesMap[fieldName].append( op->opLeft()->clone() );
807 return true;
808 }
809 return false;
810 }
811
812 if ( visitOrNodes( op->opLeft() ) && visitOrNodes( op->opRight() ) )
813 {
814 return true;
815 }
816
817 }
818 else if ( QgsExpressionNodeInOperator *inOp = dynamic_cast<QgsExpressionNodeInOperator *>( node ) )
819 {
820 if ( inOp->isNotIn() || inOp->node()->nodeType() != QgsExpressionNode::ntColumnRef )
821 {
822 return false;
823 }
824
825 const QString fieldName = inOp->node()->dump();
826
827 // Check if all nodes are literals
828 const auto nodes = inOp->list()->list();
829 for ( const auto &valueNode : std::as_const( nodes ) )
830 {
831 if ( valueNode->nodeType() != QgsExpressionNode::ntLiteral )
832 {
833 return false;
834 }
835 }
836
837 if ( !orValuesMap.contains( fieldName ) )
838 {
839 orFieldNames.append( fieldName );
840 orValuesMap.insert( fieldName, *inOp->list()->clone() );
841 }
842 else
843 {
844 for ( const auto &valueNode : std::as_const( nodes ) )
845 {
846 orValuesMap[fieldName].append( valueNode->clone() );
847 }
848 }
849
850 return true;
851 }
852 return false;
853 };
854
855
856 // Second step: build the OR chain of IN operators
857 if ( visitOrNodes( this ) && ! orValuesMap.empty() )
858 {
859
860 std::unique_ptr<QgsExpressionNode> currentNode;
861 for ( const auto &fieldName : std::as_const( orFieldNames ) )
862 {
863 auto orValuesIt = orValuesMap.find( fieldName );
864 if ( orValuesIt.value().count() == 1 )
865 {
866 auto eqNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boEQ, new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().at( 0 )->clone() );
867 if ( currentNode )
868 {
869 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), eqNode.release() );
870 }
871 else
872 {
873 currentNode = std::move( eqNode );
874 }
875 }
876 else
877 {
878 auto inNode = std::make_unique<QgsExpressionNodeInOperator>( new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().clone() );
879 if ( currentNode )
880 {
881 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), inNode.release() );
882 }
883 else
884 {
885 currentNode = std::move( inNode );
886 }
887 }
888 }
889
890
891 if ( currentNode )
892 {
893 mCompiledSimplifiedNode = std::move( currentNode );
894 }
895 }
896
897 }
898
899 bool resL = mOpLeft->prepare( parent, context );
900 bool resR = mOpRight->prepare( parent, context );
901 return resL && resR;
902}
903
905{
906 // see left/right in qgsexpressionparser.yy
907 switch ( mOp )
908 {
909 case boOr:
910 return 1;
911
912 case boAnd:
913 return 2;
914
915 case boEQ:
916 case boNE:
917 case boLE:
918 case boGE:
919 case boLT:
920 case boGT:
921 case boRegexp:
922 case boLike:
923 case boILike:
924 case boNotLike:
925 case boNotILike:
926 case boIs:
927 case boIsNot:
928 return 3;
929
930 case boPlus:
931 case boMinus:
932 return 4;
933
934 case boMul:
935 case boDiv:
936 case boIntDiv:
937 case boMod:
938 return 5;
939
940 case boPow:
941 return 6;
942
943 case boConcat:
944 return 7;
945 }
946 Q_ASSERT( false && "unexpected binary operator" );
947 return -1;
948}
949
951{
952 // see left/right in qgsexpressionparser.yy
953 switch ( mOp )
954 {
955 case boOr:
956 case boAnd:
957 case boEQ:
958 case boNE:
959 case boLE:
960 case boGE:
961 case boLT:
962 case boGT:
963 case boRegexp:
964 case boLike:
965 case boILike:
966 case boNotLike:
967 case boNotILike:
968 case boIs:
969 case boIsNot:
970 case boPlus:
971 case boMinus:
972 case boMul:
973 case boDiv:
974 case boIntDiv:
975 case boMod:
976 case boConcat:
977 return true;
978
979 case boPow:
980 return false;
981 }
982 Q_ASSERT( false && "unexpected binary operator" );
983 return false;
984}
985
987{
988 QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft.get() );
989 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight.get() );
990 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight.get() );
991
992 QString rdump( mOpRight->dump() );
993
994 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
995 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
996 {
997 rdump.prepend( '(' ).append( ')' );
998 }
999
1000 QString fmt;
1001 if ( leftAssociative() )
1002 {
1003 fmt += lOp && ( lOp->precedence() < precedence() ) ? u"(%1)"_s : u"%1"_s;
1004 fmt += " %2 "_L1;
1005 fmt += rOp && ( rOp->precedence() <= precedence() ) ? u"(%3)"_s : u"%3"_s;
1006 }
1007 else
1008 {
1009 fmt += lOp && ( lOp->precedence() <= precedence() ) ? u"(%1)"_s : u"%1"_s;
1010 fmt += " %2 "_L1;
1011 fmt += rOp && ( rOp->precedence() < precedence() ) ? u"(%3)"_s : u"%3"_s;
1012 }
1013
1014 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
1015}
1016
1018{
1019 if ( hasCachedStaticValue() )
1020 return QSet< QString >();
1021
1022 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
1023}
1024
1026{
1027 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
1028}
1029
1031{
1032 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
1033}
1034
1035QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
1036{
1037 QList<const QgsExpressionNode *> lst;
1038 lst << this;
1039 lst += mOpLeft->nodes() + mOpRight->nodes();
1040 return lst;
1041}
1042
1044{
1045 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
1046}
1047
1049{
1050 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
1051 cloneTo( copy );
1052 return copy;
1053}
1054
1056{
1057 const bool leftStatic = mOpLeft->isStatic( parent, context );
1058 const bool rightStatic = mOpRight->isStatic( parent, context );
1059
1060 if ( leftStatic && rightStatic )
1061 return true;
1062
1063 // special logic for certain ops...
1064 switch ( mOp )
1065 {
1067 {
1068 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
1069 // of the value of the other node!
1070 if ( leftStatic )
1071 {
1072 mOpLeft->prepare( parent, context );
1073 if ( mOpLeft->hasCachedStaticValue() )
1074 {
1075 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1076 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1077 {
1078 mCachedStaticValue = true;
1079 mHasCachedValue = true;
1080 return true;
1081 }
1082 }
1083 }
1084 else if ( rightStatic )
1085 {
1086 mOpRight->prepare( parent, context );
1087 if ( mOpRight->hasCachedStaticValue() )
1088 {
1089 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1090 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1091 {
1092 mCachedStaticValue = true;
1093 mHasCachedValue = true;
1094 return true;
1095 }
1096 }
1097 }
1098
1099 break;
1100 }
1102 {
1103 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
1104 // of the value of the other node!
1105
1106 if ( leftStatic )
1107 {
1108 mOpLeft->prepare( parent, context );
1109 if ( mOpLeft->hasCachedStaticValue() )
1110 {
1111 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1112 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1113 {
1114 mCachedStaticValue = false;
1115 mHasCachedValue = true;
1116 return true;
1117 }
1118 }
1119 }
1120 else if ( rightStatic )
1121 {
1122 mOpRight->prepare( parent, context );
1123 if ( mOpRight->hasCachedStaticValue() )
1124 {
1125 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1126 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1127 {
1128 mCachedStaticValue = false;
1129 mHasCachedValue = true;
1130 return true;
1131 }
1132 }
1133 }
1134
1135 break;
1136 }
1137
1159 break;
1160 }
1161
1162 return false;
1163}
1164
1165//
1166
1168{
1169 if ( mList->count() == 0 )
1170 return mNotIn ? TVL_True : TVL_False;
1171 QVariant v1 = mNode->eval( parent, context );
1173 if ( QgsExpressionUtils::isNull( v1 ) )
1174 return TVL_Unknown;
1175
1176 bool listHasNull = false;
1177
1178 const QList< QgsExpressionNode * > nodeList = mList->list();
1179 for ( QgsExpressionNode *n : nodeList )
1180 {
1181 QVariant v2 = n->eval( parent, context );
1183 if ( QgsExpressionUtils::isNull( v2 ) )
1184 listHasNull = true;
1185 else
1186 {
1187 bool equal = false;
1188 // check whether they are equal
1189 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) &&
1190 QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
1191 {
1192 // do numeric comparison if both operators can be converted to numbers,
1193 // and they aren't both string
1194 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
1196 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
1198 equal = qgsDoubleNear( f1, f2 );
1199 }
1200 else
1201 {
1202 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1204 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1206 equal = QString::compare( s1, s2 ) == 0;
1207 }
1208
1209 if ( equal ) // we know the result
1210 return mNotIn ? TVL_False : TVL_True;
1211 }
1212 }
1213
1214 // item not found
1215 if ( listHasNull )
1216 return TVL_Unknown;
1217 else
1218 return mNotIn ? TVL_True : TVL_False;
1219}
1220
1224
1229
1231{
1232 bool res = mNode->prepare( parent, context );
1233 const QList< QgsExpressionNode * > nodeList = mList->list();
1234 for ( QgsExpressionNode *n : nodeList )
1235 {
1236 res = res && n->prepare( parent, context );
1237 }
1238 return res;
1239}
1240
1242{
1243 return u"%1 %2 IN (%3)"_s.arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1244}
1245
1247{
1248 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1249 cloneTo( copy );
1250 return copy;
1251}
1252
1254{
1255 if ( !mNode->isStatic( parent, context ) )
1256 return false;
1257
1258 const QList< QgsExpressionNode * > nodeList = mList->list();
1259 for ( QgsExpressionNode *n : nodeList )
1260 {
1261 if ( !n->isStatic( parent, context ) )
1262 return false;
1263 }
1264
1265 return true;
1266}
1267
1268//
1269
1271{
1272 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1273 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1274
1275 QVariant res = fd->run( mArgs.get(), context, parent, this );
1277
1278 // everything went fine
1279 return res;
1280}
1281
1283 : mFnIndex( fnIndex )
1284{
1285 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1286 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1287 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1288 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1289
1290 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1291 const int functionParamsSize = functionParams.size();
1292 if ( functionParams.isEmpty() )
1293 {
1294 // function does not support parameters
1295 mArgs.reset( args );
1296 }
1297 else if ( !args )
1298 {
1299 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1300 mArgs = std::make_unique<NodeList>();
1301 mArgs->reserve( functionParamsSize );
1302 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1303 {
1304 // insert default value for QgsExpressionFunction::Parameter
1305 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1306 }
1307 }
1308 else
1309 {
1310 mArgs = std::make_unique<NodeList>();
1311 mArgs->reserve( functionParamsSize );
1312
1313 int idx = 0;
1314 const QStringList argNames = args->names();
1315 const QList<QgsExpressionNode *> argList = args->list();
1316 //first loop through unnamed arguments
1317 {
1318 const int argNamesSize = argNames.size();
1319 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1320 {
1321 mArgs->append( argList.at( idx )->clone() );
1322 idx++;
1323 }
1324 }
1325
1326 //next copy named QgsExpressionFunction::Parameters in order expected by function
1327 for ( ; idx < functionParamsSize; ++idx )
1328 {
1329 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1330 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1331 if ( nodeIdx < 0 )
1332 {
1333 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1334 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1335 }
1336 else
1337 {
1338 mArgs->append( argList.at( nodeIdx )->clone() );
1339 }
1340 }
1341
1342 delete args;
1343 }
1344}
1345
1350
1355
1357{
1358 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1359
1360 bool res = fd->prepare( this, parent, context );
1361 if ( mArgs && !fd->lazyEval() )
1362 {
1363 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1364 for ( QgsExpressionNode *n : nodeList )
1365 {
1366 res = res && n->prepare( parent, context );
1367 }
1368 }
1369 return res;
1370}
1371
1373{
1374 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1375 if ( fd->params() == 0 )
1376 return u"%1%2"_s.arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : u"()"_s ); // special column
1377 else
1378 return u"%1(%2)"_s.arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1379}
1380
1382{
1383 if ( hasCachedStaticValue() )
1384 return QSet< QString >();
1385
1386 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1387 QSet<QString> functionColumns = fd->referencedColumns( this );
1388
1389 if ( !mArgs )
1390 {
1391 //no referenced columns in arguments, just return function's referenced columns
1392 return functionColumns;
1393 }
1394
1395 int paramIndex = 0;
1396 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1397 for ( QgsExpressionNode *n : nodeList )
1398 {
1399 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1400 functionColumns.unite( n->referencedColumns() );
1401 paramIndex++;
1402 }
1403
1404 return functionColumns;
1405}
1406
1408{
1409 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1410 if ( fd->name() == "var"_L1 )
1411 {
1412 if ( !mArgs->list().isEmpty() )
1413 {
1414 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1415 if ( var )
1416 return QSet<QString>() << var->value().toString();
1417 }
1418 return QSet<QString>() << QString();
1419 }
1420 else
1421 {
1422 QSet<QString> functionVariables = QSet<QString>();
1423
1424 if ( !mArgs )
1425 return functionVariables;
1426
1427 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1428 for ( QgsExpressionNode *n : nodeList )
1429 {
1430 functionVariables.unite( n->referencedVariables() );
1431 }
1432
1433 return functionVariables;
1434 }
1435}
1436
1438{
1439 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1440 QSet<QString> functions = QSet<QString>();
1441 functions.insert( fd->name() );
1442
1443 if ( !mArgs )
1444 return functions;
1445
1446 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1447 for ( QgsExpressionNode *n : nodeList )
1448 {
1449 functions.unite( n->referencedFunctions() );
1450 }
1451 return functions;
1452}
1453
1454QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1455{
1456 QList<const QgsExpressionNode *> lst;
1457 lst << this;
1458 if ( !mArgs )
1459 return lst;
1460
1461 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1462 for ( QgsExpressionNode *n : nodeList )
1463 {
1464 lst += n->nodes();
1465 }
1466 return lst;
1467}
1468
1470{
1471 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1472 if ( mArgs )
1473 {
1474 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1475 for ( QgsExpressionNode *n : nodeList )
1476 needs |= n->needsGeometry();
1477 }
1478 return needs;
1479}
1480
1482{
1483 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1484 cloneTo( copy );
1485 return copy;
1486}
1487
1489{
1490 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1491}
1492
1494{
1495 if ( !args || !args->hasNamedNodes() )
1496 return true;
1497
1498 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1499 if ( functionParams.isEmpty() )
1500 {
1501 error = u"%1 does not support named QgsExpressionFunction::Parameters"_s.arg( QgsExpression::Functions()[fnIndex]->name() );
1502 return false;
1503 }
1504 else
1505 {
1506 QSet< int > providedArgs;
1507 QSet< int > handledArgs;
1508 int idx = 0;
1509 //first loop through unnamed arguments
1510 while ( args->names().at( idx ).isEmpty() )
1511 {
1512 providedArgs << idx;
1513 handledArgs << idx;
1514 idx++;
1515 }
1516
1517 //next check named QgsExpressionFunction::Parameters
1518 for ( ; idx < functionParams.count(); ++idx )
1519 {
1520 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1521 if ( nodeIdx < 0 )
1522 {
1523 if ( !functionParams.at( idx ).optional() )
1524 {
1525 error = u"No value specified for QgsExpressionFunction::Parameter '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1526 return false;
1527 }
1528 }
1529 else
1530 {
1531 if ( providedArgs.contains( idx ) )
1532 {
1533 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1534 return false;
1535 }
1536 }
1537 providedArgs << idx;
1538 handledArgs << nodeIdx;
1539 }
1540
1541 //last check for bad names
1542 idx = 0;
1543 const QStringList nameList = args->names();
1544 for ( const QString &name : nameList )
1545 {
1546 if ( !name.isEmpty() && !functionParams.contains( name ) )
1547 {
1548 error = u"Invalid QgsExpressionFunction::Parameter name '%1' for %2"_s.arg( name, QgsExpression::Functions()[fnIndex]->name() );
1549 return false;
1550 }
1551 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1552 {
1553 int functionIdx = functionParams.indexOf( name );
1554 if ( providedArgs.contains( functionIdx ) )
1555 {
1556 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1557 return false;
1558 }
1559 }
1560 idx++;
1561 }
1562
1563 }
1564 return true;
1565}
1566
1567//
1568
1570{
1571 Q_UNUSED( context )
1572 Q_UNUSED( parent )
1573 return mValue;
1574}
1575
1580
1582{
1583 Q_UNUSED( parent )
1584 Q_UNUSED( context )
1585 return true;
1586}
1587
1588
1590{
1591 if ( QgsVariantUtils::isNull( mValue ) )
1592 return u"NULL"_s;
1593
1594 switch ( mValue.userType() )
1595 {
1596 case QMetaType::Type::Int:
1597 return QString::number( mValue.toInt() );
1598 case QMetaType::Type::Double:
1599 return qgsDoubleToString( mValue.toDouble() );
1600 case QMetaType::Type::LongLong:
1601 return QString::number( mValue.toLongLong() );
1602 case QMetaType::Type::QString:
1603 return QgsExpression::quotedString( mValue.toString() );
1604 case QMetaType::Type::QTime:
1605 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1606 case QMetaType::Type::QDate:
1607 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1608 case QMetaType::Type::QDateTime:
1609 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1610 case QMetaType::Type::Bool:
1611 return mValue.toBool() ? u"TRUE"_s : u"FALSE"_s;
1612 default:
1613 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1614 }
1615}
1616
1618{
1619 return valueAsString();
1620}
1621
1623{
1624 return QSet<QString>();
1625}
1626
1628{
1629 return QSet<QString>();
1630}
1631
1633{
1634 return QSet<QString>();
1635}
1636
1637QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1638{
1639 QList<const QgsExpressionNode *> lst;
1640 lst << this;
1641 return lst;
1642}
1643
1645{
1646 return false;
1647}
1648
1650{
1652 cloneTo( copy );
1653 return copy;
1654}
1655
1657{
1658 Q_UNUSED( context )
1659 Q_UNUSED( parent )
1660 return true;
1661}
1662
1663//
1664
1666{
1667 Q_UNUSED( parent )
1668 int index = mIndex;
1669
1670 if ( index < 0 )
1671 {
1672 // have not yet found field index - first check explicitly set fields collection
1673 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1674 {
1675 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1676 index = fields.lookupField( mName );
1677 }
1678 }
1679
1680 if ( context )
1681 {
1682 QgsFeature feature = context->feature();
1683 if ( feature.isValid() )
1684 {
1685 if ( index >= 0 )
1686 return feature.attribute( index );
1687 else
1688 return feature.attribute( mName );
1689 }
1690 else
1691 {
1692 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1693 }
1694 }
1695 if ( index < 0 )
1696 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1697 return QVariant();
1698}
1699
1704
1706{
1707 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1708 return false;
1709
1710 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1711
1712 mIndex = fields.lookupField( mName );
1713
1714 if ( mIndex == -1 && context->hasFeature() )
1715 {
1716 mIndex = context->feature().fieldNameIndex( mName );
1717 }
1718
1719 if ( mIndex == -1 )
1720 {
1721 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1722 return false;
1723 }
1724 return true;
1725}
1726
1728{
1729 const thread_local QRegularExpression re( u"^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$"_s );
1730 const QRegularExpressionMatch match = re.match( mName );
1731 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1732}
1733
1735{
1736 return QSet<QString>() << mName;
1737}
1738
1740{
1741 return QSet<QString>();
1742}
1743
1745{
1746 return QSet<QString>();
1747}
1748
1749QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1750{
1751 QList<const QgsExpressionNode *> result;
1752 result << this;
1753 return result;
1754}
1755
1757{
1758 return false;
1759}
1760
1762{
1764 cloneTo( copy );
1765 return copy;
1766}
1767
1769{
1770 Q_UNUSED( context )
1771 Q_UNUSED( parent )
1772 return false;
1773}
1774
1775//
1776
1783
1785{
1786
1787 qDeleteAll( mConditions );
1788}
1789
1794
1796{
1797 for ( WhenThen *cond : std::as_const( mConditions ) )
1798 {
1799 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1800 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1802 if ( tvl == QgsExpressionUtils::True )
1803 {
1804 QVariant vRes = cond->mThenExp->eval( parent, context );
1806 return vRes;
1807 }
1808 }
1809
1810 if ( mElseExp )
1811 {
1812 QVariant vElse = mElseExp->eval( parent, context );
1814 return vElse;
1815 }
1816
1817 // return NULL if no condition is matching
1818 return QVariant();
1819}
1820
1822{
1823 bool foundAnyNonStaticConditions = false;
1824 for ( WhenThen *cond : std::as_const( mConditions ) )
1825 {
1826 const bool res = cond->mWhenExp->prepare( parent, context )
1827 && cond->mThenExp->prepare( parent, context );
1828 if ( !res )
1829 return false;
1830
1831 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1832 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1833 {
1834 // 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
1835 // value, and the static value for this WHEN clause is True.
1836 if ( cond->mThenExp->hasCachedStaticValue() )
1837 {
1838 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1839 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1840 mHasCachedValue = true;
1841 return true;
1842 }
1843 else
1844 {
1845 // 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
1846 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1847 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1848 return true;
1849 }
1850 }
1851 }
1852
1853 if ( mElseExp )
1854 {
1855 const bool res = mElseExp->prepare( parent, context );
1856 if ( !res )
1857 return false;
1858
1859 if ( !foundAnyNonStaticConditions )
1860 {
1861 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1862 if ( mElseExp->hasCachedStaticValue() )
1863 {
1864 mCachedStaticValue = mElseExp->cachedStaticValue();
1865 mHasCachedValue = true;
1866 return true;
1867 }
1868 else
1869 {
1870 // so even though the ELSE node is non-static we can effectively replace
1871 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1872 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1873 return true;
1874 }
1875 }
1876 }
1877
1878 return true;
1879}
1880
1882{
1883 QString msg( u"CASE"_s );
1884 for ( WhenThen *cond : mConditions )
1885 {
1886 msg += u" WHEN %1 THEN %2"_s.arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1887 }
1888 if ( mElseExp )
1889 msg += u" ELSE %1"_s.arg( mElseExp->dump() );
1890 msg += " END"_L1;
1891 return msg;
1892}
1893
1895{
1896 if ( hasCachedStaticValue() )
1897 return QSet< QString >();
1898
1899 QSet<QString> lst;
1900 for ( WhenThen *cond : mConditions )
1901 {
1902 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1903 }
1904
1905 if ( mElseExp )
1906 lst += mElseExp->referencedColumns();
1907
1908 return lst;
1909}
1910
1912{
1913 QSet<QString> lst;
1914 for ( WhenThen *cond : mConditions )
1915 {
1916 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1917 }
1918
1919 if ( mElseExp )
1920 lst += mElseExp->referencedVariables();
1921
1922 return lst;
1923}
1924
1926{
1927 QSet<QString> lst;
1928 for ( WhenThen *cond : mConditions )
1929 {
1930 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1931 }
1932
1933 if ( mElseExp )
1934 lst += mElseExp->referencedFunctions();
1935
1936 return lst;
1937}
1938
1939QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1940{
1941 QList<const QgsExpressionNode *> lst;
1942 lst << this;
1943 for ( WhenThen *cond : mConditions )
1944 {
1945 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1946 }
1947
1948 if ( mElseExp )
1949 lst += mElseExp->nodes();
1950
1951 return lst;
1952}
1953
1955{
1956 for ( WhenThen *cond : mConditions )
1957 {
1958 if ( cond->mWhenExp->needsGeometry() ||
1959 cond->mThenExp->needsGeometry() )
1960 return true;
1961 }
1962
1963 return mElseExp && mElseExp->needsGeometry();
1964}
1965
1967{
1969 conditions.reserve( mConditions.size() );
1970 for ( WhenThen *wt : mConditions )
1971 conditions.append( wt->clone() );
1972
1973 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1974 cloneTo( copy );
1975 return copy;
1976}
1977
1979{
1980 for ( WhenThen *wt : mConditions )
1981 {
1982 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1983 return false;
1984 }
1985
1986 if ( mElseExp )
1987 return mElseExp->isStatic( parent, context );
1988
1989 return true;
1990}
1991
1993{
1994 if ( hasCachedStaticValue() )
1995 return QSet< QString >();
1996
1997 QSet<QString> lst( mNode->referencedColumns() );
1998 const QList< QgsExpressionNode * > nodeList = mList->list();
1999 for ( const QgsExpressionNode *n : nodeList )
2000 lst.unite( n->referencedColumns() );
2001 return lst;
2002}
2003
2005{
2006 QSet<QString> lst( mNode->referencedVariables() );
2007 const QList< QgsExpressionNode * > nodeList = mList->list();
2008 for ( const QgsExpressionNode *n : nodeList )
2009 lst.unite( n->referencedVariables() );
2010 return lst;
2011}
2012
2014{
2015 QSet<QString> lst( mNode->referencedFunctions() );
2016 const QList< QgsExpressionNode * > nodeList = mList->list();
2017 for ( const QgsExpressionNode *n : nodeList )
2018 lst.unite( n->referencedFunctions() );
2019 return lst;
2020}
2021
2022QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
2023{
2024 QList<const QgsExpressionNode *> lst;
2025 lst << this;
2026 const QList< QgsExpressionNode * > nodeList = mList->list();
2027 for ( const QgsExpressionNode *n : nodeList )
2028 lst += n->nodes();
2029 return lst;
2030}
2031
2032
2036
2041
2043{
2044 bool res = mNode->prepare( parent, context );
2045 res = res && mLowerBound->prepare( parent, context );
2046 res = res && mHigherBound->prepare( parent, context );
2047 return res;
2048}
2049
2051{
2052 const QVariant nodeVal = mNode->eval( parent, context );
2053 if ( QgsVariantUtils::isNull( nodeVal ) )
2054 {
2055 return QVariant();
2056 }
2057
2058 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
2059
2061 const QVariant lowBoundValue = lowBound.eval( parent, context );
2062 const bool lowBoundBool { lowBoundValue.toBool() };
2063
2064 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
2065 {
2066 return QVariant( mNegate );
2067 }
2068
2070 const QVariant highBoundValue = highBound.eval( parent, context );
2071
2072 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2073 {
2074 return QVariant();
2075 }
2076
2077 const bool highBoundBool { highBoundValue.toBool() };
2078
2079 // We already checked if both are nulls
2080 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2081 {
2082
2083 // In this case we can return a boolean
2084 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
2085 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
2086 {
2087 return QVariant( mNegate );
2088 }
2089
2090 // Indetermined
2091 return QVariant();
2092
2093 }
2094
2095 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
2096 {
2097 return QVariant( mNegate );
2098 }
2099
2100 const bool res { lowBoundBool &&highBoundBool };
2101 return mNegate ? QVariant( ! res ) : QVariant( res );
2102
2103}
2104
2106{
2107 return u"%1 %2 %3 AND %4"_s.arg( mNode->dump(), mNegate ? u"NOT BETWEEN"_s : u"BETWEEN"_s, mLowerBound->dump(), mHigherBound->dump() );
2108}
2109
2111{
2112 QSet<QString> lst( mNode->referencedVariables() );
2113 lst.unite( mLowerBound->referencedVariables() );
2114 lst.unite( mHigherBound->referencedVariables() );
2115 return lst;
2116}
2117
2119{
2120 QSet<QString> lst( mNode->referencedFunctions() );
2121 lst.unite( mLowerBound->referencedFunctions() );
2122 lst.unite( mHigherBound->referencedFunctions() );
2123 return lst;
2124}
2125
2126QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2127{
2128 return { this, mLowerBound.get(), mHigherBound.get() };
2129}
2130
2132{
2133 QSet<QString> lst( mNode->referencedColumns() );
2134 lst.unite( mLowerBound->referencedColumns() );
2135 lst.unite( mHigherBound->referencedColumns() );
2136 return lst;
2137}
2138
2140{
2141 if ( mNode->needsGeometry() )
2142 return true;
2143
2144 if ( mLowerBound->needsGeometry() )
2145 return true;
2146
2147 if ( mHigherBound->needsGeometry() )
2148 return true;
2149
2150 return false;
2151}
2152
2154{
2155 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2156 cloneTo( copy );
2157 return copy;
2158}
2159
2161{
2162 if ( !mNode->isStatic( parent, context ) )
2163 return false;
2164
2165 if ( !mLowerBound->isStatic( parent, context ) )
2166 return false;
2167
2168 if ( !mHigherBound->isStatic( parent, context ) )
2169 return false;
2170
2171 return true;
2172}
2173
2175{
2176 return mLowerBound.get();
2177}
2178
2180{
2181 return mHigherBound.get();
2182}
2183
2185{
2186 return mNegate;
2187}
2188
2194
2200
2202{
2203 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2204}
2205
2207{
2208 return BINARY_OPERATOR_TEXT[mOp];
2209}
2210
2211//
2212
2214{
2215 const QVariant container = mContainer->eval( parent, context );
2217 const QVariant index = mIndex->eval( parent, context );
2219
2220 switch ( container.userType() )
2221 {
2222 case QMetaType::Type::QVariantMap:
2223 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2224
2225 case QMetaType::Type::QVariantList:
2226 case QMetaType::Type::QStringList:
2227 {
2228 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2229 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2230 if ( pos >= list.length() || pos < -list.length() )
2231 {
2232 return QVariant();
2233 }
2234 if ( pos < 0 )
2235 {
2236 // negative indices are from back of list
2237 pos += list.length();
2238 }
2239
2240 return list.at( pos );
2241 }
2242
2243 default:
2245 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2246 return QVariant();
2247 }
2248}
2249
2254
2256{
2257 bool resC = mContainer->prepare( parent, context );
2258 bool resV = mIndex->prepare( parent, context );
2259 return resC && resV;
2260}
2261
2263{
2264 return u"%1[%2]"_s.arg( mContainer->dump(), mIndex->dump() );
2265}
2266
2268{
2269 if ( hasCachedStaticValue() )
2270 return QSet< QString >();
2271
2272 return mContainer->referencedColumns() + mIndex->referencedColumns();
2273}
2274
2276{
2277 return mContainer->referencedVariables() + mIndex->referencedVariables();
2278}
2279
2281{
2282 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2283}
2284
2285QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2286{
2287 QList<const QgsExpressionNode *> lst;
2288 lst << this;
2289 lst += mContainer->nodes() + mIndex->nodes();
2290 return lst;
2291}
2292
2294{
2295 return mContainer->needsGeometry() || mIndex->needsGeometry();
2296}
2297
2299{
2300 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2301 cloneTo( copy );
2302 return copy;
2303}
2304
2306{
2307 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2308}
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.
An 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.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
bool negate() const
Returns true if the predicate is an exclusion test (NOT BETWEEN).
QgsExpressionNode * lowerBound() const
Returns the lower bound expression node of the range.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * higherBound() const
Returns the higher bound expression node of the range.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeBetweenOperator(QgsExpressionNode *node, QgsExpressionNode *nodeLowerBound, QgsExpressionNode *nodeHigherBound, bool negate=false)
This node tests if the result of node is between the result of nodeLowerBound and nodeHigherBound nod...
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
A binary expression operator, which operates on two values.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
bool leftAssociative() const
Returns true if the operator is left-associative.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
int precedence() const
Returns the precedence index for the operator.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
QgsExpressionNodeBinaryOperator(QgsExpressionNodeBinaryOperator::BinaryOperator op, QgsExpressionNode *opLeft, QgsExpressionNode *opRight)
Binary combination of the left and the right with op.
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 its value from a feature's field.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNodeColumnRef(const QString &name)
Constructor for QgsExpressionNodeColumnRef, referencing the column with the specified name.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
Represents a "WHEN... THEN..." portation of a CASE WHEN clause in an expression.
WhenThen(QgsExpressionNode *whenExp, QgsExpressionNode *thenExp)
A combination of when and then.
QgsExpressionNode * thenExp() const
The expression node that makes the THEN result part of the condition.
QgsExpressionNode * whenExp() const
The expression that makes the WHEN part of the condition.
QgsExpressionNodeCondition::WhenThen * clone() const
Gets a deep copy of this WhenThen combination.
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.
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
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.
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.
QgsExpressionNodeInOperator(QgsExpressionNode *node, QgsExpressionNode::NodeList *list, bool notin=false)
This node tests if the result of node is in the result of list.
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.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsExpressionNodeIndexOperator(QgsExpressionNode *container, QgsExpressionNode *index)
Constructor for QgsExpressionNodeIndexOperator.
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.
QgsExpressionNode * index() const
Returns the index node, representing an array element index or map key.
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.
QgsExpressionNode * container() const
Returns the container node, representing an array or map value.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
An expression node for literal values.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString valueAsString() const
Returns a string representation of the node's literal value.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QVariant value() const
The value of the literal.
QgsExpressionNodeLiteral(const QVariant &value)
Constructor for QgsExpressionNodeLiteral, with the specified literal value.
A unary node is either negative as in boolean (not) or as in numbers (minus).
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNodeUnaryOperator::UnaryOperator op() const
Returns the unary operator.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeUnaryOperator(QgsExpressionNodeUnaryOperator::UnaryOperator op, QgsExpressionNode *operand)
A node unary operator is modifying the value of operand by negating it with op.
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.
virtual QString dump() const
Returns a string dump of the expression node.
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.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
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.
bool mHasCachedValue
true if the node has a static, precalculated value.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
QgsExpressionNode()=default
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.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
Handles 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:60
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:50
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.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6817
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6900
bool compareOp(T diff, QgsExpressionNodeBinaryOperator::BinaryOperator op)
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.