QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 : [email protected]
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 
16 #include "qgsexpressionnodeimpl.h"
17 #include "qgsexpressionutils.h"
18 #include "qgsexpression.h"
19 
20 #include "qgsgeometry.h"
21 #include "qgsfeaturerequest.h"
22 #include "qgsstringutils.h"
23 
24 #include <QRegularExpression>
25 
26 const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
27 {
28  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
29  "OR", "AND",
30  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
31  "+", "-", "*", "/", "//", "%", "^",
32  "||"
33 };
34 
35 const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
36 {
37  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
38  "NOT", "-"
39 };
40 
42 {
43  bool needs = false;
44  const QList< QgsExpressionNode * > nodeList = mList->list();
45  for ( QgsExpressionNode *n : nodeList )
46  needs |= n->needsGeometry();
47  return needs;
48 }
49 
51 {
52  qDeleteAll( mList );
53 }
54 
56 {
57  mList.append( node->node );
58  mNameList.append( cleanNamedNodeName( node->name ) );
59  mHasNamedNodes = true;
60  delete node;
61 }
62 
64 {
65  NodeList *nl = new NodeList;
66  for ( QgsExpressionNode *node : mList )
67  {
68  nl->mList.append( node->clone() );
69  }
70  nl->mNameList = mNameList;
71 
72  return nl;
73 }
74 
76 {
77  QString msg;
78  bool first = true;
79  for ( QgsExpressionNode *n : mList )
80  {
81  if ( !first ) msg += QLatin1String( ", " );
82  else first = false;
83  msg += n->dump();
84  }
85  return msg;
86 }
87 
88 QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
89 {
90  QString cleaned = name.toLower();
91 
92  // upgrade older argument names to standard versions
93  if ( cleaned == QLatin1String( "geom" ) )
94  cleaned = QStringLiteral( "geometry" );
95  else if ( cleaned == QLatin1String( "val" ) )
96  cleaned = QStringLiteral( "value" );
97  else if ( cleaned == QLatin1String( "geometry a" ) )
98  cleaned = QStringLiteral( "geometry1" );
99  else if ( cleaned == QLatin1String( "geometry b" ) )
100  cleaned = QStringLiteral( "geometry2" );
101 
102  return cleaned;
103 }
104 
105 
106 //
107 
109 {
110  QVariant val = mOperand->eval( parent, context );
112 
113  switch ( mOp )
114  {
115  case uoNot:
116  {
117  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
119  return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
120  }
121 
122  case uoMinus:
123  if ( QgsExpressionUtils::isIntSafe( val ) )
124  return QVariant( - QgsExpressionUtils::getIntValue( val, parent ) );
125  else if ( QgsExpressionUtils::isDoubleSafe( val ) )
126  return QVariant( - QgsExpressionUtils::getDoubleValue( val, parent ) );
127  else
128  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
129  }
130  return QVariant();
131 }
132 
134 {
135  return ntUnaryOperator;
136 }
137 
139 {
140  return mOperand->prepare( parent, context );
141 }
142 
144 {
145  if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand ) )
146  return QStringLiteral( "%1 ( %2 )" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
147  else
148  return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
149 }
150 
152 {
153  if ( hasCachedStaticValue() )
154  return QSet< QString >();
155 
156  return mOperand->referencedColumns();
157 }
158 
160 {
161  return mOperand->referencedVariables();
162 }
163 
165 {
166  return mOperand->referencedFunctions();
167 }
168 
169 QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
170 {
171  QList<const QgsExpressionNode *> lst;
172  lst.append( this );
173  lst += mOperand->nodes();
174  return lst;
175 }
176 
178 {
179  return mOperand->needsGeometry();
180 }
181 
183 {
184  QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
185  cloneTo( copy );
186  return copy;
187 }
188 
190 {
191  return mOperand->isStatic( parent, context );
192 }
193 
195 {
196  return UNARY_OPERATOR_TEXT[mOp];
197 }
198 
199 //
200 
202 {
203  QVariant vL = mOpLeft->eval( parent, context );
205 
206  if ( mOp == boAnd || mOp == boOr )
207  {
208  QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
210  if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
211  return TVL_False; // shortcut -- no need to evaluate right-hand side
212  if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
213  return TVL_True; // shortcut -- no need to evaluate right-hand side
214  }
215 
216  QVariant vR = mOpRight->eval( parent, context );
218 
219  switch ( mOp )
220  {
221  case boPlus:
222  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
223  {
224  QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
226  QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
228  return QVariant( sL + sR );
229  }
230  //intentional fall-through
232  case boMinus:
233  case boMul:
234  case boDiv:
235  case boMod:
236  {
237  if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
238  return QVariant();
239  else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
240  {
241  // both are integers - let's use integer arithmetic
242  qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
244  qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
246 
247  if ( mOp == boMod && iR == 0 )
248  return QVariant();
249 
250  return QVariant( computeInt( iL, iR ) );
251  }
252  else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
253  {
254  QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
256  QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
258  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
259  {
260  parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
261  return QVariant();
262  }
263  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
264  }
265  else if ( mOp == boPlus && ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
266  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
267  {
268  QDate date = QgsExpressionUtils::getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
270  QTime time = QgsExpressionUtils::getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
272  QDateTime dt = QDateTime( date, time );
273  return QVariant( dt );
274  }
275  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
276  {
277  QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
279  QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
281  return date1 - date2;
282  }
283  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
284  {
285  QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
287  QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
289  return time1 - time2;
290  }
291  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
292  {
293  QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
295  QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
297  return datetime1 - datetime2;
298  }
299  else
300  {
301  // general floating point arithmetic
302  double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
304  double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
306  if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
307  return QVariant(); // silently handle division by zero and return NULL
308  return QVariant( computeDouble( fL, fR ) );
309  }
310  }
311  case boIntDiv:
312  {
313  //integer division
314  double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
316  double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
318  if ( fR == 0. )
319  return QVariant(); // silently handle division by zero and return NULL
320  return QVariant( qlonglong( std::floor( fL / fR ) ) );
321  }
322  case boPow:
323  if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
324  return QVariant();
325  else
326  {
327  double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
329  double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
331  return QVariant( std::pow( fL, fR ) );
332  }
333 
334  case boAnd:
335  {
336  QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
338  return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
339  }
340 
341  case boOr:
342  {
343  QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
345  return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
346  }
347 
348  case boEQ:
349  case boNE:
350  case boLT:
351  case boGT:
352  case boLE:
353  case boGE:
354  if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
355  {
356  return TVL_Unknown;
357  }
358  else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
359  {
360  // verify that we have two lists
361  if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
362  return TVL_Unknown;
363 
364  // and search for not equal respective items
365  QVariantList lL = vL.toList();
366  QVariantList lR = vR.toList();
367  for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
368  {
369  if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
370  continue; // same behavior as PostgreSQL
371 
372  if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
373  {
374  switch ( mOp )
375  {
376  case boEQ:
377  return false;
378  case boNE:
379  return true;
380  case boLT:
381  case boLE:
382  return QgsExpressionUtils::isNull( lR.at( i ) );
383  case boGT:
384  case boGE:
385  return QgsExpressionUtils::isNull( lL.at( i ) );
386  default:
387  Q_ASSERT( false );
388  return TVL_Unknown;
389  }
390  }
391 
392  QgsExpressionNodeLiteral nL( lL.at( i ) );
393  QgsExpressionNodeLiteral nR( lR.at( i ) );
394  QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
395  QVariant eq = eqNode.eval( parent, context );
397  if ( eq == TVL_False )
398  {
399  // return the two items comparison
400  QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
401  QVariant v = node.eval( parent, context );
403  return v;
404  }
405  }
406 
407  // default to length comparison
408  switch ( mOp )
409  {
410  case boEQ:
411  return lL.length() == lR.length();
412  case boNE:
413  return lL.length() != lR.length();
414  case boLT:
415  return lL.length() < lR.length();
416  case boGT:
417  return lL.length() > lR.length();
418  case boLE:
419  return lL.length() <= lR.length();
420  case boGE:
421  return lL.length() >= lR.length();
422  default:
423  Q_ASSERT( false );
424  return TVL_Unknown;
425  }
426  }
427  else if ( ( vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime ) )
428  {
429  QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
431  QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
433 
434  // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
435  // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
436  // results (due to different hidden timezones), we force all datetime comparisons to treat
437  // all datetime values as having the same time zone
438  dL.setTimeSpec( Qt::UTC );
439  dR.setTimeSpec( Qt::UTC );
440 
441  return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
442  }
443  else if ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Date ) )
444  {
445  const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
447  const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
449  return compare( dR.daysTo( dL ) ) ? TVL_True : TVL_False;
450  }
451  else if ( ( vL.type() == QVariant::Time && vR.type() == QVariant::Time ) )
452  {
453  const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
455  const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
457  return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
458  }
459  else if ( ( vL.type() != QVariant::String || vR.type() != QVariant::String ) &&
460  QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
461  {
462  // do numeric comparison if both operators can be converted to numbers,
463  // and they aren't both string
464  double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
466  double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
468  return compare( fL - fR ) ? TVL_True : TVL_False;
469  }
470  // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
471  else if ( vL.canConvert< QgsInterval >() && vR.canConvert< QgsInterval >() )
472  {
473  double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
475  double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
477  return compare( fL - fR ) ? TVL_True : TVL_False;
478  }
479  else
480  {
481  // do string comparison otherwise
482  QString sL = QgsExpressionUtils::getStringValue( vL, parent );
484  QString sR = QgsExpressionUtils::getStringValue( vR, parent );
486  int diff = QString::compare( sL, sR );
487  return compare( diff ) ? TVL_True : TVL_False;
488  }
489 
490  case boIs:
491  case boIsNot:
492  if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
493  return ( mOp == boIs ? TVL_True : TVL_False );
494  else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
495  return ( mOp == boIs ? TVL_False : TVL_True );
496  else // both operators non-null
497  {
498  bool equal = false;
499  if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
500  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
501  {
502  double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
504  double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
506  equal = qgsDoubleNear( fL, fR );
507  }
508  else
509  {
510  QString sL = QgsExpressionUtils::getStringValue( vL, parent );
512  QString sR = QgsExpressionUtils::getStringValue( vR, parent );
514  equal = QString::compare( sL, sR ) == 0;
515  }
516  if ( equal )
517  return mOp == boIs ? TVL_True : TVL_False;
518  else
519  return mOp == boIs ? TVL_False : TVL_True;
520  }
521 
522  case boRegexp:
523  case boLike:
524  case boNotLike:
525  case boILike:
526  case boNotILike:
527  if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
528  return TVL_Unknown;
529  else
530  {
531  QString str = QgsExpressionUtils::getStringValue( vL, parent );
533  QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
535  // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
536  bool matches;
537  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
538  {
539  QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
540  // manage escape % and _
541  if ( esc_regexp.startsWith( '%' ) )
542  {
543  esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
544  }
545  const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
546  int pos = 0;
547  while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
548  {
549  esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
550  pos += 1;
551  }
552  const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
553  esc_regexp.replace( rx2, QStringLiteral( "%" ) );
554  if ( esc_regexp.startsWith( '_' ) )
555  {
556  esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
557  }
558  const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
559  pos = 0;
560  while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
561  {
562  esc_regexp.replace( pos + 1, 1, '.' );
563  pos += 1;
564  }
565  esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
566 
567  matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
568  }
569  else
570  {
571  matches = QRegularExpression( regexp ).match( str ).hasMatch();
572  }
573 
574  if ( mOp == boNotLike || mOp == boNotILike )
575  {
576  matches = !matches;
577  }
578 
579  return matches ? TVL_True : TVL_False;
580  }
581 
582  case boConcat:
583  if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
584  return QVariant();
585  else
586  {
587  QString sL = QgsExpressionUtils::getStringValue( vL, parent );
589  QString sR = QgsExpressionUtils::getStringValue( vR, parent );
591  return QVariant( sL + sR );
592  }
593  }
594  Q_ASSERT( false );
595  return QVariant();
596 }
597 
598 bool QgsExpressionNodeBinaryOperator::compare( double diff )
599 {
600  switch ( mOp )
601  {
602  case boEQ:
603  return qgsDoubleNear( diff, 0.0 );
604  case boNE:
605  return !qgsDoubleNear( diff, 0.0 );
606  case boLT:
607  return diff < 0;
608  case boGT:
609  return diff > 0;
610  case boLE:
611  return diff <= 0;
612  case boGE:
613  return diff >= 0;
614  default:
615  Q_ASSERT( false );
616  return false;
617  }
618 }
619 
620 qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
621 {
622  switch ( mOp )
623  {
624  case boPlus:
625  return x + y;
626  case boMinus:
627  return x - y;
628  case boMul:
629  return x * y;
630  case boDiv:
631  return x / y;
632  case boMod:
633  return x % y;
634  default:
635  Q_ASSERT( false );
636  return 0;
637  }
638 }
639 
640 QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
641 {
642  switch ( mOp )
643  {
644  case boPlus:
645  return d.addSecs( i->seconds() );
646  case boMinus:
647  return d.addSecs( -i->seconds() );
648  default:
649  Q_ASSERT( false );
650  return QDateTime();
651  }
652 }
653 
654 double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
655 {
656  switch ( mOp )
657  {
658  case boPlus:
659  return x + y;
660  case boMinus:
661  return x - y;
662  case boMul:
663  return x * y;
664  case boDiv:
665  return x / y;
666  case boMod:
667  return std::fmod( x, y );
668  default:
669  Q_ASSERT( false );
670  return 0;
671  }
672 }
673 
675 {
676  return ntBinaryOperator;
677 }
678 
680 {
681  bool resL = mOpLeft->prepare( parent, context );
682  bool resR = mOpRight->prepare( parent, context );
683  return resL && resR;
684 }
685 
687 {
688  // see left/right in qgsexpressionparser.yy
689  switch ( mOp )
690  {
691  case boOr:
692  return 1;
693 
694  case boAnd:
695  return 2;
696 
697  case boEQ:
698  case boNE:
699  case boLE:
700  case boGE:
701  case boLT:
702  case boGT:
703  case boRegexp:
704  case boLike:
705  case boILike:
706  case boNotLike:
707  case boNotILike:
708  case boIs:
709  case boIsNot:
710  return 3;
711 
712  case boPlus:
713  case boMinus:
714  return 4;
715 
716  case boMul:
717  case boDiv:
718  case boIntDiv:
719  case boMod:
720  return 5;
721 
722  case boPow:
723  return 6;
724 
725  case boConcat:
726  return 7;
727  }
728  Q_ASSERT( false && "unexpected binary operator" );
729  return -1;
730 }
731 
733 {
734  // see left/right in qgsexpressionparser.yy
735  switch ( mOp )
736  {
737  case boOr:
738  case boAnd:
739  case boEQ:
740  case boNE:
741  case boLE:
742  case boGE:
743  case boLT:
744  case boGT:
745  case boRegexp:
746  case boLike:
747  case boILike:
748  case boNotLike:
749  case boNotILike:
750  case boIs:
751  case boIsNot:
752  case boPlus:
753  case boMinus:
754  case boMul:
755  case boDiv:
756  case boIntDiv:
757  case boMod:
758  case boConcat:
759  return true;
760 
761  case boPow:
762  return false;
763  }
764  Q_ASSERT( false && "unexpected binary operator" );
765  return false;
766 }
767 
769 {
770  QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft );
771  QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
772  QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
773 
774  QString rdump( mOpRight->dump() );
775 
776  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
777  if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
778  {
779  rdump.prepend( '(' ).append( ')' );
780  }
781 
782  QString fmt;
783  if ( leftAssociative() )
784  {
785  fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
786  fmt += QLatin1String( " %2 " );
787  fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
788  }
789  else
790  {
791  fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
792  fmt += QLatin1String( " %2 " );
793  fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
794  }
795 
796  return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
797 }
798 
800 {
801  if ( hasCachedStaticValue() )
802  return QSet< QString >();
803 
804  return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
805 }
806 
808 {
809  return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
810 }
811 
813 {
814  return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
815 }
816 
817 QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
818 {
819  QList<const QgsExpressionNode *> lst;
820  lst << this;
821  lst += mOpLeft->nodes() + mOpRight->nodes();
822  return lst;
823 }
824 
826 {
827  return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
828 }
829 
831 {
832  QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
833  cloneTo( copy );
834  return copy;
835 }
836 
838 {
839  const bool leftStatic = mOpLeft->isStatic( parent, context );
840  const bool rightStatic = mOpRight->isStatic( parent, context );
841 
842  if ( leftStatic && rightStatic )
843  return true;
844 
845  // special logic for certain ops...
846  switch ( mOp )
847  {
849  {
850  // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
851  // of the value of the other node!
852  if ( leftStatic )
853  {
854  mOpLeft->prepare( parent, context );
855  if ( mOpLeft->hasCachedStaticValue() )
856  {
857  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
858  if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
859  {
860  mCachedStaticValue = true;
861  mHasCachedValue = true;
862  return true;
863  }
864  }
865  }
866  else if ( rightStatic )
867  {
868  mOpRight->prepare( parent, context );
869  if ( mOpRight->hasCachedStaticValue() )
870  {
871  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
872  if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
873  {
874  mCachedStaticValue = true;
875  mHasCachedValue = true;
876  return true;
877  }
878  }
879  }
880 
881  break;
882  }
884  {
885  // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
886  // of the value of the other node!
887 
888  if ( leftStatic )
889  {
890  mOpLeft->prepare( parent, context );
891  if ( mOpLeft->hasCachedStaticValue() )
892  {
893  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
894  if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
895  {
896  mCachedStaticValue = false;
897  mHasCachedValue = true;
898  return true;
899  }
900  }
901  }
902  else if ( rightStatic )
903  {
904  mOpRight->prepare( parent, context );
905  if ( mOpRight->hasCachedStaticValue() )
906  {
907  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
908  if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
909  {
910  mCachedStaticValue = false;
911  mHasCachedValue = true;
912  return true;
913  }
914  }
915  }
916 
917  break;
918  }
919 
941  break;
942  }
943 
944  return false;
945 }
946 
947 //
948 
950 {
951  if ( mList->count() == 0 )
952  return mNotIn ? TVL_True : TVL_False;
953  QVariant v1 = mNode->eval( parent, context );
955  if ( QgsExpressionUtils::isNull( v1 ) )
956  return TVL_Unknown;
957 
958  bool listHasNull = false;
959 
960  const QList< QgsExpressionNode * > nodeList = mList->list();
961  for ( QgsExpressionNode *n : nodeList )
962  {
963  QVariant v2 = n->eval( parent, context );
965  if ( QgsExpressionUtils::isNull( v2 ) )
966  listHasNull = true;
967  else
968  {
969  bool equal = false;
970  // check whether they are equal
971  if ( ( v1.type() != QVariant::String || v2.type() != QVariant::String ) &&
972  QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
973  {
974  // do numeric comparison if both operators can be converted to numbers,
975  // and they aren't both string
976  double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
978  double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
980  equal = qgsDoubleNear( f1, f2 );
981  }
982  else
983  {
984  QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
986  QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
988  equal = QString::compare( s1, s2 ) == 0;
989  }
990 
991  if ( equal ) // we know the result
992  return mNotIn ? TVL_False : TVL_True;
993  }
994  }
995 
996  // item not found
997  if ( listHasNull )
998  return TVL_Unknown;
999  else
1000  return mNotIn ? TVL_True : TVL_False;
1001 }
1002 
1004 {
1005  delete mNode;
1006  delete mList;
1007 }
1008 
1010 {
1011  return ntInOperator;
1012 }
1013 
1015 {
1016  bool res = mNode->prepare( parent, context );
1017  const QList< QgsExpressionNode * > nodeList = mList->list();
1018  for ( QgsExpressionNode *n : nodeList )
1019  {
1020  res = res && n->prepare( parent, context );
1021  }
1022  return res;
1023 }
1024 
1026 {
1027  return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1028 }
1029 
1031 {
1032  QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1033  cloneTo( copy );
1034  return copy;
1035 }
1036 
1038 {
1039  if ( !mNode->isStatic( parent, context ) )
1040  return false;
1041 
1042  const QList< QgsExpressionNode * > nodeList = mList->list();
1043  for ( QgsExpressionNode *n : nodeList )
1044  {
1045  if ( !n->isStatic( parent, context ) )
1046  return false;
1047  }
1048 
1049  return true;
1050 }
1051 
1052 //
1053 
1055 {
1056  QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1057  QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1058 
1059  QVariant res = fd->run( mArgs, context, parent, this );
1061 
1062  // everything went fine
1063  return res;
1064 }
1065 
1067  : mFnIndex( fnIndex )
1068 {
1069  const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1070  if ( functionParams.isEmpty() )
1071  {
1072  // function does not support parameters
1073  mArgs = args;
1074  }
1075  else if ( !args )
1076  {
1077  // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1078  mArgs = new NodeList();
1079  for ( const QgsExpressionFunction::Parameter &param : functionParams )
1080  {
1081  // insert default value for QgsExpressionFunction::Parameter
1082  mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1083  }
1084  }
1085  else
1086  {
1087  mArgs = new NodeList();
1088 
1089  int idx = 0;
1090  //first loop through unnamed arguments
1091  while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
1092  {
1093  mArgs->append( args->list().at( idx )->clone() );
1094  idx++;
1095  }
1096 
1097  //next copy named QgsExpressionFunction::Parameters in order expected by function
1098  for ( ; idx < functionParams.count(); ++idx )
1099  {
1100  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1101  if ( nodeIdx < 0 )
1102  {
1103  //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1104  mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
1105  }
1106  else
1107  {
1108  mArgs->append( args->list().at( nodeIdx )->clone() );
1109  }
1110  }
1111 
1112  delete args;
1113  }
1114 }
1115 
1117 {
1118  delete mArgs;
1119 }
1120 
1122 {
1123  return ntFunction;
1124 }
1125 
1127 {
1128  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1129 
1130  bool res = fd->prepare( this, parent, context );
1131  if ( mArgs && !fd->lazyEval() )
1132  {
1133  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1134  for ( QgsExpressionNode *n : nodeList )
1135  {
1136  res = res && n->prepare( parent, context );
1137  }
1138  }
1139  return res;
1140 }
1141 
1143 {
1144  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1145  if ( fd->params() == 0 )
1146  return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1147  else
1148  return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1149 }
1150 
1152 {
1153  if ( hasCachedStaticValue() )
1154  return QSet< QString >();
1155 
1156  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1157  QSet<QString> functionColumns = fd->referencedColumns( this );
1158 
1159  if ( !mArgs )
1160  {
1161  //no referenced columns in arguments, just return function's referenced columns
1162  return functionColumns;
1163  }
1164 
1165  int paramIndex = 0;
1166  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1167  for ( QgsExpressionNode *n : nodeList )
1168  {
1169  if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1170  functionColumns.unite( n->referencedColumns() );
1171  paramIndex++;
1172  }
1173 
1174  return functionColumns;
1175 }
1176 
1178 {
1179  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1180  if ( fd->name() == QLatin1String( "var" ) )
1181  {
1182  if ( !mArgs->list().isEmpty() )
1183  {
1184  QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1185  if ( var )
1186  return QSet<QString>() << var->value().toString();
1187  }
1188  return QSet<QString>() << QString();
1189  }
1190  else
1191  {
1192  QSet<QString> functionVariables = QSet<QString>();
1193 
1194  if ( !mArgs )
1195  return functionVariables;
1196 
1197  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1198  for ( QgsExpressionNode *n : nodeList )
1199  {
1200  functionVariables.unite( n->referencedVariables() );
1201  }
1202 
1203  return functionVariables;
1204  }
1205 }
1206 
1208 {
1209  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1210  QSet<QString> functions = QSet<QString>();
1211  functions.insert( fd->name() );
1212 
1213  if ( !mArgs )
1214  return functions;
1215 
1216  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1217  for ( QgsExpressionNode *n : nodeList )
1218  {
1219  functions.unite( n->referencedFunctions() );
1220  }
1221  return functions;
1222 }
1223 
1224 QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1225 {
1226  QList<const QgsExpressionNode *> lst;
1227  lst << this;
1228  if ( !mArgs )
1229  return lst;
1230 
1231  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1232  for ( QgsExpressionNode *n : nodeList )
1233  {
1234  lst += n->nodes();
1235  }
1236  return lst;
1237 }
1238 
1240 {
1241  bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1242  if ( mArgs )
1243  {
1244  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1245  for ( QgsExpressionNode *n : nodeList )
1246  needs |= n->needsGeometry();
1247  }
1248  return needs;
1249 }
1250 
1252 {
1253  QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1254  cloneTo( copy );
1255  return copy;
1256 }
1257 
1259 {
1260  return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1261 }
1262 
1264 {
1265  if ( !args || !args->hasNamedNodes() )
1266  return true;
1267 
1268  const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1269  if ( functionParams.isEmpty() )
1270  {
1271  error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1272  return false;
1273  }
1274  else
1275  {
1276  QSet< int > providedArgs;
1277  QSet< int > handledArgs;
1278  int idx = 0;
1279  //first loop through unnamed arguments
1280  while ( args->names().at( idx ).isEmpty() )
1281  {
1282  providedArgs << idx;
1283  handledArgs << idx;
1284  idx++;
1285  }
1286 
1287  //next check named QgsExpressionFunction::Parameters
1288  for ( ; idx < functionParams.count(); ++idx )
1289  {
1290  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1291  if ( nodeIdx < 0 )
1292  {
1293  if ( !functionParams.at( idx ).optional() )
1294  {
1295  error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1296  return false;
1297  }
1298  }
1299  else
1300  {
1301  if ( providedArgs.contains( idx ) )
1302  {
1303  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1304  return false;
1305  }
1306  }
1307  providedArgs << idx;
1308  handledArgs << nodeIdx;
1309  }
1310 
1311  //last check for bad names
1312  idx = 0;
1313  const QStringList nameList = args->names();
1314  for ( const QString &name : nameList )
1315  {
1316  if ( !name.isEmpty() && !functionParams.contains( name ) )
1317  {
1318  error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1319  return false;
1320  }
1321  if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1322  {
1323  int functionIdx = functionParams.indexOf( name );
1324  if ( providedArgs.contains( functionIdx ) )
1325  {
1326  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1327  return false;
1328  }
1329  }
1330  idx++;
1331  }
1332 
1333  }
1334  return true;
1335 }
1336 
1337 //
1338 
1340 {
1341  Q_UNUSED( context )
1342  Q_UNUSED( parent )
1343  return mValue;
1344 }
1345 
1347 {
1348  return ntLiteral;
1349 }
1350 
1352 {
1353  Q_UNUSED( parent )
1354  Q_UNUSED( context )
1355  return true;
1356 }
1357 
1358 
1360 {
1361  if ( mValue.isNull() )
1362  return QStringLiteral( "NULL" );
1363 
1364  switch ( mValue.type() )
1365  {
1366  case QVariant::Int:
1367  return QString::number( mValue.toInt() );
1368  case QVariant::Double:
1369  return QString::number( mValue.toDouble() );
1370  case QVariant::LongLong:
1371  return QString::number( mValue.toLongLong() );
1372  case QVariant::String:
1373  return QgsExpression::quotedString( mValue.toString() );
1374  case QVariant::Bool:
1375  return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1376  default:
1377  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1378  }
1379 }
1380 
1382 {
1383  return valueAsString();
1384 }
1385 
1387 {
1388  return QSet<QString>();
1389 }
1390 
1392 {
1393  return QSet<QString>();
1394 }
1395 
1397 {
1398  return QSet<QString>();
1399 }
1400 
1401 QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1402 {
1403  QList<const QgsExpressionNode *> lst;
1404  lst << this;
1405  return lst;
1406 }
1407 
1409 {
1410  return false;
1411 }
1412 
1414 {
1415  QgsExpressionNodeLiteral *copy = new QgsExpressionNodeLiteral( mValue );
1416  cloneTo( copy );
1417  return copy;
1418 }
1419 
1421 {
1422  Q_UNUSED( context )
1423  Q_UNUSED( parent )
1424  return true;
1425 }
1426 
1427 //
1428 
1430 {
1431  Q_UNUSED( parent )
1432  int index = mIndex;
1433 
1434  if ( index < 0 )
1435  {
1436  // have not yet found field index - first check explicitly set fields collection
1437  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1438  {
1439  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1440  index = fields.lookupField( mName );
1441  }
1442  }
1443 
1444  if ( context )
1445  {
1446  QgsFeature feature = context->feature();
1447  if ( feature.isValid() )
1448  {
1449  if ( index >= 0 )
1450  return feature.attribute( index );
1451  else
1452  return feature.attribute( mName );
1453  }
1454  else
1455  {
1456  parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1457  }
1458  }
1459  if ( index < 0 )
1460  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1461  return QVariant();
1462 }
1463 
1465 {
1466  return ntColumnRef;
1467 }
1468 
1470 {
1471  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1472  return false;
1473 
1474  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1475 
1476  mIndex = fields.lookupField( mName );
1477 
1478  if ( mIndex == -1 && context->hasFeature() )
1479  {
1480  mIndex = context->feature().fieldNameIndex( mName );
1481  }
1482 
1483  if ( mIndex == -1 )
1484  {
1485  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1486  return false;
1487  }
1488  return true;
1489 }
1490 
1492 {
1493  const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
1494  const QRegularExpressionMatch match = re.match( mName );
1495  return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1496 }
1497 
1499 {
1500  return QSet<QString>() << mName;
1501 }
1502 
1504 {
1505  return QSet<QString>();
1506 }
1507 
1509 {
1510  return QSet<QString>();
1511 }
1512 
1513 QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1514 {
1515  QList<const QgsExpressionNode *> result;
1516  result << this;
1517  return result;
1518 }
1519 
1521 {
1522  return false;
1523 }
1524 
1526 {
1528  cloneTo( copy );
1529  return copy;
1530 }
1531 
1533 {
1534  Q_UNUSED( context )
1535  Q_UNUSED( parent )
1536  return false;
1537 }
1538 
1539 //
1540 
1542  : mConditions( *conditions )
1543  , mElseExp( elseExp )
1544 {
1545  delete conditions;
1546 }
1547 
1549 {
1550  delete mElseExp;
1551  qDeleteAll( mConditions );
1552 }
1553 
1555 {
1556  return ntCondition;
1557 }
1558 
1560 {
1561  for ( WhenThen *cond : std::as_const( mConditions ) )
1562  {
1563  QVariant vWhen = cond->mWhenExp->eval( parent, context );
1564  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1566  if ( tvl == QgsExpressionUtils::True )
1567  {
1568  QVariant vRes = cond->mThenExp->eval( parent, context );
1570  return vRes;
1571  }
1572  }
1573 
1574  if ( mElseExp )
1575  {
1576  QVariant vElse = mElseExp->eval( parent, context );
1578  return vElse;
1579  }
1580 
1581  // return NULL if no condition is matching
1582  return QVariant();
1583 }
1584 
1586 {
1587  bool foundAnyNonStaticConditions = false;
1588  for ( WhenThen *cond : std::as_const( mConditions ) )
1589  {
1590  const bool res = cond->mWhenExp->prepare( parent, context )
1591  && cond->mThenExp->prepare( parent, context );
1592  if ( !res )
1593  return false;
1594 
1595  foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1596  if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1597  {
1598  // 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
1599  // value, and the static value for this WHEN clause is True.
1600  if ( cond->mThenExp->hasCachedStaticValue() )
1601  {
1602  // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1603  mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1604  mHasCachedValue = true;
1605  return true;
1606  }
1607  else
1608  {
1609  // 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
1610  // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1611  mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1612  return true;
1613  }
1614  }
1615  }
1616 
1617  if ( mElseExp )
1618  {
1619  const bool res = mElseExp->prepare( parent, context );
1620  if ( !res )
1621  return false;
1622 
1623  if ( !foundAnyNonStaticConditions )
1624  {
1625  // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1626  if ( mElseExp->hasCachedStaticValue() )
1627  {
1628  mCachedStaticValue = mElseExp->cachedStaticValue();
1629  mHasCachedValue = true;
1630  return true;
1631  }
1632  else
1633  {
1634  // so even though the ELSE node is non-static we can effectively replace
1635  // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1636  mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1637  return true;
1638  }
1639  }
1640  }
1641 
1642  return true;
1643 }
1644 
1646 {
1647  QString msg( QStringLiteral( "CASE" ) );
1648  for ( WhenThen *cond : mConditions )
1649  {
1650  msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1651  }
1652  if ( mElseExp )
1653  msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1654  msg += QLatin1String( " END" );
1655  return msg;
1656 }
1657 
1659 {
1660  if ( hasCachedStaticValue() )
1661  return QSet< QString >();
1662 
1663  QSet<QString> lst;
1664  for ( WhenThen *cond : mConditions )
1665  {
1666  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1667  }
1668 
1669  if ( mElseExp )
1670  lst += mElseExp->referencedColumns();
1671 
1672  return lst;
1673 }
1674 
1676 {
1677  QSet<QString> lst;
1678  for ( WhenThen *cond : mConditions )
1679  {
1680  lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1681  }
1682 
1683  if ( mElseExp )
1684  lst += mElseExp->referencedVariables();
1685 
1686  return lst;
1687 }
1688 
1690 {
1691  QSet<QString> lst;
1692  for ( WhenThen *cond : mConditions )
1693  {
1694  lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1695  }
1696 
1697  if ( mElseExp )
1698  lst += mElseExp->referencedFunctions();
1699 
1700  return lst;
1701 }
1702 
1703 QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1704 {
1705  QList<const QgsExpressionNode *> lst;
1706  lst << this;
1707  for ( WhenThen *cond : mConditions )
1708  {
1709  lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1710  }
1711 
1712  if ( mElseExp )
1713  lst += mElseExp->nodes();
1714 
1715  return lst;
1716 }
1717 
1719 {
1720  for ( WhenThen *cond : mConditions )
1721  {
1722  if ( cond->mWhenExp->needsGeometry() ||
1723  cond->mThenExp->needsGeometry() )
1724  return true;
1725  }
1726 
1727  return mElseExp && mElseExp->needsGeometry();
1728 }
1729 
1731 {
1733  conditions.reserve( mConditions.size() );
1734  for ( WhenThen *wt : mConditions )
1735  conditions.append( wt->clone() );
1736 
1737  QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1738  cloneTo( copy );
1739  return copy;
1740 }
1741 
1743 {
1744  for ( WhenThen *wt : mConditions )
1745  {
1746  if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1747  return false;
1748  }
1749 
1750  if ( mElseExp )
1751  return mElseExp->isStatic( parent, context );
1752 
1753  return true;
1754 }
1755 
1757 {
1758  if ( hasCachedStaticValue() )
1759  return QSet< QString >();
1760 
1761  QSet<QString> lst( mNode->referencedColumns() );
1762  const QList< QgsExpressionNode * > nodeList = mList->list();
1763  for ( const QgsExpressionNode *n : nodeList )
1764  lst.unite( n->referencedColumns() );
1765  return lst;
1766 }
1767 
1769 {
1770  QSet<QString> lst( mNode->referencedVariables() );
1771  const QList< QgsExpressionNode * > nodeList = mList->list();
1772  for ( const QgsExpressionNode *n : nodeList )
1773  lst.unite( n->referencedVariables() );
1774  return lst;
1775 }
1776 
1778 {
1779  QSet<QString> lst( mNode->referencedFunctions() );
1780  const QList< QgsExpressionNode * > nodeList = mList->list();
1781  for ( const QgsExpressionNode *n : nodeList )
1782  lst.unite( n->referencedFunctions() );
1783  return lst;
1784 }
1785 
1786 QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1787 {
1788  QList<const QgsExpressionNode *> lst;
1789  lst << this;
1790  const QList< QgsExpressionNode * > nodeList = mList->list();
1791  for ( const QgsExpressionNode *n : nodeList )
1792  lst += n->nodes();
1793  return lst;
1794 }
1795 
1797  : mWhenExp( whenExp )
1798  , mThenExp( thenExp )
1799 {
1800 }
1801 
1803 {
1804  delete mWhenExp;
1805  delete mThenExp;
1806 }
1807 
1809 {
1810  return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1811 }
1812 
1814 {
1815  return BINARY_OPERATOR_TEXT[mOp];
1816 }
1817 
1818 //
1819 
1821 {
1822  const QVariant container = mContainer->eval( parent, context );
1824  const QVariant index = mIndex->eval( parent, context );
1826 
1827  switch ( container.type() )
1828  {
1829  case QVariant::Map:
1830  return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1831 
1832  case QVariant::List:
1833  case QVariant::StringList:
1834  {
1835  const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
1836  qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
1837  if ( pos >= list.length() || pos < -list.length() )
1838  {
1839  return QVariant();
1840  }
1841  if ( pos < 0 )
1842  {
1843  // negative indices are from back of list
1844  pos += list.length();
1845  }
1846 
1847  return list.at( pos );
1848  }
1849 
1850  default:
1851  if ( !container.isNull() )
1852  parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
1853  return QVariant();
1854  }
1855 }
1856 
1858 {
1859  return ntIndexOperator;
1860 }
1861 
1863 {
1864  bool resC = mContainer->prepare( parent, context );
1865  bool resV = mIndex->prepare( parent, context );
1866  return resC && resV;
1867 }
1868 
1870 {
1871  return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
1872 }
1873 
1875 {
1876  if ( hasCachedStaticValue() )
1877  return QSet< QString >();
1878 
1879  return mContainer->referencedColumns() + mIndex->referencedColumns();
1880 }
1881 
1883 {
1884  return mContainer->referencedVariables() + mIndex->referencedVariables();
1885 }
1886 
1888 {
1889  return mContainer->referencedFunctions() + mIndex->referencedFunctions();
1890 }
1891 
1892 QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
1893 {
1894  QList<const QgsExpressionNode *> lst;
1895  lst << this;
1896  lst += mContainer->nodes() + mIndex->nodes();
1897  return lst;
1898 }
1899 
1901 {
1902  return mContainer->needsGeometry() || mIndex->needsGeometry();
1903 }
1904 
1906 {
1907  QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
1908  cloneTo( copy );
1909  return copy;
1910 }
1911 
1913 {
1914  return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
1915 }
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.
A abstract base class for defining QgsExpression functions.
QList< QgsExpressionFunction::Parameter > ParameterList
List of parameters, used for function definition.
int params() const
The number of parameters this function takes.
bool lazyEval() const
true if this function should use lazy evaluation.
QString name() const
The name of the function.
virtual QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)
Evaluates the function, first evaluating all required arguments before passing them to the function's...
const QgsExpressionFunction::ParameterList & parameters() const
Returns the list of named parameters for the function, if set.
virtual QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const
Returns a set of field names which are required for this function.
virtual bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
This will be called during the prepare step() of an expression if it is not static.
A binary expression operator, which operates on two values.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
bool leftAssociative() const
Returns true if the operator is left-associative.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
int precedence() const
Returns the precedence index for the operator.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
An expression node which takes it value from a feature's field.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
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.
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.
A indexing expression operator, which allows use of square brackets [] to reference map and array ite...
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
An expression node for literal values.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString valueAsString() const
Returns a string representation of the node's literal value.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QVariant value() const
The value of the literal.
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.
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.
virtual QList< const QgsExpressionNode * > nodes() const =0
Returns a list of all nodes which are used in this expression.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
virtual QString dump() const =0
Dump this node into a serialized (part) of an expression.
QVariant eval(QgsExpression *parent, const QgsExpressionContext *context)
Evaluate this node with the given context and parent.
virtual bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const =0
Returns true if this node can be evaluated for a static value.
bool prepare(QgsExpression *parent, const QgsExpressionContext *context)
Prepare this node for evaluation.
bool mHasCachedValue
true if the node has a static, precalculated value.
const QgsExpressionNode * effectiveNode() const
Returns a reference to the simplest node which represents this node, after any compilation optimizati...
QVariant cachedStaticValue() const
Returns the node's static cached value.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
virtual QSet< QString > referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node.
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.
@ ntIndexOperator
Index operator.
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
virtual QSet< QString > referencedFunctions() const =0
Returns a set of all functions which are used in this expression.
virtual QSet< QString > referencedVariables() const =0
Returns a set of all variables which are used in this expression.
virtual QgsExpressionNode * clone() const =0
Generate a clone of this node.
Class for parsing and evaluation of expressions (formerly called "search strings").
static const QList< QgsExpressionFunction * > & Functions()
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:335
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:209
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:320
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:236
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
#define str(x)
Definition: qgis.cpp:37
#define FALLTHROUGH
Definition: qgis.h:1769
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1246
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
const QString & typeName
QgsExpressionNode * node
Node.