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