QGIS API Documentation  3.21.0-Master (909859188c)
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 ( !args || functionParams.isEmpty() )
1071  {
1072  // no QgsExpressionFunction::Parameters, or function does not support them
1073  mArgs = args;
1074  }
1075  else
1076  {
1077  mArgs = new NodeList();
1078 
1079  int idx = 0;
1080  //first loop through unnamed arguments
1081  while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
1082  {
1083  mArgs->append( args->list().at( idx )->clone() );
1084  idx++;
1085  }
1086 
1087  //next copy named QgsExpressionFunction::Parameters in order expected by function
1088  for ( ; idx < functionParams.count(); ++idx )
1089  {
1090  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1091  if ( nodeIdx < 0 )
1092  {
1093  //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1094  mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
1095  }
1096  else
1097  {
1098  mArgs->append( args->list().at( nodeIdx )->clone() );
1099  }
1100  }
1101 
1102  delete args;
1103  }
1104 }
1105 
1107 {
1108  delete mArgs;
1109 }
1110 
1112 {
1113  return ntFunction;
1114 }
1115 
1117 {
1118  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1119 
1120  bool res = fd->prepare( this, parent, context );
1121  if ( mArgs && !fd->lazyEval() )
1122  {
1123  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1124  for ( QgsExpressionNode *n : nodeList )
1125  {
1126  res = res && n->prepare( parent, context );
1127  }
1128  }
1129  return res;
1130 }
1131 
1133 {
1134  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1135  if ( fd->params() == 0 )
1136  return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1137  else
1138  return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1139 }
1140 
1142 {
1143  if ( hasCachedStaticValue() )
1144  return QSet< QString >();
1145 
1146  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1147  QSet<QString> functionColumns = fd->referencedColumns( this );
1148 
1149  if ( !mArgs )
1150  {
1151  //no referenced columns in arguments, just return function's referenced columns
1152  return functionColumns;
1153  }
1154 
1155  int paramIndex = 0;
1156  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1157  for ( QgsExpressionNode *n : nodeList )
1158  {
1159  if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1160  functionColumns.unite( n->referencedColumns() );
1161  paramIndex++;
1162  }
1163 
1164  return functionColumns;
1165 }
1166 
1168 {
1169  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1170  if ( fd->name() == QLatin1String( "var" ) )
1171  {
1172  if ( !mArgs->list().isEmpty() )
1173  {
1174  QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1175  if ( var )
1176  return QSet<QString>() << var->value().toString();
1177  }
1178  return QSet<QString>() << QString();
1179  }
1180  else
1181  {
1182  QSet<QString> functionVariables = QSet<QString>();
1183 
1184  if ( !mArgs )
1185  return functionVariables;
1186 
1187  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1188  for ( QgsExpressionNode *n : nodeList )
1189  {
1190  functionVariables.unite( n->referencedVariables() );
1191  }
1192 
1193  return functionVariables;
1194  }
1195 }
1196 
1198 {
1199  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1200  QSet<QString> functions = QSet<QString>();
1201  functions.insert( fd->name() );
1202 
1203  if ( !mArgs )
1204  return functions;
1205 
1206  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1207  for ( QgsExpressionNode *n : nodeList )
1208  {
1209  functions.unite( n->referencedFunctions() );
1210  }
1211  return functions;
1212 }
1213 
1214 QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1215 {
1216  QList<const QgsExpressionNode *> lst;
1217  lst << this;
1218  if ( !mArgs )
1219  return lst;
1220 
1221  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1222  for ( QgsExpressionNode *n : nodeList )
1223  {
1224  lst += n->nodes();
1225  }
1226  return lst;
1227 }
1228 
1230 {
1231  bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1232  if ( mArgs )
1233  {
1234  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1235  for ( QgsExpressionNode *n : nodeList )
1236  needs |= n->needsGeometry();
1237  }
1238  return needs;
1239 }
1240 
1242 {
1243  QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1244  cloneTo( copy );
1245  return copy;
1246 }
1247 
1249 {
1250  return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1251 }
1252 
1254 {
1255  if ( !args || !args->hasNamedNodes() )
1256  return true;
1257 
1258  const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1259  if ( functionParams.isEmpty() )
1260  {
1261  error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1262  return false;
1263  }
1264  else
1265  {
1266  QSet< int > providedArgs;
1267  QSet< int > handledArgs;
1268  int idx = 0;
1269  //first loop through unnamed arguments
1270  while ( args->names().at( idx ).isEmpty() )
1271  {
1272  providedArgs << idx;
1273  handledArgs << idx;
1274  idx++;
1275  }
1276 
1277  //next check named QgsExpressionFunction::Parameters
1278  for ( ; idx < functionParams.count(); ++idx )
1279  {
1280  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1281  if ( nodeIdx < 0 )
1282  {
1283  if ( !functionParams.at( idx ).optional() )
1284  {
1285  error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1286  return false;
1287  }
1288  }
1289  else
1290  {
1291  if ( providedArgs.contains( idx ) )
1292  {
1293  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1294  return false;
1295  }
1296  }
1297  providedArgs << idx;
1298  handledArgs << nodeIdx;
1299  }
1300 
1301  //last check for bad names
1302  idx = 0;
1303  const QStringList nameList = args->names();
1304  for ( const QString &name : nameList )
1305  {
1306  if ( !name.isEmpty() && !functionParams.contains( name ) )
1307  {
1308  error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1309  return false;
1310  }
1311  if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1312  {
1313  int functionIdx = functionParams.indexOf( name );
1314  if ( providedArgs.contains( functionIdx ) )
1315  {
1316  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1317  return false;
1318  }
1319  }
1320  idx++;
1321  }
1322 
1323  }
1324  return true;
1325 }
1326 
1327 //
1328 
1330 {
1331  Q_UNUSED( context )
1332  Q_UNUSED( parent )
1333  return mValue;
1334 }
1335 
1337 {
1338  return ntLiteral;
1339 }
1340 
1342 {
1343  Q_UNUSED( parent )
1344  Q_UNUSED( context )
1345  return true;
1346 }
1347 
1348 
1350 {
1351  if ( mValue.isNull() )
1352  return QStringLiteral( "NULL" );
1353 
1354  switch ( mValue.type() )
1355  {
1356  case QVariant::Int:
1357  return QString::number( mValue.toInt() );
1358  case QVariant::Double:
1359  return QString::number( mValue.toDouble() );
1360  case QVariant::LongLong:
1361  return QString::number( mValue.toLongLong() );
1362  case QVariant::String:
1363  return QgsExpression::quotedString( mValue.toString() );
1364  case QVariant::Bool:
1365  return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1366  default:
1367  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1368  }
1369 }
1370 
1372 {
1373  return valueAsString();
1374 }
1375 
1377 {
1378  return QSet<QString>();
1379 }
1380 
1382 {
1383  return QSet<QString>();
1384 }
1385 
1387 {
1388  return QSet<QString>();
1389 }
1390 
1391 QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1392 {
1393  QList<const QgsExpressionNode *> lst;
1394  lst << this;
1395  return lst;
1396 }
1397 
1399 {
1400  return false;
1401 }
1402 
1404 {
1405  QgsExpressionNodeLiteral *copy = new QgsExpressionNodeLiteral( mValue );
1406  cloneTo( copy );
1407  return copy;
1408 }
1409 
1411 {
1412  Q_UNUSED( context )
1413  Q_UNUSED( parent )
1414  return true;
1415 }
1416 
1417 //
1418 
1420 {
1421  Q_UNUSED( parent )
1422  int index = mIndex;
1423 
1424  if ( index < 0 )
1425  {
1426  // have not yet found field index - first check explicitly set fields collection
1427  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1428  {
1429  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1430  index = fields.lookupField( mName );
1431  }
1432  }
1433 
1434  if ( context )
1435  {
1436  QgsFeature feature = context->feature();
1437  if ( feature.isValid() )
1438  {
1439  if ( index >= 0 )
1440  return feature.attribute( index );
1441  else
1442  return feature.attribute( mName );
1443  }
1444  else
1445  {
1446  parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1447  }
1448  }
1449  if ( index < 0 )
1450  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1451  return QVariant();
1452 }
1453 
1455 {
1456  return ntColumnRef;
1457 }
1458 
1460 {
1461  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1462  return false;
1463 
1464  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1465 
1466  mIndex = fields.lookupField( mName );
1467 
1468  if ( mIndex == -1 && context->hasFeature() )
1469  {
1470  mIndex = context->feature().fieldNameIndex( mName );
1471  }
1472 
1473  if ( mIndex == -1 )
1474  {
1475  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1476  return false;
1477  }
1478  return true;
1479 }
1480 
1482 {
1483  const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
1484  const QRegularExpressionMatch match = re.match( mName );
1485  return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1486 }
1487 
1489 {
1490  return QSet<QString>() << mName;
1491 }
1492 
1494 {
1495  return QSet<QString>();
1496 }
1497 
1499 {
1500  return QSet<QString>();
1501 }
1502 
1503 QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1504 {
1505  QList<const QgsExpressionNode *> result;
1506  result << this;
1507  return result;
1508 }
1509 
1511 {
1512  return false;
1513 }
1514 
1516 {
1518  cloneTo( copy );
1519  return copy;
1520 }
1521 
1523 {
1524  Q_UNUSED( context )
1525  Q_UNUSED( parent )
1526  return false;
1527 }
1528 
1529 //
1530 
1532  : mConditions( *conditions )
1533  , mElseExp( elseExp )
1534 {
1535  delete conditions;
1536 }
1537 
1539 {
1540  delete mElseExp;
1541  qDeleteAll( mConditions );
1542 }
1543 
1545 {
1546  return ntCondition;
1547 }
1548 
1550 {
1551  for ( WhenThen *cond : std::as_const( mConditions ) )
1552  {
1553  QVariant vWhen = cond->mWhenExp->eval( parent, context );
1554  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1556  if ( tvl == QgsExpressionUtils::True )
1557  {
1558  QVariant vRes = cond->mThenExp->eval( parent, context );
1560  return vRes;
1561  }
1562  }
1563 
1564  if ( mElseExp )
1565  {
1566  QVariant vElse = mElseExp->eval( parent, context );
1568  return vElse;
1569  }
1570 
1571  // return NULL if no condition is matching
1572  return QVariant();
1573 }
1574 
1576 {
1577  bool foundAnyNonStaticConditions = false;
1578  for ( WhenThen *cond : std::as_const( mConditions ) )
1579  {
1580  const bool res = cond->mWhenExp->prepare( parent, context )
1581  && cond->mThenExp->prepare( parent, context );
1582  if ( !res )
1583  return false;
1584 
1585  foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1586  if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1587  {
1588  // 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
1589  // value, and the static value for this WHEN clause is True.
1590  if ( cond->mThenExp->hasCachedStaticValue() )
1591  {
1592  // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1593  mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1594  mHasCachedValue = true;
1595  return true;
1596  }
1597  else
1598  {
1599  // 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
1600  // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1601  mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1602  return true;
1603  }
1604  }
1605  }
1606 
1607  if ( mElseExp )
1608  {
1609  const bool res = mElseExp->prepare( parent, context );
1610  if ( !res )
1611  return false;
1612 
1613  if ( !foundAnyNonStaticConditions )
1614  {
1615  // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1616  if ( mElseExp->hasCachedStaticValue() )
1617  {
1618  mCachedStaticValue = mElseExp->cachedStaticValue();
1619  mHasCachedValue = true;
1620  return true;
1621  }
1622  else
1623  {
1624  // so even though the ELSE node is non-static we can effectively replace
1625  // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1626  mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1627  return true;
1628  }
1629  }
1630  }
1631 
1632  return true;
1633 }
1634 
1636 {
1637  QString msg( QStringLiteral( "CASE" ) );
1638  for ( WhenThen *cond : mConditions )
1639  {
1640  msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1641  }
1642  if ( mElseExp )
1643  msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1644  msg += QLatin1String( " END" );
1645  return msg;
1646 }
1647 
1649 {
1650  if ( hasCachedStaticValue() )
1651  return QSet< QString >();
1652 
1653  QSet<QString> lst;
1654  for ( WhenThen *cond : mConditions )
1655  {
1656  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1657  }
1658 
1659  if ( mElseExp )
1660  lst += mElseExp->referencedColumns();
1661 
1662  return lst;
1663 }
1664 
1666 {
1667  QSet<QString> lst;
1668  for ( WhenThen *cond : mConditions )
1669  {
1670  lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1671  }
1672 
1673  if ( mElseExp )
1674  lst += mElseExp->referencedVariables();
1675 
1676  return lst;
1677 }
1678 
1680 {
1681  QSet<QString> lst;
1682  for ( WhenThen *cond : mConditions )
1683  {
1684  lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1685  }
1686 
1687  if ( mElseExp )
1688  lst += mElseExp->referencedFunctions();
1689 
1690  return lst;
1691 }
1692 
1693 QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1694 {
1695  QList<const QgsExpressionNode *> lst;
1696  lst << this;
1697  for ( WhenThen *cond : mConditions )
1698  {
1699  lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1700  }
1701 
1702  if ( mElseExp )
1703  lst += mElseExp->nodes();
1704 
1705  return lst;
1706 }
1707 
1709 {
1710  for ( WhenThen *cond : mConditions )
1711  {
1712  if ( cond->mWhenExp->needsGeometry() ||
1713  cond->mThenExp->needsGeometry() )
1714  return true;
1715  }
1716 
1717  return mElseExp && mElseExp->needsGeometry();
1718 }
1719 
1721 {
1723  conditions.reserve( mConditions.size() );
1724  for ( WhenThen *wt : mConditions )
1725  conditions.append( wt->clone() );
1726 
1727  QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1728  cloneTo( copy );
1729  return copy;
1730 }
1731 
1733 {
1734  for ( WhenThen *wt : mConditions )
1735  {
1736  if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1737  return false;
1738  }
1739 
1740  if ( mElseExp )
1741  return mElseExp->isStatic( parent, context );
1742 
1743  return true;
1744 }
1745 
1747 {
1748  if ( hasCachedStaticValue() )
1749  return QSet< QString >();
1750 
1751  QSet<QString> lst( mNode->referencedColumns() );
1752  const QList< QgsExpressionNode * > nodeList = mList->list();
1753  for ( const QgsExpressionNode *n : nodeList )
1754  lst.unite( n->referencedColumns() );
1755  return lst;
1756 }
1757 
1759 {
1760  QSet<QString> lst( mNode->referencedVariables() );
1761  const QList< QgsExpressionNode * > nodeList = mList->list();
1762  for ( const QgsExpressionNode *n : nodeList )
1763  lst.unite( n->referencedVariables() );
1764  return lst;
1765 }
1766 
1768 {
1769  QSet<QString> lst( mNode->referencedFunctions() );
1770  const QList< QgsExpressionNode * > nodeList = mList->list();
1771  for ( const QgsExpressionNode *n : nodeList )
1772  lst.unite( n->referencedFunctions() );
1773  return lst;
1774 }
1775 
1776 QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1777 {
1778  QList<const QgsExpressionNode *> lst;
1779  lst << this;
1780  const QList< QgsExpressionNode * > nodeList = mList->list();
1781  for ( const QgsExpressionNode *n : nodeList )
1782  lst += n->nodes();
1783  return lst;
1784 }
1785 
1787  : mWhenExp( whenExp )
1788  , mThenExp( thenExp )
1789 {
1790 }
1791 
1793 {
1794  delete mWhenExp;
1795  delete mThenExp;
1796 }
1797 
1799 {
1800  return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1801 }
1802 
1804 {
1805  return BINARY_OPERATOR_TEXT[mOp];
1806 }
1807 
1808 //
1809 
1811 {
1812  const QVariant container = mContainer->eval( parent, context );
1814  const QVariant index = mIndex->eval( parent, context );
1816 
1817  switch ( container.type() )
1818  {
1819  case QVariant::Map:
1820  return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1821 
1822  case QVariant::List:
1823  case QVariant::StringList:
1824  {
1825  const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
1826  qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
1827  if ( pos >= list.length() || pos < -list.length() )
1828  {
1829  return QVariant();
1830  }
1831  if ( pos < 0 )
1832  {
1833  // negative indices are from back of list
1834  pos += list.length();
1835  }
1836 
1837  return list.at( pos );
1838  }
1839 
1840  default:
1841  if ( !container.isNull() )
1842  parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
1843  return QVariant();
1844  }
1845 }
1846 
1848 {
1849  return ntIndexOperator;
1850 }
1851 
1853 {
1854  bool resC = mContainer->prepare( parent, context );
1855  bool resV = mIndex->prepare( parent, context );
1856  return resC && resV;
1857 }
1858 
1860 {
1861  return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
1862 }
1863 
1865 {
1866  if ( hasCachedStaticValue() )
1867  return QSet< QString >();
1868 
1869  return mContainer->referencedColumns() + mIndex->referencedColumns();
1870 }
1871 
1873 {
1874  return mContainer->referencedVariables() + mIndex->referencedVariables();
1875 }
1876 
1878 {
1879  return mContainer->referencedFunctions() + mIndex->referencedFunctions();
1880 }
1881 
1882 QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
1883 {
1884  QList<const QgsExpressionNode *> lst;
1885  lst << this;
1886  lst += mContainer->nodes() + mIndex->nodes();
1887  return lst;
1888 }
1889 
1891 {
1892  return mContainer->needsGeometry() || mIndex->needsGeometry();
1893 }
1894 
1896 {
1897  QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
1898  cloneTo( copy );
1899  return copy;
1900 }
1901 
1903 {
1904  return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
1905 }
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.
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:317
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:191
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
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:1631
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1108
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
const QString & typeName
QgsExpressionNode * node
Node.