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