QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsexpressionnodeimpl.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpressionnodeimpl.cpp
3  -------------------
4  begin : May 2017
5  copyright : (C) 2017 Matthias Kuhn
6  email : matthias@opengis.ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
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  return mOpLeft->isStatic( parent, context ) && mOpRight->isStatic( parent, context );
839 }
840 
841 //
842 
844 {
845  if ( mList->count() == 0 )
846  return mNotIn ? TVL_True : TVL_False;
847  QVariant v1 = mNode->eval( parent, context );
849  if ( QgsExpressionUtils::isNull( v1 ) )
850  return TVL_Unknown;
851 
852  bool listHasNull = false;
853 
854  const QList< QgsExpressionNode * > nodeList = mList->list();
855  for ( QgsExpressionNode *n : nodeList )
856  {
857  QVariant v2 = n->eval( parent, context );
859  if ( QgsExpressionUtils::isNull( v2 ) )
860  listHasNull = true;
861  else
862  {
863  bool equal = false;
864  // check whether they are equal
865  if ( ( v1.type() != QVariant::String || v2.type() != QVariant::String ) &&
866  QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
867  {
868  // do numeric comparison if both operators can be converted to numbers,
869  // and they aren't both string
870  double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
872  double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
874  equal = qgsDoubleNear( f1, f2 );
875  }
876  else
877  {
878  QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
880  QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
882  equal = QString::compare( s1, s2 ) == 0;
883  }
884 
885  if ( equal ) // we know the result
886  return mNotIn ? TVL_False : TVL_True;
887  }
888  }
889 
890  // item not found
891  if ( listHasNull )
892  return TVL_Unknown;
893  else
894  return mNotIn ? TVL_True : TVL_False;
895 }
896 
898 {
899  delete mNode;
900  delete mList;
901 }
902 
904 {
905  return ntInOperator;
906 }
907 
909 {
910  bool res = mNode->prepare( parent, context );
911  const QList< QgsExpressionNode * > nodeList = mList->list();
912  for ( QgsExpressionNode *n : nodeList )
913  {
914  res = res && n->prepare( parent, context );
915  }
916  return res;
917 }
918 
920 {
921  return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
922 }
923 
925 {
926  QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
927  cloneTo( copy );
928  return copy;
929 }
930 
932 {
933  if ( !mNode->isStatic( parent, context ) )
934  return false;
935 
936  const QList< QgsExpressionNode * > nodeList = mList->list();
937  for ( QgsExpressionNode *n : nodeList )
938  {
939  if ( !n->isStatic( parent, context ) )
940  return false;
941  }
942 
943  return true;
944 }
945 
946 //
947 
949 {
950  QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
951  QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
952 
953  QVariant res = fd->run( mArgs, context, parent, this );
955 
956  // everything went fine
957  return res;
958 }
959 
961  : mFnIndex( fnIndex )
962 {
963  const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
964  if ( !args || functionParams.isEmpty() )
965  {
966  // no QgsExpressionFunction::Parameters, or function does not support them
967  mArgs = args;
968  }
969  else
970  {
971  mArgs = new NodeList();
972 
973  int idx = 0;
974  //first loop through unnamed arguments
975  while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
976  {
977  mArgs->append( args->list().at( idx )->clone() );
978  idx++;
979  }
980 
981  //next copy named QgsExpressionFunction::Parameters in order expected by function
982  for ( ; idx < functionParams.count(); ++idx )
983  {
984  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
985  if ( nodeIdx < 0 )
986  {
987  //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
988  mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
989  }
990  else
991  {
992  mArgs->append( args->list().at( nodeIdx )->clone() );
993  }
994  }
995 
996  delete args;
997  }
998 }
999 
1001 {
1002  delete mArgs;
1003 }
1004 
1006 {
1007  return ntFunction;
1008 }
1009 
1011 {
1012  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1013 
1014  bool res = fd->prepare( this, parent, context );
1015  if ( mArgs && !fd->lazyEval() )
1016  {
1017  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1018  for ( QgsExpressionNode *n : nodeList )
1019  {
1020  res = res && n->prepare( parent, context );
1021  }
1022  }
1023  return res;
1024 }
1025 
1027 {
1028  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1029  if ( fd->params() == 0 )
1030  return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1031  else
1032  return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1033 }
1034 
1036 {
1037  if ( hasCachedStaticValue() )
1038  return QSet< QString >();
1039 
1040  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1041  QSet<QString> functionColumns = fd->referencedColumns( this );
1042 
1043  if ( !mArgs )
1044  {
1045  //no referenced columns in arguments, just return function's referenced columns
1046  return functionColumns;
1047  }
1048 
1049  int paramIndex = 0;
1050  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1051  for ( QgsExpressionNode *n : nodeList )
1052  {
1053  if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1054  functionColumns.unite( n->referencedColumns() );
1055  paramIndex++;
1056  }
1057 
1058  return functionColumns;
1059 }
1060 
1062 {
1063  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1064  if ( fd->name() == QLatin1String( "var" ) )
1065  {
1066  if ( !mArgs->list().isEmpty() )
1067  {
1068  QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1069  if ( var )
1070  return QSet<QString>() << var->value().toString();
1071  }
1072  return QSet<QString>() << QString();
1073  }
1074  else
1075  {
1076  QSet<QString> functionVariables = QSet<QString>();
1077 
1078  if ( !mArgs )
1079  return functionVariables;
1080 
1081  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1082  for ( QgsExpressionNode *n : nodeList )
1083  {
1084  functionVariables.unite( n->referencedVariables() );
1085  }
1086 
1087  return functionVariables;
1088  }
1089 }
1090 
1092 {
1093  QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1094  QSet<QString> functions = QSet<QString>();
1095  functions.insert( fd->name() );
1096 
1097  if ( !mArgs )
1098  return functions;
1099 
1100  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1101  for ( QgsExpressionNode *n : nodeList )
1102  {
1103  functions.unite( n->referencedFunctions() );
1104  }
1105  return functions;
1106 }
1107 
1108 QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1109 {
1110  QList<const QgsExpressionNode *> lst;
1111  lst << this;
1112  if ( !mArgs )
1113  return lst;
1114 
1115  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1116  for ( QgsExpressionNode *n : nodeList )
1117  {
1118  lst += n->nodes();
1119  }
1120  return lst;
1121 }
1122 
1124 {
1125  bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1126  if ( mArgs )
1127  {
1128  const QList< QgsExpressionNode * > nodeList = mArgs->list();
1129  for ( QgsExpressionNode *n : nodeList )
1130  needs |= n->needsGeometry();
1131  }
1132  return needs;
1133 }
1134 
1136 {
1137  QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1138  cloneTo( copy );
1139  return copy;
1140 }
1141 
1143 {
1144  return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1145 }
1146 
1148 {
1149  if ( !args || !args->hasNamedNodes() )
1150  return true;
1151 
1152  const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1153  if ( functionParams.isEmpty() )
1154  {
1155  error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1156  return false;
1157  }
1158  else
1159  {
1160  QSet< int > providedArgs;
1161  QSet< int > handledArgs;
1162  int idx = 0;
1163  //first loop through unnamed arguments
1164  while ( args->names().at( idx ).isEmpty() )
1165  {
1166  providedArgs << idx;
1167  handledArgs << idx;
1168  idx++;
1169  }
1170 
1171  //next check named QgsExpressionFunction::Parameters
1172  for ( ; idx < functionParams.count(); ++idx )
1173  {
1174  int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1175  if ( nodeIdx < 0 )
1176  {
1177  if ( !functionParams.at( idx ).optional() )
1178  {
1179  error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1180  return false;
1181  }
1182  }
1183  else
1184  {
1185  if ( providedArgs.contains( idx ) )
1186  {
1187  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1188  return false;
1189  }
1190  }
1191  providedArgs << idx;
1192  handledArgs << nodeIdx;
1193  }
1194 
1195  //last check for bad names
1196  idx = 0;
1197  const QStringList nameList = args->names();
1198  for ( const QString &name : nameList )
1199  {
1200  if ( !name.isEmpty() && !functionParams.contains( name ) )
1201  {
1202  error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1203  return false;
1204  }
1205  if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1206  {
1207  int functionIdx = functionParams.indexOf( name );
1208  if ( providedArgs.contains( functionIdx ) )
1209  {
1210  error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1211  return false;
1212  }
1213  }
1214  idx++;
1215  }
1216 
1217  }
1218  return true;
1219 }
1220 
1221 //
1222 
1224 {
1225  Q_UNUSED( context )
1226  Q_UNUSED( parent )
1227  return mValue;
1228 }
1229 
1231 {
1232  return ntLiteral;
1233 }
1234 
1236 {
1237  Q_UNUSED( parent )
1238  Q_UNUSED( context )
1239  return true;
1240 }
1241 
1242 
1244 {
1245  if ( mValue.isNull() )
1246  return QStringLiteral( "NULL" );
1247 
1248  switch ( mValue.type() )
1249  {
1250  case QVariant::Int:
1251  return QString::number( mValue.toInt() );
1252  case QVariant::Double:
1253  return QString::number( mValue.toDouble() );
1254  case QVariant::LongLong:
1255  return QString::number( mValue.toLongLong() );
1256  case QVariant::String:
1257  return QgsExpression::quotedString( mValue.toString() );
1258  case QVariant::Bool:
1259  return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1260  default:
1261  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1262  }
1263 }
1264 
1266 {
1267  return QSet<QString>();
1268 }
1269 
1271 {
1272  return QSet<QString>();
1273 }
1274 
1276 {
1277  return QSet<QString>();
1278 }
1279 
1280 QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1281 {
1282  QList<const QgsExpressionNode *> lst;
1283  lst << this;
1284  return lst;
1285 }
1286 
1288 {
1289  return false;
1290 }
1291 
1293 {
1294  QgsExpressionNodeLiteral *copy = new QgsExpressionNodeLiteral( mValue );
1295  cloneTo( copy );
1296  return copy;
1297 }
1298 
1300 {
1301  Q_UNUSED( context )
1302  Q_UNUSED( parent )
1303  return true;
1304 }
1305 
1306 //
1307 
1309 {
1310  Q_UNUSED( parent )
1311  int index = mIndex;
1312 
1313  if ( index < 0 )
1314  {
1315  // have not yet found field index - first check explicitly set fields collection
1316  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1317  {
1318  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1319  index = fields.lookupField( mName );
1320  }
1321  }
1322 
1323  if ( context )
1324  {
1325  QgsFeature feature = context->feature();
1326  if ( feature.isValid() )
1327  {
1328  if ( index >= 0 )
1329  return feature.attribute( index );
1330  else
1331  return feature.attribute( mName );
1332  }
1333  else
1334  {
1335  parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1336  }
1337  }
1338  if ( index < 0 )
1339  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1340  return QVariant();
1341 }
1342 
1344 {
1345  return ntColumnRef;
1346 }
1347 
1349 {
1350  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1351  return false;
1352 
1353  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1354 
1355  mIndex = fields.lookupField( mName );
1356 
1357  if ( mIndex == -1 && context->hasFeature() )
1358  {
1359  mIndex = context->feature().fieldNameIndex( mName );
1360  }
1361 
1362  if ( mIndex == -1 )
1363  {
1364  parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1365  return false;
1366  }
1367  return true;
1368 }
1369 
1371 {
1372  const thread_local QRegExp re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
1373  return re.exactMatch( mName ) ? mName : QgsExpression::quotedColumnRef( mName );
1374 }
1375 
1377 {
1378  return QSet<QString>() << mName;
1379 }
1380 
1382 {
1383  return QSet<QString>();
1384 }
1385 
1387 {
1388  return QSet<QString>();
1389 }
1390 
1391 QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1392 {
1393  QList<const QgsExpressionNode *> result;
1394  result << this;
1395  return result;
1396 }
1397 
1399 {
1400  return false;
1401 }
1402 
1404 {
1406  cloneTo( copy );
1407  return copy;
1408 }
1409 
1411 {
1412  Q_UNUSED( context )
1413  Q_UNUSED( parent )
1414  return false;
1415 }
1416 
1417 //
1418 
1420  : mConditions( *conditions )
1421  , mElseExp( elseExp )
1422 {
1423  delete conditions;
1424 }
1425 
1427 {
1428  delete mElseExp;
1429  qDeleteAll( mConditions );
1430 }
1431 
1433 {
1434  return ntCondition;
1435 }
1436 
1438 {
1439  for ( WhenThen *cond : qgis::as_const( mConditions ) )
1440  {
1441  QVariant vWhen = cond->mWhenExp->eval( parent, context );
1442  QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1444  if ( tvl == QgsExpressionUtils::True )
1445  {
1446  QVariant vRes = cond->mThenExp->eval( parent, context );
1448  return vRes;
1449  }
1450  }
1451 
1452  if ( mElseExp )
1453  {
1454  QVariant vElse = mElseExp->eval( parent, context );
1456  return vElse;
1457  }
1458 
1459  // return NULL if no condition is matching
1460  return QVariant();
1461 }
1462 
1464 {
1465  bool res;
1466  for ( WhenThen *cond : qgis::as_const( mConditions ) )
1467  {
1468  res = cond->mWhenExp->prepare( parent, context )
1469  & cond->mThenExp->prepare( parent, context );
1470  if ( !res )
1471  return false;
1472  }
1473 
1474  if ( mElseExp )
1475  return mElseExp->prepare( parent, context );
1476 
1477  return true;
1478 }
1479 
1481 {
1482  QString msg( QStringLiteral( "CASE" ) );
1483  for ( WhenThen *cond : mConditions )
1484  {
1485  msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1486  }
1487  if ( mElseExp )
1488  msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1489  msg += QLatin1String( " END" );
1490  return msg;
1491 }
1492 
1494 {
1495  if ( hasCachedStaticValue() )
1496  return QSet< QString >();
1497 
1498  QSet<QString> lst;
1499  for ( WhenThen *cond : mConditions )
1500  {
1501  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1502  }
1503 
1504  if ( mElseExp )
1505  lst += mElseExp->referencedColumns();
1506 
1507  return lst;
1508 }
1509 
1511 {
1512  QSet<QString> lst;
1513  for ( WhenThen *cond : mConditions )
1514  {
1515  lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1516  }
1517 
1518  if ( mElseExp )
1519  lst += mElseExp->referencedVariables();
1520 
1521  return lst;
1522 }
1523 
1525 {
1526  QSet<QString> lst;
1527  for ( WhenThen *cond : mConditions )
1528  {
1529  lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1530  }
1531 
1532  if ( mElseExp )
1533  lst += mElseExp->referencedFunctions();
1534 
1535  return lst;
1536 }
1537 
1538 QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1539 {
1540  QList<const QgsExpressionNode *> lst;
1541  lst << this;
1542  for ( WhenThen *cond : mConditions )
1543  {
1544  lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1545  }
1546 
1547  if ( mElseExp )
1548  lst += mElseExp->nodes();
1549 
1550  return lst;
1551 }
1552 
1554 {
1555  for ( WhenThen *cond : mConditions )
1556  {
1557  if ( cond->mWhenExp->needsGeometry() ||
1558  cond->mThenExp->needsGeometry() )
1559  return true;
1560  }
1561 
1562  return mElseExp && mElseExp->needsGeometry();
1563 }
1564 
1566 {
1568  conditions.reserve( mConditions.size() );
1569  for ( WhenThen *wt : mConditions )
1570  conditions.append( wt->clone() );
1571 
1572  QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1573  cloneTo( copy );
1574  return copy;
1575 }
1576 
1578 {
1579  for ( WhenThen *wt : mConditions )
1580  {
1581  if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1582  return false;
1583  }
1584 
1585  if ( mElseExp )
1586  return mElseExp->isStatic( parent, context );
1587 
1588  return true;
1589 }
1590 
1592 {
1593  if ( hasCachedStaticValue() )
1594  return QSet< QString >();
1595 
1596  QSet<QString> lst( mNode->referencedColumns() );
1597  const QList< QgsExpressionNode * > nodeList = mList->list();
1598  for ( const QgsExpressionNode *n : nodeList )
1599  lst.unite( n->referencedColumns() );
1600  return lst;
1601 }
1602 
1604 {
1605  QSet<QString> lst( mNode->referencedVariables() );
1606  const QList< QgsExpressionNode * > nodeList = mList->list();
1607  for ( const QgsExpressionNode *n : nodeList )
1608  lst.unite( n->referencedVariables() );
1609  return lst;
1610 }
1611 
1613 {
1614  QSet<QString> lst( mNode->referencedFunctions() );
1615  const QList< QgsExpressionNode * > nodeList = mList->list();
1616  for ( const QgsExpressionNode *n : nodeList )
1617  lst.unite( n->referencedFunctions() );
1618  return lst;
1619 }
1620 
1621 QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1622 {
1623  QList<const QgsExpressionNode *> lst;
1624  lst << this;
1625  const QList< QgsExpressionNode * > nodeList = mList->list();
1626  for ( const QgsExpressionNode *n : nodeList )
1627  lst += n->nodes();
1628  return lst;
1629 }
1630 
1632  : mWhenExp( whenExp )
1633  , mThenExp( thenExp )
1634 {
1635 }
1636 
1638 {
1639  delete mWhenExp;
1640  delete mThenExp;
1641 }
1642 
1644 {
1645  return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
1646 }
1647 
1649 {
1650  return BINARY_OPERATOR_TEXT[mOp];
1651 }
1652 
1653 //
1654 
1656 {
1657  const QVariant container = mContainer->eval( parent, context );
1659  const QVariant index = mIndex->eval( parent, context );
1661 
1662  switch ( container.type() )
1663  {
1664  case QVariant::Map:
1665  return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
1666 
1667  case QVariant::List:
1668  case QVariant::StringList:
1669  {
1670  const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
1671  qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
1672  if ( pos >= list.length() || pos < -list.length() )
1673  {
1674  return QVariant();
1675  }
1676  if ( pos < 0 )
1677  {
1678  // negative indices are from back of list
1679  pos += list.length();
1680  }
1681 
1682  return list.at( pos );
1683  }
1684 
1685  default:
1686  parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
1687  return QVariant();
1688  }
1689 }
1690 
1692 {
1693  return ntIndexOperator;
1694 }
1695 
1697 {
1698  bool resC = mContainer->prepare( parent, context );
1699  bool resV = mIndex->prepare( parent, context );
1700  return resC && resV;
1701 }
1702 
1704 {
1705  return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
1706 }
1707 
1709 {
1710  if ( hasCachedStaticValue() )
1711  return QSet< QString >();
1712 
1713  return mContainer->referencedColumns() + mIndex->referencedColumns();
1714 }
1715 
1717 {
1718  return mContainer->referencedVariables() + mIndex->referencedVariables();
1719 }
1720 
1722 {
1723  return mContainer->referencedFunctions() + mIndex->referencedFunctions();
1724 }
1725 
1726 QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
1727 {
1728  QList<const QgsExpressionNode *> lst;
1729  lst << this;
1730  lst += mContainer->nodes() + mIndex->nodes();
1731  return lst;
1732 }
1733 
1735 {
1736  return mContainer->needsGeometry() || mIndex->needsGeometry();
1737 }
1738 
1740 {
1741  QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
1742  cloneTo( copy );
1743  return copy;
1744 }
1745 
1747 {
1748  return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
1749 }
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.
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.
virtual QSet< QString > referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node.
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)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
Definition: qgsfeature.cpp:302
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:190
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:287
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 FALLTHROUGH
Definition: qgis.h:829
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
const QString & typeName
QgsExpressionNode * node
Node.