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