QGIS API Documentation  2.99.0-Master (a18066b)
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
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 "qgsexpression.h"
17 #include "qgsrelationmanager.h"
18 
19 #include <QtDebug>
20 #include <QDomDocument>
21 #include <QDate>
22 #include <QRegExp>
23 #include <QColor>
24 #include <QUuid>
25 #include <QMutex>
26 
27 #include <cmath>
28 #include <limits>
29 
30 #include "qgsdistancearea.h"
31 #include "qgsfeature.h"
32 #include "qgsfeatureiterator.h"
33 #include "qgsgeometry.h"
34 #include "qgsgeometryengine.h"
35 #include "qgsgeometryutils.h"
36 #include "qgslogger.h"
37 #include "qgsogcutils.h"
38 #include "qgsvectorlayer.h"
39 #include "qgssymbollayerutils.h"
40 #include "qgscolorramp.h"
41 #include "qgsstyle.h"
42 #include "qgsexpressioncontext.h"
43 #include "qgsproject.h"
44 #include "qgsstringutils.h"
45 #include "qgsgeometrycollection.h"
46 #include "qgspointv2.h"
47 #include "qgspolygon.h"
48 #include "qgsmultipoint.h"
49 #include "qgsmultilinestring.h"
50 #include "qgscurvepolygon.h"
51 #include "qgsexpressionprivate.h"
52 #include "qgsexpressionsorter.h"
54 #include "qgsmessagelog.h"
55 #include "qgscsexception.h"
56 #include "qgsrasterlayer.h"
57 #include "qgsrasterdataprovider.h"
58 
59 // from parser
60 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
61 
63 // three-value logic
64 
65 enum TVL
66 {
70 };
71 
72 static TVL AND[3][3] =
73 {
74  // false true unknown
75  { False, False, False }, // false
76  { False, True, Unknown }, // true
77  { False, Unknown, Unknown } // unknown
78 };
79 
80 static TVL OR[3][3] =
81 {
82  { False, True, Unknown }, // false
83  { True, True, True }, // true
84  { Unknown, True, Unknown } // unknown
85 };
86 
87 static TVL NOT[3] = { True, False, Unknown };
88 
89 static QVariant tvl2variant( TVL v )
90 {
91  switch ( v )
92  {
93  case False:
94  return 0;
95  case True:
96  return 1;
97  case Unknown:
98  default:
99  return QVariant();
100  }
101 }
102 
103 #define TVL_True QVariant(1)
104 #define TVL_False QVariant(0)
105 #define TVL_Unknown QVariant()
106 
108 // QVariant checks and conversions
109 
110 inline bool isIntSafe( const QVariant& v )
111 {
112  if ( v.type() == QVariant::Int )
113  return true;
114  if ( v.type() == QVariant::UInt )
115  return true;
116  if ( v.type() == QVariant::LongLong )
117  return true;
118  if ( v.type() == QVariant::ULongLong )
119  return true;
120  if ( v.type() == QVariant::Double )
121  return false;
122  if ( v.type() == QVariant::String )
123  {
124  bool ok;
125  v.toString().toInt( &ok );
126  return ok;
127  }
128  return false;
129 }
130 inline bool isDoubleSafe( const QVariant& v )
131 {
132  if ( v.type() == QVariant::Double )
133  return true;
134  if ( v.type() == QVariant::Int )
135  return true;
136  if ( v.type() == QVariant::UInt )
137  return true;
138  if ( v.type() == QVariant::LongLong )
139  return true;
140  if ( v.type() == QVariant::ULongLong )
141  return true;
142  if ( v.type() == QVariant::String )
143  {
144  bool ok;
145  double val = v.toString().toDouble( &ok );
146  ok = ok && qIsFinite( val ) && !qIsNaN( val );
147  return ok;
148  }
149  return false;
150 }
151 
152 inline bool isDateTimeSafe( const QVariant& v )
153 {
154  return v.type() == QVariant::DateTime
155  || v.type() == QVariant::Date
156  || v.type() == QVariant::Time;
157 }
158 
159 inline bool isIntervalSafe( const QVariant& v )
160 {
161  if ( v.canConvert<QgsInterval>() )
162  {
163  return true;
164  }
165 
166  if ( v.type() == QVariant::String )
167  {
168  return QgsInterval::fromString( v.toString() ).isValid();
169  }
170  return false;
171 }
172 
173 inline bool isNull( const QVariant& v )
174 {
175  return v.isNull();
176 }
177 
179 // evaluation error macros
180 
181 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
182 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
183 
185 // operators
186 
188 {
189  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
190  "OR", "AND",
191  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
192  "+", "-", "*", "/", "//", "%", "^",
193  "||"
194 };
195 
197 {
198  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
199  "NOT", "-"
200 };
201 
203 // functions
204 
205 // implicit conversion to string
206 static QString getStringValue( const QVariant& value, QgsExpression* )
207 {
208  return value.toString();
209 }
210 
211 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
212 {
213  bool ok;
214  double x = value.toDouble( &ok );
215  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
216  {
217  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
218  return 0;
219  }
220  return x;
221 }
222 
223 static qlonglong getIntValue( const QVariant& value, QgsExpression* parent )
224 {
225  bool ok;
226  qlonglong x = value.toLongLong( &ok );
227  if ( ok )
228  {
229  return x;
230  }
231  else
232  {
233  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
234  return 0;
235  }
236 }
237 
238 static int getNativeIntValue( const QVariant& value, QgsExpression* parent )
239 {
240  bool ok;
241  qlonglong x = value.toLongLong( &ok );
243  {
244  return x;
245  }
246  else
247  {
248  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to native int" ).arg( value.toString() ) );
249  return 0;
250  }
251 }
252 
253 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
254 {
255  QDateTime d = value.toDateTime();
256  if ( d.isValid() )
257  {
258  return d;
259  }
260  else
261  {
262  QTime t = value.toTime();
263  if ( t.isValid() )
264  {
265  return QDateTime( QDate( 1, 1, 1 ), t );
266  }
267 
268  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
269  return QDateTime();
270  }
271 }
272 
273 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
274 {
275  QDate d = value.toDate();
276  if ( d.isValid() )
277  {
278  return d;
279  }
280  else
281  {
282  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
283  return QDate();
284  }
285 }
286 
287 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
288 {
289  QTime t = value.toTime();
290  if ( t.isValid() )
291  {
292  return t;
293  }
294  else
295  {
296  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
297  return QTime();
298  }
299 }
300 
301 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
302 {
303  if ( value.canConvert<QgsInterval>() )
304  return value.value<QgsInterval>();
305 
306  QgsInterval inter = QgsInterval::fromString( value.toString() );
307  if ( inter.isValid() )
308  {
309  return inter;
310  }
311  // If we get here then we can't convert so we just error and return invalid.
312  if ( report_error )
313  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
314 
315  return QgsInterval();
316 }
317 
318 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
319 {
320  if ( value.canConvert<QgsGeometry>() )
321  return value.value<QgsGeometry>();
322 
323  parent->setEvalErrorString( QStringLiteral( "Cannot convert to QgsGeometry" ) );
324  return QgsGeometry();
325 }
326 
327 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
328 {
329  if ( value.canConvert<QgsFeature>() )
330  return value.value<QgsFeature>();
331 
332  parent->setEvalErrorString( QStringLiteral( "Cannot convert to QgsFeature" ) );
333  return 0;
334 }
335 
336 #define FEAT_FROM_CONTEXT(c, f) if (!(c) || !(c)->hasFeature() ) return QVariant(); \
337  QgsFeature f = ( c )->feature();
338 
339 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
340 {
341  if ( value.canConvert<QgsExpression::Node*>() )
342  return value.value<QgsExpression::Node*>();
343 
344  parent->setEvalErrorString( QStringLiteral( "Cannot convert to Node" ) );
345  return nullptr;
346 }
347 
348 QgsVectorLayer* getVectorLayer( const QVariant& value, QgsExpression* )
349 {
350  QgsMapLayer* ml = value.value< QgsWeakMapLayerPointer >().data();
351  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( ml );
352  if ( !vl )
353  {
354  QString layerString = value.toString();
355  vl = qobject_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( layerString ) ); //search by id first
356 
357  if ( !vl )
358  {
359  QList<QgsMapLayer *> layersByName = QgsProject::instance()->mapLayersByName( layerString );
360  if ( !layersByName.isEmpty() )
361  {
362  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
363  }
364  }
365  }
366 
367  return vl;
368 }
369 
370 
371 // this handles also NULL values
372 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
373 {
374  // we need to convert to TVL
375  if ( value.isNull() )
376  return Unknown;
377 
378  //handle some special cases
379  if ( value.canConvert<QgsGeometry>() )
380  {
381  //geom is false if empty
382  QgsGeometry geom = value.value<QgsGeometry>();
383  return geom.isNull() ? False : True;
384  }
385  else if ( value.canConvert<QgsFeature>() )
386  {
387  //feat is false if non-valid
388  QgsFeature feat = value.value<QgsFeature>();
389  return feat.isValid() ? True : False;
390  }
391 
392  if ( value.type() == QVariant::Int )
393  return value.toInt() != 0 ? True : False;
394 
395  bool ok;
396  double x = value.toDouble( &ok );
397  if ( !ok )
398  {
399  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
400  return Unknown;
401  }
402  return !qgsDoubleNear( x, 0.0 ) ? True : False;
403 }
404 
405 static QVariantList getListValue( const QVariant& value, QgsExpression* parent )
406 {
407  if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
408  {
409  return value.toList();
410  }
411  else
412  {
413  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
414  return QVariantList();
415  }
416 }
417 
418 static QVariantMap getMapValue( const QVariant& value, QgsExpression* parent )
419 {
420  if ( value.type() == QVariant::Map )
421  {
422  return value.toMap();
423  }
424  else
425  {
426  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
427  return QVariantMap();
428  }
429 }
430 
432 
433 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
434 {
435  if ( !context )
436  return QVariant();
437 
438  QString name = getStringValue( values.at( 0 ), parent );
439  return context->variable( name );
440 }
441 
442 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
443 {
444  if ( !context )
445  return QVariant();
446 
447  QString expString = getStringValue( values.at( 0 ), parent );
448  QgsExpression expression( expString );
449  return expression.evaluate( context );
450 }
451 
452 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
453 {
454  double x = getDoubleValue( values.at( 0 ), parent );
455  return QVariant( sqrt( x ) );
456 }
457 
458 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
459 {
460  double val = getDoubleValue( values.at( 0 ), parent );
461  return QVariant( fabs( val ) );
462 }
463 
464 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
465 {
466  double deg = getDoubleValue( values.at( 0 ), parent );
467  return ( deg * M_PI ) / 180;
468 }
469 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
470 {
471  double rad = getDoubleValue( values.at( 0 ), parent );
472  return ( 180 * rad ) / M_PI;
473 }
474 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
475 {
476  double x = getDoubleValue( values.at( 0 ), parent );
477  return QVariant( sin( x ) );
478 }
479 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
480 {
481  double x = getDoubleValue( values.at( 0 ), parent );
482  return QVariant( cos( x ) );
483 }
484 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
485 {
486  double x = getDoubleValue( values.at( 0 ), parent );
487  return QVariant( tan( x ) );
488 }
489 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
490 {
491  double x = getDoubleValue( values.at( 0 ), parent );
492  return QVariant( asin( x ) );
493 }
494 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
495 {
496  double x = getDoubleValue( values.at( 0 ), parent );
497  return QVariant( acos( x ) );
498 }
499 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
500 {
501  double x = getDoubleValue( values.at( 0 ), parent );
502  return QVariant( atan( x ) );
503 }
504 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
505 {
506  double y = getDoubleValue( values.at( 0 ), parent );
507  double x = getDoubleValue( values.at( 1 ), parent );
508  return QVariant( atan2( y, x ) );
509 }
510 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
511 {
512  double x = getDoubleValue( values.at( 0 ), parent );
513  return QVariant( exp( x ) );
514 }
515 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
516 {
517  double x = getDoubleValue( values.at( 0 ), parent );
518  if ( x <= 0 )
519  return QVariant();
520  return QVariant( log( x ) );
521 }
522 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
523 {
524  double x = getDoubleValue( values.at( 0 ), parent );
525  if ( x <= 0 )
526  return QVariant();
527  return QVariant( log10( x ) );
528 }
529 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
530 {
531  double b = getDoubleValue( values.at( 0 ), parent );
532  double x = getDoubleValue( values.at( 1 ), parent );
533  if ( x <= 0 || b <= 0 )
534  return QVariant();
535  return QVariant( log( x ) / log( b ) );
536 }
537 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
538 {
539  double min = getDoubleValue( values.at( 0 ), parent );
540  double max = getDoubleValue( values.at( 1 ), parent );
541  if ( max < min )
542  return QVariant();
543 
544  // Return a random double in the range [min, max] (inclusive)
545  double f = static_cast< double >( qrand() ) / RAND_MAX;
546  return QVariant( min + f * ( max - min ) );
547 }
548 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
549 {
550  qlonglong min = getIntValue( values.at( 0 ), parent );
551  qlonglong max = getIntValue( values.at( 1 ), parent );
552  if ( max < min )
553  return QVariant();
554 
555  // Return a random integer in the range [min, max] (inclusive)
556  return QVariant( min + ( qrand() % static_cast< qlonglong >( max - min + 1 ) ) );
557 }
558 
559 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
560 {
561  double val = getDoubleValue( values.at( 0 ), parent );
562  double domainMin = getDoubleValue( values.at( 1 ), parent );
563  double domainMax = getDoubleValue( values.at( 2 ), parent );
564  double rangeMin = getDoubleValue( values.at( 3 ), parent );
565  double rangeMax = getDoubleValue( values.at( 4 ), parent );
566 
567  if ( domainMin >= domainMax )
568  {
569  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
570  return QVariant();
571  }
572 
573  // outside of domain?
574  if ( val >= domainMax )
575  {
576  return rangeMax;
577  }
578  else if ( val <= domainMin )
579  {
580  return rangeMin;
581  }
582 
583  // calculate linear scale
584  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
585  double c = rangeMin - ( domainMin * m );
586 
587  // Return linearly scaled value
588  return QVariant( m * val + c );
589 }
590 
591 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
592 {
593  double val = getDoubleValue( values.at( 0 ), parent );
594  double domainMin = getDoubleValue( values.at( 1 ), parent );
595  double domainMax = getDoubleValue( values.at( 2 ), parent );
596  double rangeMin = getDoubleValue( values.at( 3 ), parent );
597  double rangeMax = getDoubleValue( values.at( 4 ), parent );
598  double exponent = getDoubleValue( values.at( 5 ), parent );
599 
600  if ( domainMin >= domainMax )
601  {
602  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
603  return QVariant();
604  }
605  if ( exponent <= 0 )
606  {
607  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
608  return QVariant();
609  }
610 
611  // outside of domain?
612  if ( val >= domainMax )
613  {
614  return rangeMax;
615  }
616  else if ( val <= domainMin )
617  {
618  return rangeMin;
619  }
620 
621  // Return exponentially scaled value
622  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
623 }
624 
625 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
626 {
627  //initially set max as first value
628  double maxVal = getDoubleValue( values.at( 0 ), parent );
629 
630  //check against all other values
631  for ( int i = 1; i < values.length(); ++i )
632  {
633  double testVal = getDoubleValue( values[i], parent );
634  if ( testVal > maxVal )
635  {
636  maxVal = testVal;
637  }
638  }
639 
640  return QVariant( maxVal );
641 }
642 
643 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
644 {
645  //initially set min as first value
646  double minVal = getDoubleValue( values.at( 0 ), parent );
647 
648  //check against all other values
649  for ( int i = 1; i < values.length(); ++i )
650  {
651  double testVal = getDoubleValue( values[i], parent );
652  if ( testVal < minVal )
653  {
654  minVal = testVal;
655  }
656  }
657 
658  return QVariant( minVal );
659 }
660 
661 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
662 {
663  //lazy eval, so we need to evaluate nodes now
664 
665  //first node is layer id or name
666  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
668  QVariant value = node->eval( parent, context );
670  QgsVectorLayer* vl = getVectorLayer( value, parent );
671  if ( !vl )
672  {
673  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
674  return QVariant();
675  }
676 
677  // second node is aggregate type
678  node = getNode( values.at( 1 ), parent );
680  value = node->eval( parent, context );
682  bool ok = false;
684  if ( !ok )
685  {
686  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
687  return QVariant();
688  }
689 
690  // third node is subexpression (or field name)
691  node = getNode( values.at( 2 ), parent );
693  QString subExpression = node->dump();
694 
696  //optional forth node is filter
697  if ( values.count() > 3 )
698  {
699  node = getNode( values.at( 3 ), parent );
701  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
702  if ( !nl || nl->value().isValid() )
703  parameters.filter = node->dump();
704  }
705 
706  //optional fifth node is concatenator
707  if ( values.count() > 4 )
708  {
709  node = getNode( values.at( 4 ), parent );
711  value = node->eval( parent, context );
713  parameters.delimiter = value.toString();
714  }
715 
716  QVariant result;
717  if ( context )
718  {
719  QString cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter );
720 
721  QgsExpression subExp( subExpression );
722  QgsExpression filterExp( parameters.filter );
723  if ( filterExp.referencedVariables().contains( "parent" )
724  || filterExp.referencedVariables().contains( QString() )
725  || subExp.referencedVariables().contains( "parent" )
726  || subExp.referencedVariables().contains( QString() ) )
727  {
728  cacheKey += ':' + qHash( context->feature() );
729  }
730 
731  if ( context && context->hasCachedValue( cacheKey ) )
732  return context->cachedValue( cacheKey );
733 
734  QgsExpressionContext subContext( *context );
736  subScope->setVariable( "parent", context->feature() );
737  subContext.appendScope( subScope );
738  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
739 
740  context->setCachedValue( cacheKey, result );
741  }
742  else
743  {
744  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
745  }
746  if ( !ok )
747  {
748  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
749  return QVariant();
750  }
751 
752  return result;
753 }
754 
755 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
756 {
757  if ( !context )
758  {
759  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
760  return QVariant();
761  }
762 
763  // first step - find current layer
764  QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
765  if ( !vl )
766  {
767  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
768  return QVariant();
769  }
770 
771  //lazy eval, so we need to evaluate nodes now
772 
773  //first node is relation name
774  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
776  QVariant value = node->eval( parent, context );
778  QString relationId = value.toString();
779  // check relation exists
780  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
781  if ( !relation.isValid() || relation.referencedLayer() != vl )
782  {
783  // check for relations by name
784  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->relationsByName( relationId );
785  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
786  {
787  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
788  return QVariant();
789  }
790  else
791  {
792  relation = relations.at( 0 );
793  }
794  }
795 
796  QgsVectorLayer* childLayer = relation.referencingLayer();
797 
798  // second node is aggregate type
799  node = getNode( values.at( 1 ), parent );
801  value = node->eval( parent, context );
803  bool ok = false;
805  if ( !ok )
806  {
807  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
808  return QVariant();
809  }
810 
811  //third node is subexpression (or field name)
812  node = getNode( values.at( 2 ), parent );
814  QString subExpression = node->dump();
815 
816  //optional fourth node is concatenator
818  if ( values.count() > 3 )
819  {
820  node = getNode( values.at( 3 ), parent );
822  value = node->eval( parent, context );
824  parameters.delimiter = value.toString();
825  }
826 
827  FEAT_FROM_CONTEXT( context, f );
828  parameters.filter = relation.getRelatedFeaturesFilter( f );
829 
830  QString cacheKey = QStringLiteral( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
831  QString::number( static_cast< int >( aggregate ) ),
832  subExpression,
833  parameters.filter );
834  if ( context && context->hasCachedValue( cacheKey ) )
835  return context->cachedValue( cacheKey );
836 
837  QVariant result;
838  ok = false;
839 
840 
841  QgsExpressionContext subContext( *context );
842  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
843 
844  if ( !ok )
845  {
846  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
847  return QVariant();
848  }
849 
850  // cache value
851  if ( context )
852  context->setCachedValue( cacheKey, result );
853  return result;
854 }
855 
856 
857 static QVariant fcnAggregateGeneric( QgsAggregateCalculator::Aggregate aggregate, const QVariantList& values, QgsAggregateCalculator::AggregateParameters parameters, const QgsExpressionContext* context, QgsExpression *parent )
858 {
859  if ( !context )
860  {
861  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
862  return QVariant();
863  }
864 
865  // first step - find current layer
866  QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
867  if ( !vl )
868  {
869  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
870  return QVariant();
871  }
872 
873  //lazy eval, so we need to evaluate nodes now
874 
875  //first node is subexpression (or field name)
876  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
878  QString subExpression = node->dump();
879 
880  //optional second node is group by
881  QString groupBy;
882  if ( values.count() > 1 )
883  {
884  node = getNode( values.at( 1 ), parent );
886  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
887  if ( !nl || nl->value().isValid() )
888  groupBy = node->dump();
889  }
890 
891  //optional third node is filter
892  if ( values.count() > 2 )
893  {
894  node = getNode( values.at( 2 ), parent );
896  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
897  if ( !nl || nl->value().isValid() )
898  parameters.filter = node->dump();
899  }
900 
901  // build up filter with group by
902 
903  // find current group by value
904  if ( !groupBy.isEmpty() )
905  {
906  QgsExpression groupByExp( groupBy );
907  QVariant groupByValue = groupByExp.evaluate( context );
908  if ( !parameters.filter.isEmpty() )
909  parameters.filter = QStringLiteral( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
910  else
911  parameters.filter = QStringLiteral( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
912  }
913 
914  QString cacheKey = QStringLiteral( "agg:%1:%2:%3:%4" ).arg( vl->id(),
915  QString::number( static_cast< int >( aggregate ) ),
916  subExpression,
917  parameters.filter );
918  if ( context && context->hasCachedValue( cacheKey ) )
919  return context->cachedValue( cacheKey );
920 
921  QVariant result;
922  bool ok = false;
923 
924  QgsExpressionContext subContext( *context );
925  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
926 
927  if ( !ok )
928  {
929  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
930  return QVariant();
931  }
932 
933  // cache value
934  if ( context )
935  context->setCachedValue( cacheKey, result );
936  return result;
937 }
938 
939 
940 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
941 {
943 }
944 
945 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
946 {
948 }
949 
950 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
951 {
953 }
954 
955 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
956 {
958 }
959 
960 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
961 {
963 }
964 
965 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
966 {
968 }
969 
970 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
971 {
973 }
974 
975 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
976 {
978 }
979 
980 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
981 {
983 }
984 
985 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
986 {
988 }
989 
990 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
991 {
993 }
994 
995 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
996 {
998 }
999 
1000 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1001 {
1003 }
1004 
1005 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1006 {
1008 }
1009 
1010 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1011 {
1013 }
1014 
1015 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1016 {
1018 }
1019 
1020 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1021 {
1023 }
1024 
1025 static QVariant fcnAggregateCollectGeometry( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1026 {
1028 }
1029 
1030 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1031 {
1033 
1034  //fourth node is concatenator
1035  if ( values.count() > 3 )
1036  {
1037  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
1039  QVariant value = node->eval( parent, context );
1041  parameters.delimiter = value.toString();
1042  }
1043 
1044  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
1045 }
1046 
1047 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1048 {
1049  double minValue = getDoubleValue( values.at( 0 ), parent );
1050  double testValue = getDoubleValue( values.at( 1 ), parent );
1051  double maxValue = getDoubleValue( values.at( 2 ), parent );
1052 
1053  // force testValue to sit inside the range specified by the min and max value
1054  if ( testValue <= minValue )
1055  {
1056  return QVariant( minValue );
1057  }
1058  else if ( testValue >= maxValue )
1059  {
1060  return QVariant( maxValue );
1061  }
1062  else
1063  {
1064  return QVariant( testValue );
1065  }
1066 }
1067 
1068 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1069 {
1070  double x = getDoubleValue( values.at( 0 ), parent );
1071  return QVariant( floor( x ) );
1072 }
1073 
1074 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1075 {
1076  double x = getDoubleValue( values.at( 0 ), parent );
1077  return QVariant( ceil( x ) );
1078 }
1079 
1080 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1081 {
1082  return QVariant( getIntValue( values.at( 0 ), parent ) );
1083 }
1084 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1085 {
1086  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1087 }
1088 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1089 {
1090  return QVariant( getStringValue( values.at( 0 ), parent ) );
1091 }
1092 
1093 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1094 {
1095  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1096 }
1097 
1098 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1099 {
1100  Q_FOREACH ( const QVariant &value, values )
1101  {
1102  if ( value.isNull() )
1103  continue;
1104  return value;
1105  }
1106  return QVariant();
1107 }
1108 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1109 {
1110  QString str = getStringValue( values.at( 0 ), parent );
1111  return QVariant( str.toLower() );
1112 }
1113 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1114 {
1115  QString str = getStringValue( values.at( 0 ), parent );
1116  return QVariant( str.toUpper() );
1117 }
1118 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1119 {
1120  QString str = getStringValue( values.at( 0 ), parent );
1121  QStringList elems = str.split( ' ' );
1122  for ( int i = 0; i < elems.size(); i++ )
1123  {
1124  if ( elems[i].size() > 1 )
1125  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1126  }
1127  return QVariant( elems.join( QStringLiteral( " " ) ) );
1128 }
1129 
1130 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1131 {
1132  QString str = getStringValue( values.at( 0 ), parent );
1133  return QVariant( str.trimmed() );
1134 }
1135 
1136 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1137 {
1138  QString string1 = getStringValue( values.at( 0 ), parent );
1139  QString string2 = getStringValue( values.at( 1 ), parent );
1140  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1141 }
1142 
1143 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1144 {
1145  QString string1 = getStringValue( values.at( 0 ), parent );
1146  QString string2 = getStringValue( values.at( 1 ), parent );
1147  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1148 }
1149 
1150 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1151 {
1152  QString string1 = getStringValue( values.at( 0 ), parent );
1153  QString string2 = getStringValue( values.at( 1 ), parent );
1154  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1155  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1156 }
1157 
1158 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1159 {
1160  QString string = getStringValue( values.at( 0 ), parent );
1161  return QVariant( QgsStringUtils::soundex( string ) );
1162 }
1163 
1164 static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1165 {
1166  QChar character = QChar( getNativeIntValue( values.at( 0 ), parent ) );
1167  return QVariant( QString( character ) );
1168 }
1169 
1170 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1171 {
1172  if ( values.length() == 2 || values.length() == 3 )
1173  {
1174  QString str = getStringValue( values.at( 0 ), parent );
1175  qlonglong wrap = getIntValue( values.at( 1 ), parent );
1176 
1177  if ( !str.isEmpty() && wrap != 0 )
1178  {
1179  QString newstr;
1180  QRegExp rx;
1181  QString customdelimiter = getStringValue( values.at( 2 ), parent );
1182  int delimiterlength;
1183 
1184  if ( customdelimiter.length() > 0 )
1185  {
1186  rx.setPatternSyntax( QRegExp::FixedString );
1187  rx.setPattern( customdelimiter );
1188  delimiterlength = customdelimiter.length();
1189  }
1190  else
1191  {
1192  // \x200B is a ZERO-WIDTH SPACE, needed for worwrap to support a number of complex scripts (Indic, Arabic, etc.)
1193  rx.setPattern( QStringLiteral( "[\\s\\x200B]" ) );
1194  delimiterlength = 1;
1195  }
1196 
1197 
1198  QStringList lines = str.split( '\n' );
1199  int strlength, strcurrent, strhit, lasthit;
1200 
1201  for ( int i = 0; i < lines.size(); i++ )
1202  {
1203  strlength = lines[i].length();
1204  strcurrent = 0;
1205  strhit = 0;
1206  lasthit = 0;
1207 
1208  while ( strcurrent < strlength )
1209  {
1210  // positive wrap value = desired maximum line width to wrap
1211  // negative wrap value = desired minimum line width before wrap
1212  if ( wrap > 0 )
1213  {
1214  //first try to locate delimiter backwards
1215  strhit = lines[i].lastIndexOf( rx, strcurrent + wrap );
1216  if ( strhit == lasthit || strhit == -1 )
1217  {
1218  //if no new backward delimiter found, try to locate forward
1219  strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
1220  }
1221  lasthit = strhit;
1222  }
1223  else
1224  {
1225  strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
1226  }
1227  if ( strhit > -1 )
1228  {
1229  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1230  newstr.append( '\n' );
1231  strcurrent = strhit + delimiterlength;
1232  }
1233  else
1234  {
1235  newstr.append( lines[i].midRef( strcurrent ) );
1236  strcurrent = strlength;
1237  }
1238  }
1239  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1240  }
1241 
1242  return QVariant( newstr );
1243  }
1244  }
1245 
1246  return QVariant();
1247 }
1248 
1249 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1250 {
1251  // two variants, one for geometry, one for string
1252  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1253  {
1254  //geometry variant
1255  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1256  if ( geom.type() != QgsWkbTypes::LineGeometry )
1257  return QVariant();
1258 
1259  return QVariant( geom.length() );
1260  }
1261 
1262  //otherwise fall back to string variant
1263  QString str = getStringValue( values.at( 0 ), parent );
1264  return QVariant( str.length() );
1265 }
1266 
1267 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1268 {
1269  if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
1270  {
1271  QString str = getStringValue( values.at( 0 ), parent );
1272  QVariantMap map = getMapValue( values.at( 1 ), parent );
1273 
1274  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1275  {
1276  str = str.replace( it.key(), it.value().toString() );
1277  }
1278 
1279  return QVariant( str );
1280  }
1281  else if ( values.count() == 3 )
1282  {
1283  QString str = getStringValue( values.at( 0 ), parent );
1284  QVariantList before;
1285  QVariantList after;
1286  bool isSingleReplacement = false;
1287 
1288  if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1289  {
1290  before = QVariantList() << getStringValue( values.at( 1 ), parent );
1291  }
1292  else
1293  {
1294  before = getListValue( values.at( 1 ), parent );
1295  }
1296 
1297  if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1298  {
1299  after = QVariantList() << getStringValue( values.at( 2 ), parent );
1300  isSingleReplacement = true;
1301  }
1302  else
1303  {
1304  after = getListValue( values.at( 2 ), parent );
1305  }
1306 
1307  if ( !isSingleReplacement && before.length() != after.length() )
1308  {
1309  parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1310  return QVariant();
1311  }
1312 
1313  for ( int i = 0; i < before.length(); i++ )
1314  {
1315  str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1316  }
1317 
1318  return QVariant( str );
1319  }
1320  else
1321  {
1322  parent->setEvalErrorString( QObject::tr( "Function replace requires 2 or 3 arguments" ) );
1323  return QVariant();
1324  }
1325 }
1326 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1327 {
1328  QString str = getStringValue( values.at( 0 ), parent );
1329  QString regexp = getStringValue( values.at( 1 ), parent );
1330  QString after = getStringValue( values.at( 2 ), parent );
1331 
1332  QRegularExpression re( regexp );
1333  if ( !re.isValid() )
1334  {
1335  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1336  return QVariant();
1337  }
1338  return QVariant( str.replace( re, after ) );
1339 }
1340 
1341 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1342 {
1343  QString str = getStringValue( values.at( 0 ), parent );
1344  QString regexp = getStringValue( values.at( 1 ), parent );
1345 
1346  QRegularExpression re( regexp );
1347  if ( !re.isValid() )
1348  {
1349  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1350  return QVariant();
1351  }
1352  return QVariant(( str.indexOf( re ) + 1 ) );
1353 }
1354 
1355 static QVariant fcnRegexpMatches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1356 {
1357  QString str = getStringValue( values.at( 0 ), parent );
1358  QString regexp = getStringValue( values.at( 1 ), parent );
1359  QString empty = getStringValue( values.at( 2 ), parent );
1360 
1361  QRegularExpression re( regexp );
1362  if ( !re.isValid() )
1363  {
1364  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1365  return QVariant();
1366  }
1367 
1368  QRegularExpressionMatch matches = re.match( str );
1369  if ( matches.hasMatch() )
1370  {
1371  QVariantList array;
1372  QStringList list = matches.capturedTexts();
1373 
1374  // Skip the first string to only return captured groups
1375  for ( QStringList::const_iterator it = ++list.constBegin(); it != list.constEnd(); ++it )
1376  {
1377  array += ( !( *it ).isEmpty() ) ? *it : empty;
1378  }
1379 
1380  return QVariant( array );
1381  }
1382  else
1383  {
1384  return QVariant();
1385  }
1386 }
1387 
1388 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1389 {
1390  QString str = getStringValue( values.at( 0 ), parent );
1391  QString regexp = getStringValue( values.at( 1 ), parent );
1392 
1393  QRegularExpression re( regexp );
1394  if ( !re.isValid() )
1395  {
1396  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1397  return QVariant();
1398  }
1399 
1400  // extract substring
1401  QRegularExpressionMatch match = re.match( str );
1402  if ( match.hasMatch() )
1403  {
1404  // return first capture
1405  return QVariant( match.captured( 0 ) );
1406  }
1407  else
1408  {
1409  return QVariant( "" );
1410  }
1411 }
1412 
1413 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1414 {
1415  return QUuid::createUuid().toString();
1416 }
1417 
1418 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1419 {
1420  if ( !values.at( 0 ).isValid() || !values.at( 1 ).isValid() )
1421  return QVariant();
1422 
1423  QString str = getStringValue( values.at( 0 ), parent );
1424  qlonglong from = getIntValue( values.at( 1 ), parent );
1425 
1426  qlonglong len = 0;
1427  if ( values.at( 2 ).isValid() )
1428  len = getIntValue( values.at( 2 ), parent );
1429  else
1430  len = str.size();
1431 
1432  if ( from < 0 )
1433  {
1434  from = str.size() + from;
1435  if ( from < 0 )
1436  {
1437  from = 0;
1438  }
1439  }
1440  else if ( from > 0 )
1441  {
1442  //account for the fact that substr() starts at 1
1443  from -= 1;
1444  }
1445 
1446  if ( len < 0 )
1447  {
1448  len = str.size() + len - from;
1449  if ( len < 0 )
1450  {
1451  len = 0;
1452  }
1453  }
1454 
1455  return QVariant( str.mid( from, len ) );
1456 }
1457 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1458 {
1459  FEAT_FROM_CONTEXT( context, f );
1460  // TODO: handling of 64-bit feature ids?
1461  return QVariant( static_cast< int >( f.id() ) );
1462 }
1463 
1464 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1465 {
1466  if ( !context )
1467  return QVariant();
1468 
1469  return context->feature();
1470 }
1471 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1472 {
1473  QgsFeature feat = getFeature( values.at( 0 ), parent );
1474  QString attr = getStringValue( values.at( 1 ), parent );
1475 
1476  return feat.attribute( attr );
1477 }
1478 
1479 static QVariant fcnIsSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
1480 {
1481  QgsVectorLayer* layer = nullptr;
1482  QgsFeature feature;
1483 
1484  if ( values.isEmpty() )
1485  {
1486  feature = context->feature();
1487  layer = getVectorLayer( context->variable( "layer" ), parent );
1488  }
1489  else if ( values.size() == 1 )
1490  {
1491  layer = getVectorLayer( context->variable( "layer" ), parent );
1492  feature = getFeature( values.at( 0 ), parent );
1493  }
1494  else if ( values.size() == 2 )
1495  {
1496  layer = getVectorLayer( values.at( 0 ), parent );
1497  feature = getFeature( values.at( 1 ), parent );
1498  }
1499  else
1500  {
1501  parent->setEvalErrorString( QObject::tr( "Function `is_selected` requires no more than two parameters. %1 given." ).arg( values.length() ) );
1502  return QVariant();
1503  }
1504 
1505  if ( !layer || !feature.isValid() )
1506  {
1507  return QVariant( QVariant::Bool );
1508  }
1509 
1510  return layer->selectedFeatureIds().contains( feature.id() );
1511 }
1512 
1513 static QVariant fcnNumSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
1514 {
1515  QgsVectorLayer* layer = nullptr;
1516 
1517  if ( values.isEmpty() )
1518  layer = getVectorLayer( context->variable( "layer" ), parent );
1519  else if ( values.count() == 1 )
1520  layer = getVectorLayer( values.at( 0 ), parent );
1521  else
1522  {
1523  parent->setEvalErrorString( QObject::tr( "Function `num_selected` requires no more than one parameter. %1 given." ).arg( values.length() ) );
1524  return QVariant();
1525  }
1526 
1527  if ( !layer )
1528  {
1529  return QVariant( QVariant::LongLong );
1530  }
1531 
1532  return layer->selectedFeatureCount();
1533 }
1534 
1535 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1536 {
1537  QString concat;
1538  Q_FOREACH ( const QVariant &value, values )
1539  {
1540  concat += getStringValue( value, parent );
1541  }
1542  return concat;
1543 }
1544 
1545 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1546 {
1547  QString string = getStringValue( values.at( 0 ), parent );
1548  return string.indexOf( getStringValue( values.at( 1 ), parent ) ) + 1;
1549 }
1550 
1551 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1552 {
1553  QString string = getStringValue( values.at( 0 ), parent );
1554  qlonglong pos = getIntValue( values.at( 1 ), parent );
1555  return string.right( pos );
1556 }
1557 
1558 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1559 {
1560  QString string = getStringValue( values.at( 0 ), parent );
1561  qlonglong pos = getIntValue( values.at( 1 ), parent );
1562  return string.left( pos );
1563 }
1564 
1565 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1566 {
1567  QString string = getStringValue( values.at( 0 ), parent );
1568  qlonglong length = getIntValue( values.at( 1 ), parent );
1569  QString fill = getStringValue( values.at( 2 ), parent );
1570  return string.leftJustified( length, fill.at( 0 ), true );
1571 }
1572 
1573 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1574 {
1575  QString string = getStringValue( values.at( 0 ), parent );
1576  qlonglong length = getIntValue( values.at( 1 ), parent );
1577  QString fill = getStringValue( values.at( 2 ), parent );
1578  return string.rightJustified( length, fill.at( 0 ), true );
1579 }
1580 
1581 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1582 {
1583  QString string = getStringValue( values.at( 0 ), parent );
1584  for ( int n = 1; n < values.length(); n++ )
1585  {
1586  string = string.arg( getStringValue( values.at( n ), parent ) );
1587  }
1588  return string;
1589 }
1590 
1591 
1592 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1593 {
1594  return QVariant( QDateTime::currentDateTime() );
1595 }
1596 
1597 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1598 {
1599  return QVariant( getDateValue( values.at( 0 ), parent ) );
1600 }
1601 
1602 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1603 {
1604  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1605 }
1606 
1607 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1608 {
1609  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1610 }
1611 
1612 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1613 {
1614  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1615  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1616  int seconds = d2.secsTo( d1 );
1617  return QVariant::fromValue( QgsInterval( seconds ) );
1618 }
1619 
1620 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1621 {
1622  if ( !values.at( 0 ).canConvert<QDate>() )
1623  return QVariant();
1624 
1625  QDate date = getDateValue( values.at( 0 ), parent );
1626  if ( !date.isValid() )
1627  return QVariant();
1628 
1629  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1630  // (to match PostgreSQL behavior)
1631  return date.dayOfWeek() % 7;
1632 }
1633 
1634 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1635 {
1636  QVariant value = values.at( 0 );
1637  QgsInterval inter = getInterval( value, parent, false );
1638  if ( inter.isValid() )
1639  {
1640  return QVariant( inter.days() );
1641  }
1642  else
1643  {
1644  QDateTime d1 = getDateTimeValue( value, parent );
1645  return QVariant( d1.date().day() );
1646  }
1647 }
1648 
1649 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1650 {
1651  QVariant value = values.at( 0 );
1652  QgsInterval inter = getInterval( value, parent, false );
1653  if ( inter.isValid() )
1654  {
1655  return QVariant( inter.years() );
1656  }
1657  else
1658  {
1659  QDateTime d1 = getDateTimeValue( value, parent );
1660  return QVariant( d1.date().year() );
1661  }
1662 }
1663 
1664 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1665 {
1666  QVariant value = values.at( 0 );
1667  QgsInterval inter = getInterval( value, parent, false );
1668  if ( inter.isValid() )
1669  {
1670  return QVariant( inter.months() );
1671  }
1672  else
1673  {
1674  QDateTime d1 = getDateTimeValue( value, parent );
1675  return QVariant( d1.date().month() );
1676  }
1677 }
1678 
1679 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1680 {
1681  QVariant value = values.at( 0 );
1682  QgsInterval inter = getInterval( value, parent, false );
1683  if ( inter.isValid() )
1684  {
1685  return QVariant( inter.weeks() );
1686  }
1687  else
1688  {
1689  QDateTime d1 = getDateTimeValue( value, parent );
1690  return QVariant( d1.date().weekNumber() );
1691  }
1692 }
1693 
1694 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1695 {
1696  QVariant value = values.at( 0 );
1697  QgsInterval inter = getInterval( value, parent, false );
1698  if ( inter.isValid() )
1699  {
1700  return QVariant( inter.hours() );
1701  }
1702  else
1703  {
1704  QTime t1 = getTimeValue( value, parent );
1705  return QVariant( t1.hour() );
1706  }
1707 }
1708 
1709 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1710 {
1711  QVariant value = values.at( 0 );
1712  QgsInterval inter = getInterval( value, parent, false );
1713  if ( inter.isValid() )
1714  {
1715  return QVariant( inter.minutes() );
1716  }
1717  else
1718  {
1719  QTime t1 = getTimeValue( value, parent );
1720  return QVariant( t1.minute() );
1721  }
1722 }
1723 
1724 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1725 {
1726  QVariant value = values.at( 0 );
1727  QgsInterval inter = getInterval( value, parent, false );
1728  if ( inter.isValid() )
1729  {
1730  return QVariant( inter.seconds() );
1731  }
1732  else
1733  {
1734  QTime t1 = getTimeValue( value, parent );
1735  return QVariant( t1.second() );
1736  }
1737 }
1738 
1739 static QVariant fcnEpoch( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1740 {
1741  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
1742  if ( dt.isValid() )
1743  {
1744  return QVariant( dt.toMSecsSinceEpoch() );
1745  }
1746  else
1747  {
1748  return QVariant();
1749  }
1750 }
1751 
1752 #define ENSURE_GEOM_TYPE(f, g, geomtype) \
1753  if ( !(f).hasGeometry() ) \
1754  return QVariant(); \
1755  QgsGeometry g = (f).geometry(); \
1756  if ( (g).type() != (geomtype) ) \
1757  return QVariant();
1758 
1759 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1760 {
1761  FEAT_FROM_CONTEXT( context, f );
1763  if ( g.isMultipart() )
1764  {
1765  return g.asMultiPoint().at( 0 ).x();
1766  }
1767  else
1768  {
1769  return g.asPoint().x();
1770  }
1771 }
1772 
1773 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1774 {
1775  FEAT_FROM_CONTEXT( context, f );
1777  if ( g.isMultipart() )
1778  {
1779  return g.asMultiPoint().at( 0 ).y();
1780  }
1781  else
1782  {
1783  return g.asPoint().y();
1784  }
1785 }
1786 
1787 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1788 {
1789  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1790  if ( geom.isNull() )
1791  return QVariant();
1792 
1793  //if single point, return the point's x coordinate
1794  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1795  {
1796  return geom.asPoint().x();
1797  }
1798 
1799  //otherwise return centroid x
1800  QgsGeometry centroid = geom.centroid();
1801  QVariant result( centroid.asPoint().x() );
1802  return result;
1803 }
1804 
1805 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1806 {
1807  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1808  if ( geom.isNull() )
1809  return QVariant();
1810 
1811  //if single point, return the point's y coordinate
1812  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1813  {
1814  return geom.asPoint().y();
1815  }
1816 
1817  //otherwise return centroid y
1818  QgsGeometry centroid = geom.centroid();
1819  QVariant result( centroid.asPoint().y() );
1820  return result;
1821 }
1822 
1823 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1824 {
1825  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1826  if ( geom.isNull() )
1827  return QVariant(); //or 0?
1828 
1829  //if single point, return the point's z coordinate
1830  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1831  {
1832  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1833  if ( point )
1834  return point->z();
1835  }
1836 
1837  return QVariant();
1838 }
1839 
1840 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1841 {
1842  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1843  if ( geom.isNull() )
1844  return QVariant(); //or 0?
1845 
1846  //if single point, return the point's m value
1847  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1848  {
1849  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1850  if ( point )
1851  return point->m();
1852  }
1853 
1854  return QVariant();
1855 }
1856 
1857 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1858 {
1859  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1860 
1861  if ( geom.isNull() )
1862  return QVariant();
1863 
1864  //idx is 1 based
1865  qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;
1866 
1867  QgsVertexId vId;
1868  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1869  {
1870  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1871  return QVariant();
1872  }
1873 
1874  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1875  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1876 }
1877 
1878 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1879 {
1880  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1881 
1882  if ( geom.isNull() )
1883  return QVariant();
1884 
1885  QgsVertexId vId;
1886  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1887  {
1888  return QVariant();
1889  }
1890 
1891  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1892  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1893 }
1894 
1895 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1896 {
1897  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1898 
1899  if ( geom.isNull() )
1900  return QVariant();
1901 
1902  QgsVertexId vId;
1903  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1904  {
1905  return QVariant();
1906  }
1907 
1908  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1909  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1910 }
1911 
1912 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1913 {
1914  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1915 
1916  if ( geom.isNull() )
1917  return QVariant();
1918 
1919  bool ignoreClosing = false;
1920  if ( values.length() > 1 )
1921  {
1922  ignoreClosing = getIntValue( values.at( 1 ), parent );
1923  }
1924 
1925  QgsMultiPointV2* mp = new QgsMultiPointV2();
1926 
1927  Q_FOREACH ( const QgsRingSequence &part, geom.geometry()->coordinateSequence() )
1928  {
1929  Q_FOREACH ( const QgsPointSequence &ring, part )
1930  {
1931  bool skipLast = false;
1932  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1933  {
1934  skipLast = true;
1935  }
1936 
1937  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1938  {
1939  mp->addGeometry( ring.at( i ).clone() );
1940  }
1941  }
1942  }
1943 
1944  return QVariant::fromValue( QgsGeometry( mp ) );
1945 }
1946 
1947 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1948 {
1949  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1950 
1951  if ( geom.isNull() )
1952  return QVariant();
1953 
1954  QList< QgsLineString* > linesToProcess = QgsGeometryUtils::extractLineStrings( geom.geometry() );
1955 
1956  //ok, now we have a complete list of segmentized lines from the geometry
1958  Q_FOREACH ( QgsLineString* line, linesToProcess )
1959  {
1960  for ( int i = 0; i < line->numPoints() - 1; ++i )
1961  {
1962  QgsLineString* segment = new QgsLineString();
1963  segment->setPoints( QgsPointSequence()
1964  << line->pointN( i )
1965  << line->pointN( i + 1 ) );
1966  ml->addGeometry( segment );
1967  }
1968  delete line;
1969  }
1970 
1971  return QVariant::fromValue( QgsGeometry( ml ) );
1972 }
1973 
1974 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1975 {
1976  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1977 
1978  if ( geom.isNull() )
1979  return QVariant();
1980 
1981  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
1982  if ( !curvePolygon )
1983  return QVariant();
1984 
1985  //idx is 1 based
1986  qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;
1987 
1988  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1989  return QVariant();
1990 
1991  QgsCurve* curve = static_cast< QgsCurve* >( curvePolygon->interiorRing( idx )->clone() );
1992  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1993  return result;
1994 }
1995 
1996 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1997 {
1998  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1999 
2000  if ( geom.isNull() )
2001  return QVariant();
2002 
2003  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
2004  if ( !collection )
2005  return QVariant();
2006 
2007  //idx is 1 based
2008  qlonglong idx = getIntValue( values.at( 1 ), parent ) - 1;
2009 
2010  if ( idx < 0 || idx >= collection->numGeometries() )
2011  return QVariant();
2012 
2013  QgsAbstractGeometry* part = collection->geometryN( idx )->clone();
2014  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
2015  return result;
2016 }
2017 
2018 static QVariant fcnBoundary( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2019 {
2020  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2021 
2022  if ( geom.isNull() )
2023  return QVariant();
2024 
2025  QgsAbstractGeometry* boundary = geom.geometry()->boundary();
2026  if ( !boundary )
2027  return QVariant();
2028 
2029  return QVariant::fromValue( QgsGeometry( boundary ) );
2030 }
2031 
2032 static QVariant fcnLineMerge( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2033 {
2034  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2035 
2036  if ( geom.isNull() )
2037  return QVariant();
2038 
2039  QgsGeometry merged = geom.mergeLines();
2040  if ( merged.isNull() )
2041  return QVariant();
2042 
2043  return QVariant::fromValue( merged );
2044 }
2045 
2046 static QVariant fcnSimplify( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2047 {
2048  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2049 
2050  if ( geom.isNull() )
2051  return QVariant();
2052 
2053  double tolerance = getDoubleValue( values.at( 1 ), parent );
2054 
2055  QgsGeometry simplified = geom.simplify( tolerance );
2056  if ( simplified.isNull() )
2057  return QVariant();
2058 
2059  return simplified;
2060 }
2061 
2062 static QVariant fcnSimplifyVW( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2063 {
2064  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2065 
2066  if ( geom.isNull() )
2067  return QVariant();
2068 
2069  double tolerance = getDoubleValue( values.at( 1 ), parent );
2070 
2072 
2073  QgsGeometry simplified = simplifier.simplify( geom );
2074  if ( simplified.isNull() )
2075  return QVariant();
2076 
2077  return simplified;
2078 }
2079 
2080 static QVariant fcnSmooth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2081 {
2082  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2083 
2084  if ( geom.isNull() )
2085  return QVariant();
2086 
2087  int iterations = qMin( getNativeIntValue( values.at( 1 ), parent ), 10 );
2088  double offset = qBound( 0.0, getDoubleValue( values.at( 2 ), parent ), 0.5 );
2089  double minLength = getDoubleValue( values.at( 3 ), parent );
2090  double maxAngle = qBound( 0.0, getDoubleValue( values.at( 4 ), parent ), 180.0 );
2091 
2092  QgsGeometry smoothed = geom.smooth( iterations, offset, minLength, maxAngle );
2093  if ( smoothed.isNull() )
2094  return QVariant();
2095 
2096  return smoothed;
2097 }
2098 
2099 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2100 {
2101  if ( values.count() < 2 || values.count() > 4 )
2102  {
2103  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
2104  return QVariant();
2105  }
2106 
2107  double x = getDoubleValue( values.at( 0 ), parent );
2108  double y = getDoubleValue( values.at( 1 ), parent );
2109  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
2110  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
2111  switch ( values.count() )
2112  {
2113  case 2:
2114  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
2115  case 3:
2116  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointZ, x, y, z ) ) );
2117  case 4:
2118  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointZM, x, y, z, m ) ) );
2119  }
2120  return QVariant(); //avoid warning
2121 }
2122 
2123 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2124 {
2125  double x = getDoubleValue( values.at( 0 ), parent );
2126  double y = getDoubleValue( values.at( 1 ), parent );
2127  double m = getDoubleValue( values.at( 2 ), parent );
2128  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointM, x, y, 0.0, m ) ) );
2129 }
2130 
2131 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2132 {
2133  if ( values.count() < 2 )
2134  {
2135  return QVariant();
2136  }
2137 
2138  QgsLineString* lineString = new QgsLineString();
2139  lineString->clear();
2140 
2141  Q_FOREACH ( const QVariant& value, values )
2142  {
2143  QgsGeometry geom = getGeometry( value, parent );
2144  if ( geom.isNull() )
2145  continue;
2146 
2147  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2148  continue;
2149 
2150  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
2151  if ( !point )
2152  continue;
2153 
2154  lineString->addVertex( *point );
2155  }
2156 
2157  return QVariant::fromValue( QgsGeometry( lineString ) );
2158 }
2159 
2160 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2161 {
2162  if ( values.count() < 1 )
2163  {
2164  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
2165  return QVariant();
2166  }
2167 
2168  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
2169  if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isMultipart() || outerRing.isNull() )
2170  return QVariant();
2171 
2172  QgsPolygonV2* polygon = new QgsPolygonV2();
2173  polygon->setExteriorRing( dynamic_cast< QgsCurve* >( outerRing.geometry()->clone() ) );
2174 
2175  for ( int i = 1; i < values.count(); ++i )
2176  {
2177  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
2178  if ( ringGeom.isNull() )
2179  continue;
2180 
2181  if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isMultipart() || ringGeom.isNull() )
2182  continue;
2183 
2184  polygon->addInteriorRing( dynamic_cast< QgsCurve* >( ringGeom.geometry()->clone() ) );
2185  }
2186 
2187  return QVariant::fromValue( QgsGeometry( polygon ) );
2188 }
2189 
2190 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
2191 {
2192  FEAT_FROM_CONTEXT( context, f );
2193  qlonglong idx = getIntValue( values.at( 0 ), parent );
2194  QgsGeometry g = f.geometry();
2195  if ( g.isNull() )
2196  return QVariant();
2197 
2198  if ( idx < 0 )
2199  {
2200  idx += g.geometry()->nCoordinates();
2201  }
2202  if ( idx < 0 || idx >= g.geometry()->nCoordinates() )
2203  {
2204  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
2205  return QVariant();
2206  }
2207 
2208  QgsPoint p = g.vertexAt( idx );
2209  return QVariant( QPointF( p.x(), p.y() ) );
2210 }
2211 
2212 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
2213 {
2214  QVariant v = pointAt( values, f, parent );
2215  if ( v.type() == QVariant::PointF )
2216  return QVariant( v.toPointF().x() );
2217  else
2218  return QVariant();
2219 }
2220 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
2221 {
2222  QVariant v = pointAt( values, f, parent );
2223  if ( v.type() == QVariant::PointF )
2224  return QVariant( v.toPointF().y() );
2225  else
2226  return QVariant();
2227 }
2228 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
2229 {
2230  FEAT_FROM_CONTEXT( context, f );
2231  QgsGeometry geom = f.geometry();
2232  if ( !geom.isNull() )
2233  return QVariant::fromValue( geom );
2234  else
2235  return QVariant();
2236 }
2237 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2238 {
2239  QString wkt = getStringValue( values.at( 0 ), parent );
2240  QgsGeometry geom = QgsGeometry::fromWkt( wkt );
2241  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2242  return result;
2243 }
2244 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2245 {
2246  QString gml = getStringValue( values.at( 0 ), parent );
2248  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2249  return result;
2250 }
2251 
2252 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2253 {
2254  FEAT_FROM_CONTEXT( context, f );
2256  QgsDistanceArea* calc = parent->geomCalculator();
2257  if ( calc )
2258  {
2259  double area = calc->measureArea( f.geometry() );
2260  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
2261  return QVariant( area );
2262  }
2263  else
2264  {
2265  return QVariant( f.geometry().area() );
2266  }
2267 }
2268 
2269 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2270 {
2271  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2272 
2273  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
2274  return QVariant();
2275 
2276  return QVariant( geom.area() );
2277 }
2278 
2279 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2280 {
2281  FEAT_FROM_CONTEXT( context, f );
2283  QgsDistanceArea* calc = parent->geomCalculator();
2284  if ( calc )
2285  {
2286  double len = calc->measureLength( f.geometry() );
2287  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2288  return QVariant( len );
2289  }
2290  else
2291  {
2292  return QVariant( f.geometry().length() );
2293  }
2294 }
2295 
2296 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2297 {
2298  FEAT_FROM_CONTEXT( context, f );
2300  QgsDistanceArea* calc = parent->geomCalculator();
2301  if ( calc )
2302  {
2303  double len = calc->measurePerimeter( f.geometry() );
2304  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2305  return QVariant( len );
2306  }
2307  else
2308  {
2309  return f.geometry().isNull() ? QVariant( 0 ) : QVariant( f.geometry().geometry()->perimeter() );
2310  }
2311 }
2312 
2313 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2314 {
2315  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2316 
2317  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
2318  return QVariant();
2319 
2320  //length for polygons = perimeter
2321  return QVariant( geom.length() );
2322 }
2323 
2324 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2325 {
2326  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2327  return QVariant( geom.isNull() ? 0 : geom.geometry()->nCoordinates() );
2328 }
2329 
2330 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2331 {
2332  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2333  if ( geom.isNull() )
2334  return QVariant();
2335 
2336  return QVariant( geom.geometry()->partCount() );
2337 }
2338 
2339 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2340 {
2341  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2342 
2343  if ( geom.isNull() )
2344  return QVariant();
2345 
2346  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
2347  if ( curvePolygon )
2348  return QVariant( curvePolygon->numInteriorRings() );
2349 
2350  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
2351  if ( collection )
2352  {
2353  //find first CurvePolygon in collection
2354  for ( int i = 0; i < collection->numGeometries(); ++i )
2355  {
2356  curvePolygon = dynamic_cast< QgsCurvePolygon*>( collection->geometryN( i ) );
2357  if ( !curvePolygon )
2358  continue;
2359 
2360  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2361  }
2362  }
2363 
2364  return QVariant();
2365 }
2366 
2367 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2368 {
2369  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2370 
2371  if ( geom.isNull() )
2372  return QVariant();
2373 
2374  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
2375  if ( curvePolygon )
2376  return QVariant( curvePolygon->ringCount() );
2377 
2378  bool foundPoly = false;
2379  int ringCount = 0;
2380  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
2381  if ( collection )
2382  {
2383  //find CurvePolygons in collection
2384  for ( int i = 0; i < collection->numGeometries(); ++i )
2385  {
2386  curvePolygon = dynamic_cast< QgsCurvePolygon*>( collection->geometryN( i ) );
2387  if ( !curvePolygon )
2388  continue;
2389 
2390  foundPoly = true;
2391  ringCount += curvePolygon->ringCount();
2392  }
2393  }
2394 
2395  if ( !foundPoly )
2396  return QVariant();
2397 
2398  return QVariant( ringCount );
2399 }
2400 
2401 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2402 {
2403  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2404  QgsGeometry geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2405  QVariant result = !geomBounds.isNull() ? QVariant::fromValue( geomBounds ) : QVariant();
2406  return result;
2407 }
2408 
2409 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2410 {
2411  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2412  return QVariant::fromValue( geom.boundingBox().width() );
2413 }
2414 
2415 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2416 {
2417  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2418  return QVariant::fromValue( geom.boundingBox().height() );
2419 }
2420 
2421 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2422 {
2423  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2424  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2425 }
2426 
2427 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2428 {
2429  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2430  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2431 }
2432 
2433 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2434 {
2435  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2436  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2437 }
2438 
2439 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2440 {
2441  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2442  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2443 }
2444 
2445 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2446 {
2447  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2448  if ( fGeom.isNull() )
2449  return QVariant();
2450 
2451  QgsCurve* curve = dynamic_cast< QgsCurve* >( fGeom.geometry() );
2452  if ( !curve )
2453  return QVariant();
2454 
2455  return QVariant::fromValue( curve->isClosed() );
2456 }
2457 
2458 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2459 {
2460  if ( values.length() < 2 || values.length() > 3 )
2461  return QVariant();
2462 
2463  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2464  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2465 
2466  if ( fGeom.isNull() || sGeom.isNull() )
2467  return QVariant();
2468 
2469  std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( fGeom.geometry() ) );
2470 
2471  if ( values.length() == 2 )
2472  {
2473  //two geometry arguments, return relation
2474  QString result = engine->relate( *sGeom.geometry() );
2475  return QVariant::fromValue( result );
2476  }
2477  else
2478  {
2479  //three arguments, test pattern
2480  QString pattern = getStringValue( values.at( 2 ), parent );
2481  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2482  return QVariant::fromValue( result );
2483  }
2484 }
2485 
2486 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2487 {
2488  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2489  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2490  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2491 }
2492 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2493 {
2494  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2495  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2496  return fGeom.disjoint( sGeom ) ? TVL_True : TVL_False;
2497 }
2498 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2499 {
2500  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2501  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2502  return fGeom.intersects( sGeom ) ? TVL_True : TVL_False;
2503 }
2504 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2505 {
2506  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2507  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2508  return fGeom.touches( sGeom ) ? TVL_True : TVL_False;
2509 }
2510 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2511 {
2512  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2513  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2514  return fGeom.crosses( sGeom ) ? TVL_True : TVL_False;
2515 }
2516 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2517 {
2518  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2519  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2520  return fGeom.contains( sGeom ) ? TVL_True : TVL_False;
2521 }
2522 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2523 {
2524  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2525  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2526  return fGeom.overlaps( sGeom ) ? TVL_True : TVL_False;
2527 }
2528 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2529 {
2530  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2531  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2532  return fGeom.within( sGeom ) ? TVL_True : TVL_False;
2533 }
2534 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2535 {
2536  if ( values.length() < 2 || values.length() > 3 )
2537  return QVariant();
2538 
2539  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2540  double dist = getDoubleValue( values.at( 1 ), parent );
2541  qlonglong seg = 8;
2542  if ( values.length() == 3 )
2543  seg = getIntValue( values.at( 2 ), parent );
2544 
2545  QgsGeometry geom = fGeom.buffer( dist, seg );
2546  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2547  return result;
2548 }
2549 
2550 static QVariant fcnOffsetCurve( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2551 {
2552  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2553  double dist = getDoubleValue( values.at( 1 ), parent );
2554  qlonglong segments = getIntValue( values.at( 2 ), parent );
2555  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
2556  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
2557  return QVariant();
2558  double mitreLimit = getDoubleValue( values.at( 3 ), parent );
2559 
2560  QgsGeometry geom = fGeom.offsetCurve( dist, segments, join, mitreLimit );
2561  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2562  return result;
2563 }
2564 
2565 static QVariant fcnSingleSidedBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2566 {
2567  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2568  double dist = getDoubleValue( values.at( 1 ), parent );
2569  qlonglong segments = getIntValue( values.at( 2 ), parent );
2570  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
2571  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
2572  return QVariant();
2573  double mitreLimit = getDoubleValue( values.at( 3 ), parent );
2574 
2575  QgsGeometry geom = fGeom.singleSidedBuffer( dist, segments, QgsGeometry::SideLeft, join, mitreLimit );
2576  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2577  return result;
2578 }
2579 
2580 static QVariant fcnExtend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2581 {
2582  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2583  double distStart = getDoubleValue( values.at( 1 ), parent );
2584  double distEnd = getDoubleValue( values.at( 2 ), parent );
2585 
2586  QgsGeometry geom = fGeom.extendLine( distStart, distEnd );
2587  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2588  return result;
2589 }
2590 
2591 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2592 {
2593  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2594  double dx = getDoubleValue( values.at( 1 ), parent );
2595  double dy = getDoubleValue( values.at( 2 ), parent );
2596  fGeom.translate( dx, dy );
2597  return QVariant::fromValue( fGeom );
2598 }
2599 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2600 {
2601  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2602  QgsGeometry geom = fGeom.centroid();
2603  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2604  return result;
2605 }
2606 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2607 {
2608  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2609  QgsGeometry geom = fGeom.pointOnSurface();
2610  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2611  return result;
2612 }
2613 
2614 static QVariant fcnPoleOfInaccessibility( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2615 {
2616  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2617  double tolerance = getDoubleValue( values.at( 1 ), parent );
2618  QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
2619  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2620  return result;
2621 }
2622 
2623 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2624 {
2625  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2626  QgsGeometry geom = fGeom.convexHull();
2627  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2628  return result;
2629 }
2630 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2631 {
2632  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2633  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2634  QgsGeometry geom = fGeom.difference( sGeom );
2635  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2636  return result;
2637 }
2638 
2639 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2640 {
2641  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2642  if ( fGeom.isNull() )
2643  return QVariant();
2644 
2645  QgsCurve* curve = dynamic_cast< QgsCurve* >( fGeom.geometry() );
2646  if ( !curve )
2647  return QVariant();
2648 
2649  QgsCurve* reversed = curve->reversed();
2650  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2651  return result;
2652 }
2653 
2654 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2655 {
2656  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2657  if ( fGeom.isNull() )
2658  return QVariant();
2659 
2660  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( fGeom.geometry() );
2661  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2662  return QVariant();
2663 
2664  QgsCurve* exterior = static_cast< QgsCurve* >( curvePolygon->exteriorRing()->clone() );
2665  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2666  return result;
2667 }
2668 
2669 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2670 {
2671  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2672  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2673  return QVariant( fGeom.distance( sGeom ) );
2674 }
2675 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2676 {
2677  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2678  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2679  QgsGeometry geom = fGeom.intersection( sGeom );
2680  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2681  return result;
2682 }
2683 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2684 {
2685  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2686  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2687  QgsGeometry geom = fGeom.symDifference( sGeom );
2688  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2689  return result;
2690 }
2691 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2692 {
2693  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2694  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2695  QgsGeometry geom = fGeom.combine( sGeom );
2696  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2697  return result;
2698 }
2699 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2700 {
2701  if ( values.length() < 1 || values.length() > 2 )
2702  return QVariant();
2703 
2704  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2705  qlonglong prec = 8;
2706  if ( values.length() == 2 )
2707  prec = getIntValue( values.at( 1 ), parent );
2708  QString wkt = fGeom.exportToWkt( prec );
2709  return QVariant( wkt );
2710 }
2711 
2712 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2713 {
2714  if ( values.length() != 2 )
2715  {
2716  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2717  return QVariant();
2718  }
2719 
2720  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2721  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2722 
2723  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2724  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2725 
2726  if ( !pt1 || !pt2 )
2727  {
2728  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2729  return QVariant();
2730  }
2731 
2732  // Code from postgis
2733  if ( pt1->x() == pt2->x() )
2734  {
2735  if ( pt1->y() < pt2->y() )
2736  return 0.0;
2737  else if ( pt1->y() > pt2->y() )
2738  return M_PI;
2739  else
2740  return 0;
2741  }
2742 
2743  if ( pt1->y() == pt2->y() )
2744  {
2745  if ( pt1->x() < pt2->x() )
2746  return M_PI / 2;
2747  else if ( pt1->x() > pt2->x() )
2748  return M_PI + ( M_PI / 2 );
2749  else
2750  return 0;
2751  }
2752 
2753  if ( pt1->x() < pt2->x() )
2754  {
2755  if ( pt1->y() < pt2->y() )
2756  {
2757  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2758  }
2759  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2760  {
2761  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2762  + ( M_PI / 2 );
2763  }
2764  }
2765 
2766  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2767  {
2768  if ( pt1->y() > pt2->y() )
2769  {
2770  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2771  + M_PI;
2772  }
2773  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2774  {
2775  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2776  + ( M_PI + ( M_PI / 2 ) );
2777  }
2778  }
2779 }
2780 
2781 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2782 {
2783  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2784 
2785  if ( geom.type() != QgsWkbTypes::PointGeometry )
2786  {
2787  parent->setEvalErrorString( QStringLiteral( "'project' requires a point geometry" ) );
2788  return QVariant();
2789  }
2790 
2791  double distance = getDoubleValue( values.at( 1 ), parent );
2792  double azimuth = getDoubleValue( values.at( 2 ), parent );
2793  double inclination = getDoubleValue( values.at( 3 ), parent );
2794 
2795  const QgsPointV2* p = static_cast<const QgsPointV2*>( geom.geometry() );
2796  QgsPointV2 newPoint = p->project( distance, 180.0 * azimuth / M_PI, 180.0 * inclination / M_PI );
2797 
2798  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint ) ) );
2799 }
2800 
2801 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2802 {
2803  if ( values.length() != 3 )
2804  return QVariant();
2805 
2806  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2807  double x = getDoubleValue( values.at( 1 ), parent );
2808  double y = getDoubleValue( values.at( 2 ), parent );
2809 
2810  QgsGeometry geom = fGeom.extrude( x, y );
2811 
2812  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2813  return result;
2814 }
2815 
2816 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2817 {
2818  if ( values.length() < 2 )
2819  return QVariant();
2820 
2821  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2822 
2823  if ( !fGeom.isMultipart() )
2824  return values.at( 0 );
2825 
2826  QString expString = getStringValue( values.at( 1 ), parent );
2827  bool asc = values.value( 2 ).toBool();
2828 
2829  QgsExpressionContext* unconstedContext = nullptr;
2830  QgsFeature f;
2831  if ( ctx )
2832  {
2833  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2834  // so no reason to worry
2835  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2836  f = ctx->feature();
2837  }
2838  else
2839  {
2840  // If there's no context provided, create a fake one
2841  unconstedContext = new QgsExpressionContext();
2842  }
2843 
2844  QgsGeometryCollection* collection = dynamic_cast<QgsGeometryCollection*>( fGeom.geometry() );
2845  Q_ASSERT( collection ); // Should have failed the multipart check above
2846 
2848  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2849  QgsExpressionSorter sorter( orderBy );
2850 
2851  QList<QgsFeature> partFeatures;
2852  partFeatures.reserve( collection->partCount() );
2853  for ( int i = 0; i < collection->partCount(); ++i )
2854  {
2855  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2856  partFeatures << f;
2857  }
2858 
2859  sorter.sortFeatures( partFeatures, unconstedContext );
2860 
2861  QgsGeometryCollection* orderedGeom = dynamic_cast<QgsGeometryCollection*>( fGeom.geometry()->clone() );
2862 
2863  Q_ASSERT( orderedGeom );
2864 
2865  while ( orderedGeom->partCount() )
2866  orderedGeom->removeGeometry( 0 );
2867 
2868  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2869  {
2870  orderedGeom->addGeometry( feature.geometry().geometry()->clone() );
2871  }
2872 
2873  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2874 
2875  if ( !ctx )
2876  delete unconstedContext;
2877 
2878  return result;
2879 }
2880 
2881 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2882 {
2883  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2884  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2885 
2886  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2887 
2888  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2889  return result;
2890 }
2891 
2892 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2893 {
2894  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2895  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2896 
2897  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2898 
2899  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2900  return result;
2901 }
2902 
2903 static QVariant fcnLineInterpolatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2904 {
2905  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2906  double distance = getDoubleValue( values.at( 1 ), parent );
2907 
2908  QgsGeometry geom = lineGeom.interpolate( distance );
2909 
2910  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
2911  return result;
2912 }
2913 
2914 static QVariant fcnLineInterpolateAngle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2915 {
2916  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2917  double distance = getDoubleValue( values.at( 1 ), parent );
2918 
2919  return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
2920 }
2921 
2922 static QVariant fcnAngleAtVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2923 {
2924  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2925  qlonglong vertex = getIntValue( values.at( 1 ), parent );
2926 
2927  return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
2928 }
2929 
2930 static QVariant fcnDistanceToVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2931 {
2932  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2933  qlonglong vertex = getIntValue( values.at( 1 ), parent );
2934 
2935  return geom.distanceToVertex( vertex );
2936 }
2937 
2938 static QVariant fcnLineLocatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2939 {
2940  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2941  QgsGeometry pointGeom = getGeometry( values.at( 1 ), parent );
2942 
2943  double distance = lineGeom.lineLocatePoint( pointGeom );
2944 
2945  return distance >= 0 ? distance : QVariant();
2946 }
2947 
2948 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2949 {
2950  if ( values.length() == 2 && values.at( 1 ).toInt() != 0 )
2951  {
2952  double number = getDoubleValue( values.at( 0 ), parent );
2953  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2954  return QVariant( qRound( number * scaler ) / scaler );
2955  }
2956 
2957  if ( values.length() >= 1 )
2958  {
2959  double number = getIntValue( values.at( 0 ), parent );
2960  return QVariant( qRound( number ) );
2961  }
2962 
2963  return QVariant();
2964 }
2965 
2966 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2967 {
2968  Q_UNUSED( values );
2969  Q_UNUSED( parent );
2970  return M_PI;
2971 }
2972 
2973 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2974 {
2975  double value = getDoubleValue( values.at( 0 ), parent );
2976  int places = getIntValue( values.at( 1 ), parent );
2977  if ( places < 0 )
2978  {
2979  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2980  return QVariant();
2981  }
2982  return QStringLiteral( "%L1" ).arg( value, 0, 'f', places );
2983 }
2984 
2985 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2986 {
2987  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2988  QString format = getStringValue( values.at( 1 ), parent );
2989  return dt.toString( format );
2990 }
2991 
2992 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2993 {
2994  int red = getIntValue( values.at( 0 ), parent );
2995  int green = getIntValue( values.at( 1 ), parent );
2996  int blue = getIntValue( values.at( 2 ), parent );
2997  QColor color = QColor( red, green, blue );
2998  if ( ! color.isValid() )
2999  {
3000  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
3001  color = QColor( 0, 0, 0 );
3002  }
3003 
3004  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3005 }
3006 
3007 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
3008 {
3009  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
3011  QVariant value = node->eval( parent, context );
3013  if ( value.toBool() )
3014  {
3015  node = getNode( values.at( 1 ), parent );
3017  value = node->eval( parent, context );
3019  }
3020  else
3021  {
3022  node = getNode( values.at( 2 ), parent );
3024  value = node->eval( parent, context );
3026  }
3027  return value;
3028 }
3029 
3030 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3031 {
3032  int red = getIntValue( values.at( 0 ), parent );
3033  int green = getIntValue( values.at( 1 ), parent );
3034  int blue = getIntValue( values.at( 2 ), parent );
3035  int alpha = getIntValue( values.at( 3 ), parent );
3036  QColor color = QColor( red, green, blue, alpha );
3037  if ( ! color.isValid() )
3038  {
3039  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
3040  color = QColor( 0, 0, 0 );
3041  }
3042  return QgsSymbolLayerUtils::encodeColor( color );
3043 }
3044 
3045 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3046 {
3047  QString rampName = getStringValue( values.at( 0 ), parent );
3048  const QgsColorRamp *mRamp = QgsStyle::defaultStyle()->colorRampRef( rampName );
3049  if ( ! mRamp )
3050  {
3051  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
3052  return QColor( 0, 0, 0 ).name();
3053  }
3054  double value = getDoubleValue( values.at( 1 ), parent );
3055  QColor color = mRamp->color( value );
3056  return QgsSymbolLayerUtils::encodeColor( color );
3057 }
3058 
3059 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3060 {
3061  // Hue ranges from 0 - 360
3062  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3063  // Saturation ranges from 0 - 100
3064  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3065  // Lightness ranges from 0 - 100
3066  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
3067 
3068  QColor color = QColor::fromHslF( hue, saturation, lightness );
3069 
3070  if ( ! color.isValid() )
3071  {
3072  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
3073  color = QColor( 0, 0, 0 );
3074  }
3075 
3076  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3077 }
3078 
3079 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3080 {
3081  // Hue ranges from 0 - 360
3082  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3083  // Saturation ranges from 0 - 100
3084  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3085  // Lightness ranges from 0 - 100
3086  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
3087  // Alpha ranges from 0 - 255
3088  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
3089 
3090  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
3091  if ( ! color.isValid() )
3092  {
3093  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
3094  color = QColor( 0, 0, 0 );
3095  }
3096  return QgsSymbolLayerUtils::encodeColor( color );
3097 }
3098 
3099 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3100 {
3101  // Hue ranges from 0 - 360
3102  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3103  // Saturation ranges from 0 - 100
3104  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3105  // Value ranges from 0 - 100
3106  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
3107 
3108  QColor color = QColor::fromHsvF( hue, saturation, value );
3109 
3110  if ( ! color.isValid() )
3111  {
3112  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
3113  color = QColor( 0, 0, 0 );
3114  }
3115 
3116  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3117 }
3118 
3119 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3120 {
3121  // Hue ranges from 0 - 360
3122  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3123  // Saturation ranges from 0 - 100
3124  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3125  // Value ranges from 0 - 100
3126  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
3127  // Alpha ranges from 0 - 255
3128  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
3129 
3130  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
3131  if ( ! color.isValid() )
3132  {
3133  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
3134  color = QColor( 0, 0, 0 );
3135  }
3136  return QgsSymbolLayerUtils::encodeColor( color );
3137 }
3138 
3139 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3140 {
3141  // Cyan ranges from 0 - 100
3142  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
3143  // Magenta ranges from 0 - 100
3144  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
3145  // Yellow ranges from 0 - 100
3146  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
3147  // Black ranges from 0 - 100
3148  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
3149 
3150  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
3151 
3152  if ( ! color.isValid() )
3153  {
3154  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
3155  color = QColor( 0, 0, 0 );
3156  }
3157 
3158  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3159 }
3160 
3161 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3162 {
3163  // Cyan ranges from 0 - 100
3164  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
3165  // Magenta ranges from 0 - 100
3166  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
3167  // Yellow ranges from 0 - 100
3168  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
3169  // Black ranges from 0 - 100
3170  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
3171  // Alpha ranges from 0 - 255
3172  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
3173 
3174  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
3175  if ( ! color.isValid() )
3176  {
3177  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
3178  color = QColor( 0, 0, 0 );
3179  }
3180  return QgsSymbolLayerUtils::encodeColor( color );
3181 }
3182 
3183 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3184 {
3185  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3186  if ( ! color.isValid() )
3187  {
3188  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3189  return QVariant();
3190  }
3191 
3192  QString part = getStringValue( values.at( 1 ), parent );
3193  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
3194  return color.red();
3195  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
3196  return color.green();
3197  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
3198  return color.blue();
3199  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
3200  return color.alpha();
3201  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
3202  return color.hsvHueF() * 360;
3203  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
3204  return color.hsvSaturationF() * 100;
3205  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
3206  return color.valueF() * 100;
3207  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
3208  return color.hslHueF() * 360;
3209  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
3210  return color.hslSaturationF() * 100;
3211  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
3212  return color.lightnessF() * 100;
3213  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
3214  return color.cyanF() * 100;
3215  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
3216  return color.magentaF() * 100;
3217  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
3218  return color.yellowF() * 100;
3219  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
3220  return color.blackF() * 100;
3221 
3222  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
3223  return QVariant();
3224 }
3225 
3226 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3227 {
3228  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3229  if ( ! color.isValid() )
3230  {
3231  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3232  return QVariant();
3233  }
3234 
3235  QString part = getStringValue( values.at( 1 ), parent );
3236  int value = getIntValue( values.at( 2 ), parent );
3237  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
3238  color.setRed( value );
3239  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
3240  color.setGreen( value );
3241  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
3242  color.setBlue( value );
3243  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
3244  color.setAlpha( value );
3245  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
3246  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
3247  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
3248  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
3249  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
3250  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
3251  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
3252  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
3253  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
3254  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
3255  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
3256  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
3257  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
3258  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
3259  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
3260  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
3261  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
3262  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
3263  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
3264  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
3265  else
3266  {
3267  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
3268  return QVariant();
3269  }
3270  return QgsSymbolLayerUtils::encodeColor( color );
3271 }
3272 
3273 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3274 {
3275  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3276  if ( ! color.isValid() )
3277  {
3278  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3279  return QVariant();
3280  }
3281 
3282  color = color.darker( getIntValue( values.at( 1 ), parent ) );
3283 
3284  return QgsSymbolLayerUtils::encodeColor( color );
3285 }
3286 
3287 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3288 {
3289  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3290  if ( ! color.isValid() )
3291  {
3292  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3293  return QVariant();
3294  }
3295 
3296  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
3297 
3298  return QgsSymbolLayerUtils::encodeColor( color );
3299 }
3300 
3301 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3302 {
3303  QgsFeature feat = getFeature( values.at( 0 ), parent );
3304  QgsGeometry geom = feat.geometry();
3305  if ( !geom.isNull() )
3306  return QVariant::fromValue( geom );
3307  return QVariant();
3308 }
3309 
3310 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3311 {
3312  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
3313  QString sAuthId = getStringValue( values.at( 1 ), parent );
3314  QString dAuthId = getStringValue( values.at( 2 ), parent );
3315 
3317  if ( ! s.isValid() )
3318  return QVariant::fromValue( fGeom );
3320  if ( ! d.isValid() )
3321  return QVariant::fromValue( fGeom );
3322 
3323  QgsCoordinateTransform t( s, d );
3324  try
3325  {
3326  if ( fGeom.transform( t ) == 0 )
3327  return QVariant::fromValue( fGeom );
3328  }
3329  catch ( QgsCsException &cse )
3330  {
3331  QgsMessageLog::logMessage( QStringLiteral( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
3332  return QVariant();
3333  }
3334  return QVariant();
3335 }
3336 
3337 
3338 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3339 {
3340  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
3341  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
3342 
3343  //no layer found
3344  if ( !vl )
3345  {
3346  return QVariant();
3347  }
3348 
3349  QString attribute = getStringValue( values.at( 1 ), parent );
3350  int attributeId = vl->fields().lookupField( attribute );
3351  if ( attributeId == -1 )
3352  {
3353  return QVariant();
3354  }
3355 
3356  const QVariant& attVal = values.at( 2 );
3357  QgsFeatureRequest req;
3358  req.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
3359  QgsExpression::quotedString( attVal.toString() ) ) );
3360  req.setLimit( 1 );
3361  if ( !parent->needsGeometry() )
3362  {
3364  }
3365  QgsFeatureIterator fIt = vl->getFeatures( req );
3366 
3367  QgsFeature fet;
3368  if ( fIt.nextFeature( fet ) )
3369  return QVariant::fromValue( fet );
3370 
3371  return QVariant();
3372 }
3373 
3374 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3375 {
3376  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3377 
3378  //try to find a matching layer by name
3379  QgsMapLayer* layer = QgsProject::instance()->mapLayer( layerIdOrName ); //search by id first
3380  if ( !layer )
3381  {
3382  QList<QgsMapLayer *> layersByName = QgsProject::instance()->mapLayersByName( layerIdOrName );
3383  if ( !layersByName.isEmpty() )
3384  {
3385  layer = layersByName.at( 0 );
3386  }
3387  }
3388 
3389  if ( !layer )
3390  return QVariant();
3391 
3392  QString layerProperty = getStringValue( values.at( 1 ), parent );
3393  if ( QString::compare( layerProperty, QStringLiteral( "name" ), Qt::CaseInsensitive ) == 0 )
3394  return layer->name();
3395  else if ( QString::compare( layerProperty, QStringLiteral( "id" ), Qt::CaseInsensitive ) == 0 )
3396  return layer->id();
3397  else if ( QString::compare( layerProperty, QStringLiteral( "title" ), Qt::CaseInsensitive ) == 0 )
3398  return layer->title();
3399  else if ( QString::compare( layerProperty, QStringLiteral( "abstract" ), Qt::CaseInsensitive ) == 0 )
3400  return layer->abstract();
3401  else if ( QString::compare( layerProperty, QStringLiteral( "keywords" ), Qt::CaseInsensitive ) == 0 )
3402  return layer->keywordList();
3403  else if ( QString::compare( layerProperty, QStringLiteral( "data_url" ), Qt::CaseInsensitive ) == 0 )
3404  return layer->dataUrl();
3405  else if ( QString::compare( layerProperty, QStringLiteral( "attribution" ), Qt::CaseInsensitive ) == 0 )
3406  return layer->attribution();
3407  else if ( QString::compare( layerProperty, QStringLiteral( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3408  return layer->attributionUrl();
3409  else if ( QString::compare( layerProperty, QStringLiteral( "source" ), Qt::CaseInsensitive ) == 0 )
3410  return layer->publicSource();
3411  else if ( QString::compare( layerProperty, QStringLiteral( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3412  return layer->minimumScale();
3413  else if ( QString::compare( layerProperty, QStringLiteral( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3414  return layer->maximumScale();
3415  else if ( QString::compare( layerProperty, QStringLiteral( "crs" ), Qt::CaseInsensitive ) == 0 )
3416  return layer->crs().authid();
3417  else if ( QString::compare( layerProperty, QStringLiteral( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3418  return layer->crs().toProj4();
3419  else if ( QString::compare( layerProperty, QStringLiteral( "extent" ), Qt::CaseInsensitive ) == 0 )
3420  {
3421  QgsGeometry extentGeom = QgsGeometry::fromRect( layer->extent() );
3422  QVariant result = QVariant::fromValue( extentGeom );
3423  return result;
3424  }
3425  else if ( QString::compare( layerProperty, QStringLiteral( "type" ), Qt::CaseInsensitive ) == 0 )
3426  {
3427  switch ( layer->type() )
3428  {
3430  return QCoreApplication::translate( "expressions", "Vector" );
3432  return QCoreApplication::translate( "expressions", "Raster" );
3434  return QCoreApplication::translate( "expressions", "Plugin" );
3435  }
3436  }
3437  else
3438  {
3439  //vector layer methods
3440  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3441  if ( vLayer )
3442  {
3443  if ( QString::compare( layerProperty, QStringLiteral( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3444  return vLayer->storageType();
3445  else if ( QString::compare( layerProperty, QStringLiteral( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3447  else if ( QString::compare( layerProperty, QStringLiteral( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3448  return QVariant::fromValue( vLayer->featureCount() );
3449  }
3450  }
3451 
3452  return QVariant();
3453 }
3454 
3455 static QVariant fcnGetRasterBandStat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3456 {
3457  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3458 
3459  //try to find a matching layer by name
3460  QgsMapLayer* layer = QgsProject::instance()->mapLayer( layerIdOrName ); //search by id first
3461  if ( !layer )
3462  {
3463  QList<QgsMapLayer *> layersByName = QgsProject::instance()->mapLayersByName( layerIdOrName );
3464  if ( !layersByName.isEmpty() )
3465  {
3466  layer = layersByName.at( 0 );
3467  }
3468  }
3469 
3470  if ( !layer )
3471  return QVariant();
3472 
3473  QgsRasterLayer* rl = qobject_cast< QgsRasterLayer* >( layer );
3474  if ( !rl )
3475  return QVariant();
3476 
3477  int band = getIntValue( values.at( 1 ), parent );
3478  if ( band < 1 || band > rl->bandCount() )
3479  {
3480  parent->setEvalErrorString( QObject::tr( "Invalid band number %1 for layer %2" ).arg( band ).arg( layerIdOrName ) );
3481  return QVariant();
3482  }
3483 
3484  QString layerProperty = getStringValue( values.at( 2 ), parent );
3485  int stat = 0;
3486 
3487  if ( QString::compare( layerProperty, QStringLiteral( "avg" ), Qt::CaseInsensitive ) == 0 )
3488  stat = QgsRasterBandStats::Mean;
3489  else if ( QString::compare( layerProperty, QStringLiteral( "stdev" ), Qt::CaseInsensitive ) == 0 )
3491  else if ( QString::compare( layerProperty, QStringLiteral( "min" ), Qt::CaseInsensitive ) == 0 )
3492  stat = QgsRasterBandStats::Min;
3493  else if ( QString::compare( layerProperty, QStringLiteral( "max" ), Qt::CaseInsensitive ) == 0 )
3494  stat = QgsRasterBandStats::Max;
3495  else if ( QString::compare( layerProperty, QStringLiteral( "range" ), Qt::CaseInsensitive ) == 0 )
3497  else if ( QString::compare( layerProperty, QStringLiteral( "sum" ), Qt::CaseInsensitive ) == 0 )
3498  stat = QgsRasterBandStats::Sum;
3499  else
3500  {
3501  parent->setEvalErrorString( QObject::tr( "Invalid raster statistic: '%1'" ).arg( layerProperty ) );
3502  return QVariant();
3503  }
3504 
3505  QgsRasterBandStats stats = rl->dataProvider()->bandStatistics( band, stat );
3506  switch ( stat )
3507  {
3509  return stats.mean;
3511  return stats.stdDev;
3513  return stats.minimumValue;
3515  return stats.maximumValue;
3517  return stats.range;
3519  return stats.sum;
3520  }
3521  return QVariant();
3522 }
3523 
3524 static QVariant fcnArray( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
3525 {
3526  return values;
3527 }
3528 
3529 static QVariant fcnArrayLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3530 {
3531  return getListValue( values.at( 0 ), parent ).length();
3532 }
3533 
3534 static QVariant fcnArrayContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3535 {
3536  return QVariant( getListValue( values.at( 0 ), parent ).contains( values.at( 1 ) ) );
3537 }
3538 
3539 static QVariant fcnArrayFind( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3540 {
3541  return getListValue( values.at( 0 ), parent ).indexOf( values.at( 1 ) );
3542 }
3543 
3544 static QVariant fcnArrayGet( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3545 {
3546  const QVariantList list = getListValue( values.at( 0 ), parent );
3547  const qlonglong pos = getIntValue( values.at( 1 ), parent );
3548  if ( pos < 0 || pos >= list.length() ) return QVariant();
3549  return list.at( pos );
3550 }
3551 
3552 static QVariant convertToSameType( const QVariant& value, QVariant::Type type )
3553 {
3554  QVariant result = value;
3555  result.convert( type );
3556  return result;
3557 }
3558 
3559 static QVariant fcnArrayAppend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3560 {
3561  QVariantList list = getListValue( values.at( 0 ), parent );
3562  list.append( values.at( 1 ) );
3563  return convertToSameType( list , values.at( 0 ).type() );
3564 }
3565 
3566 static QVariant fcnArrayPrepend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3567 {
3568  QVariantList list = getListValue( values.at( 0 ), parent );
3569  list.prepend( values.at( 1 ) );
3570  return convertToSameType( list , values.at( 0 ).type() );
3571 }
3572 
3573 static QVariant fcnArrayInsert( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3574 {
3575  QVariantList list = getListValue( values.at( 0 ), parent );
3576  list.insert( getIntValue( values.at( 1 ), parent ), values.at( 2 ) );
3577  return convertToSameType( list , values.at( 0 ).type() );
3578 }
3579 
3580 static QVariant fcnArrayRemoveAt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3581 {
3582  QVariantList list = getListValue( values.at( 0 ), parent );
3583  list.removeAt( getIntValue( values.at( 1 ), parent ) );
3584  return convertToSameType( list , values.at( 0 ).type() );
3585 }
3586 
3587 static QVariant fcnArrayRemoveAll( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3588 {
3589  QVariantList list = getListValue( values.at( 0 ), parent );
3590  list.removeAll( values.at( 1 ) );
3591  return convertToSameType( list , values.at( 0 ).type() );
3592 }
3593 
3594 static QVariant fcnArrayCat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3595 {
3596  QVariantList list;
3597  Q_FOREACH ( const QVariant& cur, values )
3598  {
3599  list += getListValue( cur, parent );
3600  }
3601  return convertToSameType( list , values.at( 0 ).type() );
3602 }
3603 
3604 static QVariant fcnArrayIntersect( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3605 {
3606  const QVariantList array1 = getListValue( values.at( 0 ), parent );
3607  Q_FOREACH ( const QVariant& cur, getListValue( values.at( 1 ), parent ) )
3608  {
3609  if ( array1.contains( cur ) )
3610  return QVariant( true );
3611  }
3612  return QVariant( false );
3613 }
3614 
3615 
3616 static QVariant fcnArrayDistinct( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3617 {
3618  QVariantList array = getListValue( values.at( 0 ), parent );
3619 
3620  QVariantList distinct;
3621 
3622  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
3623  {
3624  if ( !distinct.contains( *it ) )
3625  {
3626  distinct += ( *it );
3627  }
3628  }
3629 
3630  return distinct;
3631 }
3632 
3633 static QVariant fcnArrayToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3634 {
3635  QVariantList array = getListValue( values.at( 0 ), parent );
3636  QString delimiter = getStringValue( values.at( 1 ), parent );
3637  QString empty = getStringValue( values.at( 2 ), parent );
3638 
3639  QString str;
3640 
3641  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
3642  {
3643  str += ( !( *it ).toString().isEmpty() ) ? ( *it ).toString() : empty;
3644  if ( it != ( array.constEnd() - 1 ) )
3645  {
3646  str += delimiter;
3647  }
3648  }
3649 
3650  return QVariant( str );
3651 }
3652 
3653 static QVariant fcnStringToArray( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3654 {
3655  QString str = getStringValue( values.at( 0 ), parent );
3656  QString delimiter = getStringValue( values.at( 1 ), parent );
3657  QString empty = getStringValue( values.at( 2 ), parent );
3658 
3659  QStringList list = str.split( delimiter );
3660  QVariantList array;
3661 
3662  for ( QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
3663  {
3664  array += ( !( *it ).isEmpty() ) ? *it : empty;
3665  }
3666 
3667  return array;
3668 }
3669 
3670 static QVariant fcnMap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3671 {
3672  QVariantMap result;
3673  for ( int i = 0; i + 1 < values.length(); i += 2 )
3674  {
3675  result.insert( getStringValue( values.at( i ), parent ), values.at( i + 1 ) );
3676  }
3677  return result;
3678 }
3679 
3680 static QVariant fcnMapGet( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3681 {
3682  return getMapValue( values.at( 0 ), parent ).value( values.at( 1 ).toString() );
3683 }
3684 
3685 static QVariant fcnMapExist( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3686 {
3687  return getMapValue( values.at( 0 ), parent ).contains( values.at( 1 ).toString() );
3688 }
3689 
3690 static QVariant fcnMapDelete( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3691 {
3692  QVariantMap map = getMapValue( values.at( 0 ), parent );
3693  map.remove( values.at( 1 ).toString() );
3694  return map;
3695 }
3696 
3697 static QVariant fcnMapInsert( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3698 {
3699  QVariantMap map = getMapValue( values.at( 0 ), parent );
3700  map.insert( values.at( 1 ).toString(), values.at( 2 ) );
3701  return map;
3702 }
3703 
3704 static QVariant fcnMapConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3705 {
3706  QVariantMap result;
3707  Q_FOREACH ( const QVariant& cur, values )
3708  {
3709  const QVariantMap curMap = getMapValue( cur, parent );
3710  for ( QVariantMap::const_iterator it = curMap.constBegin(); it != curMap.constEnd(); ++it )
3711  result.insert( it.key(), it.value() );
3712  }
3713  return result;
3714 }
3715 
3716 static QVariant fcnMapAKeys( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3717 {
3718  return QStringList( getMapValue( values.at( 0 ), parent ).keys() );
3719 }
3720 
3721 static QVariant fcnMapAVals( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3722 {
3723  return getMapValue( values.at( 0 ), parent ).values();
3724 }
3725 
3726 
3727 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3728 {
3729  int fnIdx = functionIndex( function->name() );
3730  if ( fnIdx != -1 )
3731  {
3732  return false;
3733  }
3734  QgsExpression::sFunctions.append( function );
3735  if ( transferOwnership )
3736  QgsExpression::sOwnedFunctions.append( function );
3737  return true;
3738 }
3739 
3740 bool QgsExpression::unregisterFunction( const QString& name )
3741 {
3742  // You can never override the built in functions.
3743  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3744  {
3745  return false;
3746  }
3747  int fnIdx = functionIndex( name );
3748  if ( fnIdx != -1 )
3749  {
3750  QgsExpression::sFunctions.removeAt( fnIdx );
3751  return true;
3752  }
3753  return false;
3754 }
3755 
3757 {
3758  qDeleteAll( QgsExpression::sOwnedFunctions );
3760 }
3761 
3763 
3765 {
3766  if ( sBuiltinFunctions.isEmpty() )
3767  {
3768  Functions(); // this method builds the gmBuiltinFunctions as well
3769  }
3770  return sBuiltinFunctions;
3771 }
3772 
3773 QList<QgsExpression::Function*> QgsExpression::sFunctions;
3774 QList<QgsExpression::Function*> QgsExpression::sOwnedFunctions;
3775 
3776 const QList<QgsExpression::Function*>& QgsExpression::Functions()
3777 {
3778  // The construction of the list isn't thread-safe, and without the mutex,
3779  // crashes in the WFS provider may occur, since it can parse expressions
3780  // in parallel.
3781  // The mutex needs to be recursive.
3782  static QMutex sFunctionsMutex( QMutex::Recursive );
3783  QMutexLocker locker( &sFunctionsMutex );
3784 
3785  if ( sFunctions.isEmpty() )
3786  {
3787  ParameterList aggParams = ParameterList() << Parameter( QStringLiteral( "expression" ) )
3788  << Parameter( QStringLiteral( "group_by" ), true )
3789  << Parameter( QStringLiteral( "filter" ), true );
3790 
3791  sFunctions
3792  << new StaticFunction( QStringLiteral( "sqrt" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnSqrt, QStringLiteral( "Math" ) )
3793  << new StaticFunction( QStringLiteral( "radians" ), ParameterList() << Parameter( QStringLiteral( "degrees" ) ), fcnRadians, QStringLiteral( "Math" ) )
3794  << new StaticFunction( QStringLiteral( "degrees" ), ParameterList() << Parameter( QStringLiteral( "radians" ) ), fcnDegrees, QStringLiteral( "Math" ) )
3795  << new StaticFunction( QStringLiteral( "azimuth" ), ParameterList() << Parameter( QStringLiteral( "point_a" ) ) << Parameter( QStringLiteral( "point_b" ) ), fcnAzimuth, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
3796  << new StaticFunction( QStringLiteral( "project" ), ParameterList() << Parameter( QStringLiteral( "point" ) ) << Parameter( QStringLiteral( "distance" ) ) << Parameter( QStringLiteral( "azimuth" ) ) << Parameter( QStringLiteral( "elevation" ), true, M_PI / 2 ), fcnProject, QStringLiteral( "GeometryGroup" ) )
3797  << new StaticFunction( QStringLiteral( "abs" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAbs, QStringLiteral( "Math" ) )
3798  << new StaticFunction( QStringLiteral( "cos" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnCos, QStringLiteral( "Math" ) )
3799  << new StaticFunction( QStringLiteral( "sin" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnSin, QStringLiteral( "Math" ) )
3800  << new StaticFunction( QStringLiteral( "tan" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnTan, QStringLiteral( "Math" ) )
3801  << new StaticFunction( QStringLiteral( "asin" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAsin, QStringLiteral( "Math" ) )
3802  << new StaticFunction( QStringLiteral( "acos" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAcos, QStringLiteral( "Math" ) )
3803  << new StaticFunction( QStringLiteral( "atan" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAtan, QStringLiteral( "Math" ) )
3804  << new StaticFunction( QStringLiteral( "atan2" ), ParameterList() << Parameter( QStringLiteral( "dx" ) ) << Parameter( QStringLiteral( "dy" ) ), fcnAtan2, QStringLiteral( "Math" ) )
3805  << new StaticFunction( QStringLiteral( "exp" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnExp, QStringLiteral( "Math" ) )
3806  << new StaticFunction( QStringLiteral( "ln" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnLn, QStringLiteral( "Math" ) )
3807  << new StaticFunction( QStringLiteral( "log10" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnLog10, QStringLiteral( "Math" ) )
3808  << new StaticFunction( QStringLiteral( "log" ), ParameterList() << Parameter( QStringLiteral( "base" ) ) << Parameter( QStringLiteral( "value" ) ), fcnLog, QStringLiteral( "Math" ) )
3809  << new StaticFunction( QStringLiteral( "round" ), ParameterList() << Parameter( QStringLiteral( "value" ) ) << Parameter( QStringLiteral( "places" ), true, 0 ), fcnRound, QStringLiteral( "Math" ) )
3810  << new StaticFunction( QStringLiteral( "rand" ), ParameterList() << Parameter( QStringLiteral( "min" ) ) << Parameter( QStringLiteral( "max" ) ), fcnRnd, QStringLiteral( "Math" ) )
3811  << new StaticFunction( QStringLiteral( "randf" ), ParameterList() << Parameter( QStringLiteral( "min" ), true, 0.0 ) << Parameter( QStringLiteral( "max" ), true, 1.0 ), fcnRndF, QStringLiteral( "Math" ) )
3812  << new StaticFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ) )
3813  << new StaticFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ) )
3814  << new StaticFunction( QStringLiteral( "clamp" ), ParameterList() << Parameter( QStringLiteral( "min" ) ) << Parameter( QStringLiteral( "value" ) ) << Parameter( QStringLiteral( "max" ) ), fcnClamp, QStringLiteral( "Math" ) )
3815  << new StaticFunction( QStringLiteral( "scale_linear" ), 5, fcnLinearScale, QStringLiteral( "Math" ) )
3816  << new StaticFunction( QStringLiteral( "scale_exp" ), 6, fcnExpScale, QStringLiteral( "Math" ) )
3817  << new StaticFunction( QStringLiteral( "floor" ), 1, fcnFloor, QStringLiteral( "Math" ) )
3818  << new StaticFunction( QStringLiteral( "ceil" ), 1, fcnCeil, QStringLiteral( "Math" ) )
3819  << new StaticFunction( QStringLiteral( "pi" ), 0, fcnPi, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$pi" ) )
3820  << new StaticFunction( QStringLiteral( "to_int" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToInt, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toint" ) )
3821  << new StaticFunction( QStringLiteral( "to_real" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToReal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toreal" ) )
3822  << new StaticFunction( QStringLiteral( "to_string" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToString, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tostring" ) )
3823  << new StaticFunction( QStringLiteral( "to_datetime" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToDateTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todatetime" ) )
3824  << new StaticFunction( QStringLiteral( "to_date" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToDate, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todate" ) )
3825  << new StaticFunction( QStringLiteral( "to_time" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "totime" ) )
3826  << new StaticFunction( QStringLiteral( "to_interval" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToInterval, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tointerval" ) )
3827  << new StaticFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
3828  << new StaticFunction( QStringLiteral( "if" ), 3, fcnIf, QStringLiteral( "Conditionals" ), QString(), False, QSet<QString>(), true )
3829 
3830  << new StaticFunction( QStringLiteral( "aggregate" ),
3831  ParameterList()
3832  << Parameter( QStringLiteral( "layer" ) )
3833  << Parameter( QStringLiteral( "aggregate" ) )
3834  << Parameter( QStringLiteral( "expression" ) )
3835  << Parameter( QStringLiteral( "filter" ), true )
3836  << Parameter( QStringLiteral( "concatenator" ), true ),
3837  fcnAggregate,
3838  QStringLiteral( "Aggregates" ),
3839  QString(),
3840  []( const QgsExpression::NodeFunction* node )
3841  {
3842  // usesGeometry callback: return true if @parent variable is referenced
3843 
3844  if ( !node )
3845  return true;
3846 
3847  if ( !node->args() )
3848  return false;
3849 
3850  QSet<QString> referencedVars;
3851  if ( node->args()->count() > 2 )
3852  {
3853  QgsExpression::Node* subExpressionNode = node->args()->at( 2 );
3854  referencedVars = subExpressionNode->referencedVariables();
3855  }
3856 
3857  if ( node->args()->count() > 3 )
3858  {
3859  QgsExpression::Node* filterNode = node->args()->at( 3 );
3860  referencedVars.unite( filterNode->referencedVariables() );
3861  }
3862  return referencedVars.contains( "parent" ) || referencedVars.contains( QString() );
3863  },
3864  []( const QgsExpression::NodeFunction* node )
3865  {
3866  // referencedColumns callback: return AllAttributes if @parent variable is referenced
3867 
3868  if ( !node )
3869  return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
3870 
3871  if ( !node->args() )
3872  return QSet<QString>();
3873 
3874  QSet<QString> referencedCols;
3875  QSet<QString> referencedVars;
3876 
3877  if ( node->args()->count() > 2 )
3878  {
3879  QgsExpression::Node* subExpressionNode = node->args()->at( 2 );
3880  referencedVars = subExpressionNode->referencedVariables();
3881  referencedCols = subExpressionNode->referencedColumns();
3882  }
3883  if ( node->args()->count() > 3 )
3884  {
3885  QgsExpression::Node* filterNode = node->args()->at( 3 );
3886  referencedVars = filterNode->referencedVariables();
3887  referencedCols.unite( filterNode->referencedColumns() );
3888  }
3889 
3890  if ( referencedVars.contains( "parent" ) || referencedVars.contains( QString() ) )
3891  return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
3892  else
3893  return referencedCols;
3894  },
3895  true
3896  )
3897 
3898  << new StaticFunction( QStringLiteral( "relation_aggregate" ), ParameterList() << Parameter( QStringLiteral( "relation" ) ) << Parameter( QStringLiteral( "aggregate" ) ) << Parameter( QStringLiteral( "expression" ) ) << Parameter( QStringLiteral( "concatenator" ), true ),
3899  fcnAggregateRelation, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true )
3900 
3901  << new StaticFunction( QStringLiteral( "count" ), aggParams, fcnAggregateCount, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3902  << new StaticFunction( QStringLiteral( "count_distinct" ), aggParams, fcnAggregateCountDistinct, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3903  << new StaticFunction( QStringLiteral( "count_missing" ), aggParams, fcnAggregateCountMissing, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3904  << new StaticFunction( QStringLiteral( "minimum" ), aggParams, fcnAggregateMin, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3905  << new StaticFunction( QStringLiteral( "maximum" ), aggParams, fcnAggregateMax, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3906  << new StaticFunction( QStringLiteral( "sum" ), aggParams, fcnAggregateSum, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3907  << new StaticFunction( QStringLiteral( "mean" ), aggParams, fcnAggregateMean, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3908  << new StaticFunction( QStringLiteral( "median" ), aggParams, fcnAggregateMedian, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3909  << new StaticFunction( QStringLiteral( "stdev" ), aggParams, fcnAggregateStdev, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3910  << new StaticFunction( QStringLiteral( "range" ), aggParams, fcnAggregateRange, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3911  << new StaticFunction( QStringLiteral( "minority" ), aggParams, fcnAggregateMinority, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3912  << new StaticFunction( QStringLiteral( "majority" ), aggParams, fcnAggregateMajority, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3913  << new StaticFunction( QStringLiteral( "q1" ), aggParams, fcnAggregateQ1, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3914  << new StaticFunction( QStringLiteral( "q3" ), aggParams, fcnAggregateQ3, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3915  << new StaticFunction( QStringLiteral( "iqr" ), aggParams, fcnAggregateIQR, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3916  << new StaticFunction( QStringLiteral( "min_length" ), aggParams, fcnAggregateMinLength, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3917  << new StaticFunction( QStringLiteral( "max_length" ), aggParams, fcnAggregateMaxLength, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3918  << new StaticFunction( QStringLiteral( "collect" ), aggParams, fcnAggregateCollectGeometry, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3919  << new StaticFunction( QStringLiteral( "concatenate" ), aggParams << Parameter( QStringLiteral( "concatenator" ), true ), fcnAggregateStringConcat, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3920 
3921  << new StaticFunction( QStringLiteral( "regexp_match" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "regex" ) ), fcnRegexpMatch, QStringList() << QStringLiteral( "Conditionals" ) << QStringLiteral( "String" ) )
3922  << new StaticFunction( QStringLiteral( "regexp_matches" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "regex" ) ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnRegexpMatches, QStringLiteral( "Arrays" ) )
3923 
3924  << new StaticFunction( QStringLiteral( "now" ), 0, fcnNow, QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$now" ) )
3925  << new StaticFunction( QStringLiteral( "age" ), 2, fcnAge, QStringLiteral( "Date and Time" ) )
3926  << new StaticFunction( QStringLiteral( "year" ), 1, fcnYear, QStringLiteral( "Date and Time" ) )
3927  << new StaticFunction( QStringLiteral( "month" ), 1, fcnMonth, QStringLiteral( "Date and Time" ) )
3928  << new StaticFunction( QStringLiteral( "week" ), 1, fcnWeek, QStringLiteral( "Date and Time" ) )
3929  << new StaticFunction( QStringLiteral( "day" ), 1, fcnDay, QStringLiteral( "Date and Time" ) )
3930  << new StaticFunction( QStringLiteral( "hour" ), 1, fcnHour, QStringLiteral( "Date and Time" ) )
3931  << new StaticFunction( QStringLiteral( "minute" ), 1, fcnMinute, QStringLiteral( "Date and Time" ) )
3932  << new StaticFunction( QStringLiteral( "second" ), 1, fcnSeconds, QStringLiteral( "Date and Time" ) )
3933  << new StaticFunction( QStringLiteral( "epoch" ), ParameterList() << Parameter( QStringLiteral( "date" ) ), fcnEpoch, QStringLiteral( "Date and Time" ) )
3934  << new StaticFunction( QStringLiteral( "day_of_week" ), 1, fcnDayOfWeek, QStringLiteral( "Date and Time" ) )
3935  << new StaticFunction( QStringLiteral( "lower" ), 1, fcnLower, QStringLiteral( "String" ) )
3936  << new StaticFunction( QStringLiteral( "upper" ), 1, fcnUpper, QStringLiteral( "String" ) )
3937  << new StaticFunction( QStringLiteral( "title" ), 1, fcnTitle, QStringLiteral( "String" ) )
3938  << new StaticFunction( QStringLiteral( "trim" ), 1, fcnTrim, QStringLiteral( "String" ) )
3939  << new StaticFunction( QStringLiteral( "levenshtein" ), 2, fcnLevenshtein, QStringLiteral( "Fuzzy Matching" ) )
3940  << new StaticFunction( QStringLiteral( "longest_common_substring" ), 2, fcnLCS, QStringLiteral( "Fuzzy Matching" ) )
3941  << new StaticFunction( QStringLiteral( "hamming_distance" ), 2, fcnHamming, QStringLiteral( "Fuzzy Matching" ) )
3942  << new StaticFunction( QStringLiteral( "soundex" ), 1, fcnSoundex, QStringLiteral( "Fuzzy Matching" ) )
3943  << new StaticFunction( QStringLiteral( "char" ), 1, fcnChar, QStringLiteral( "String" ) )
3944  << new StaticFunction( QStringLiteral( "wordwrap" ), ParameterList() << Parameter( QStringLiteral( "text" ) ) << Parameter( QStringLiteral( "length" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
3945  << new StaticFunction( QStringLiteral( "length" ), ParameterList() << Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
3946  << new StaticFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
3947  << new StaticFunction( QStringLiteral( "regexp_replace" ), 3, fcnRegexpReplace, QStringLiteral( "String" ) )
3948  << new StaticFunction( QStringLiteral( "regexp_substr" ), 2, fcnRegexpSubstr, QStringLiteral( "String" ) )
3949  << new StaticFunction( QStringLiteral( "substr" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "start " ) ) << Parameter( QStringLiteral( "length" ), true ), fcnSubstr, QStringLiteral( "String" ), QString(),
3950  false, QSet< QString >(), false, QStringList(), true )
3951  << new StaticFunction( QStringLiteral( "concat" ), -1, fcnConcat, QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList(), true )
3952  << new StaticFunction( QStringLiteral( "strpos" ), 2, fcnStrpos, QStringLiteral( "String" ) )
3953  << new StaticFunction( QStringLiteral( "left" ), 2, fcnLeft, QStringLiteral( "String" ) )
3954  << new StaticFunction( QStringLiteral( "right" ), 2, fcnRight, QStringLiteral( "String" ) )
3955  << new StaticFunction( QStringLiteral( "rpad" ), 3, fcnRPad, QStringLiteral( "String" ) )
3956  << new StaticFunction( QStringLiteral( "lpad" ), 3, fcnLPad, QStringLiteral( "String" ) )
3957  << new StaticFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
3958  << new StaticFunction( QStringLiteral( "format_number" ), 2, fcnFormatNumber, QStringLiteral( "String" ) )
3959  << new StaticFunction( QStringLiteral( "format_date" ), ParameterList() << Parameter( QStringLiteral( "date" ) ) << Parameter( QStringLiteral( "format" ) ), fcnFormatDate, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "Date and Time" ) )
3960  << new StaticFunction( QStringLiteral( "color_rgb" ), 3, fcnColorRgb, QStringLiteral( "Color" ) )
3961  << new StaticFunction( QStringLiteral( "color_rgba" ), 4, fncColorRgba, QStringLiteral( "Color" ) )
3962  << new StaticFunction( QStringLiteral( "ramp_color" ), 2, fcnRampColor, QStringLiteral( "Color" ) )
3963  << new StaticFunction( QStringLiteral( "color_hsl" ), 3, fcnColorHsl, QStringLiteral( "Color" ) )
3964  << new StaticFunction( QStringLiteral( "color_hsla" ), 4, fncColorHsla, QStringLiteral( "Color" ) )
3965  << new StaticFunction( QStringLiteral( "color_hsv" ), 3, fcnColorHsv, QStringLiteral( "Color" ) )
3966  << new StaticFunction( QStringLiteral( "color_hsva" ), 4, fncColorHsva, QStringLiteral( "Color" ) )
3967  << new StaticFunction( QStringLiteral( "color_cmyk" ), 4, fcnColorCmyk, QStringLiteral( "Color" ) )
3968  << new StaticFunction( QStringLiteral( "color_cmyka" ), 5, fncColorCmyka, QStringLiteral( "Color" ) )
3969  << new StaticFunction( QStringLiteral( "color_part" ), 2, fncColorPart, QStringLiteral( "Color" ) )
3970  << new StaticFunction( QStringLiteral( "darker" ), 2, fncDarker, QStringLiteral( "Color" ) )
3971  << new StaticFunction( QStringLiteral( "lighter" ), 2, fncLighter, QStringLiteral( "Color" ) )
3972  << new StaticFunction( QStringLiteral( "set_color_part" ), 3, fncSetColorPart, QStringLiteral( "Color" ) )
3973  << new StaticFunction( QStringLiteral( "$geometry" ), 0, fcnGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
3974  << new StaticFunction( QStringLiteral( "$area" ), 0, fcnGeomArea, QStringLiteral( "GeometryGroup" ), QString(), true )
3975  << new StaticFunction( QStringLiteral( "area" ), 1, fcnArea, QStringLiteral( "GeometryGroup" ) )
3976  << new StaticFunction( QStringLiteral( "$length" ), 0, fcnGeomLength, QStringLiteral( "GeometryGroup" ), QString(), true )
3977  << new StaticFunction( QStringLiteral( "$perimeter" ), 0, fcnGeomPerimeter, QStringLiteral( "GeometryGroup" ), QString(), true )
3978  << new StaticFunction( QStringLiteral( "perimeter" ), 1, fcnPerimeter, QStringLiteral( "GeometryGroup" ) )
3979  << new StaticFunction( QStringLiteral( "$x" ), 0, fcnX, QStringLiteral( "GeometryGroup" ), QString(), true )
3980  << new StaticFunction( QStringLiteral( "$y" ), 0, fcnY, QStringLiteral( "GeometryGroup" ), QString(), true )
3981  << new StaticFunction( QStringLiteral( "x" ), 1, fcnGeomX, QStringLiteral( "GeometryGroup" ) )
3982  << new StaticFunction( QStringLiteral( "y" ), 1, fcnGeomY, QStringLiteral( "GeometryGroup" ) )
3983  << new StaticFunction( QStringLiteral( "z" ), 1, fcnGeomZ, QStringLiteral( "GeometryGroup" ) )
3984  << new StaticFunction( QStringLiteral( "m" ), 1, fcnGeomM, QStringLiteral( "GeometryGroup" ) )
3985  << new StaticFunction( QStringLiteral( "point_n" ), 2, fcnPointN, QStringLiteral( "GeometryGroup" ) )
3986  << new StaticFunction( QStringLiteral( "start_point" ), 1, fcnStartPoint, QStringLiteral( "GeometryGroup" ) )
3987  << new StaticFunction( QStringLiteral( "end_point" ), 1, fcnEndPoint, QStringLiteral( "GeometryGroup" ) )
3988  << new StaticFunction( QStringLiteral( "nodes_to_points" ), -1, fcnNodesToPoints, QStringLiteral( "GeometryGroup" ) )
3989  << new StaticFunction( QStringLiteral( "segments_to_lines" ), 1, fcnSegmentsToLines, QStringLiteral( "GeometryGroup" ) )
3990  << new StaticFunction( QStringLiteral( "make_point" ), -1, fcnMakePoint, QStringLiteral( "GeometryGroup" ) )
3991  << new StaticFunction( QStringLiteral( "make_point_m" ), 3, fcnMakePointM, QStringLiteral( "GeometryGroup" ) )
3992  << new StaticFunction( QStringLiteral( "make_line" ), -1, fcnMakeLine, QStringLiteral( "GeometryGroup" ) )
3993  << new StaticFunction( QStringLiteral( "make_polygon" ), -1, fcnMakePolygon, QStringLiteral( "GeometryGroup" ) )
3994  << new StaticFunction( QStringLiteral( "$x_at" ), 1, fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) )
3995  << new StaticFunction( QStringLiteral( "$y_at" ), 1, fcnYat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "yat" ) << QStringLiteral( "y_at" ) )
3996  << new StaticFunction( QStringLiteral( "x_min" ), 1, fcnXMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmin" ) )
3997  << new StaticFunction( QStringLiteral( "x_max" ), 1, fcnXMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmax" ) )
3998  << new StaticFunction( QStringLiteral( "y_min" ), 1, fcnYMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymin" ) )
3999  << new StaticFunction( QStringLiteral( "y_max" ), 1, fcnYMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymax" ) )
4000  << new StaticFunction( QStringLiteral( "geom_from_wkt" ), 1, fcnGeomFromWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromWKT" ) )
4001  << new StaticFunction( QStringLiteral( "geom_from_gml" ), 1, fcnGeomFromGML, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromGML" ) )
4002  << new StaticFunction( QStringLiteral( "relate" ), -1, fcnRelate, QStringLiteral( "GeometryGroup" ) )
4003  << new StaticFunction( QStringLiteral( "intersects_bbox" ), 2, fcnBbox, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "bbox" ) )
4004  << new StaticFunction( QStringLiteral( "disjoint" ), 2, fcnDisjoint, QStringLiteral( "GeometryGroup" ) )
4005  << new StaticFunction( QStringLiteral( "intersects" ), 2, fcnIntersects, QStringLiteral( "GeometryGroup" ) )
4006  << new StaticFunction( QStringLiteral( "touches" ), 2, fcnTouches, QStringLiteral( "GeometryGroup" ) )
4007  << new StaticFunction( QStringLiteral( "crosses" ), 2, fcnCrosses, QStringLiteral( "GeometryGroup" ) )
4008  << new StaticFunction( QStringLiteral( "contains" ), 2, fcnContains, QStringLiteral( "GeometryGroup" ) )
4009  << new StaticFunction( QStringLiteral( "overlaps" ), 2, fcnOverlaps, QStringLiteral( "GeometryGroup" ) )
4010  << new StaticFunction( QStringLiteral( "within" ), 2, fcnWithin, QStringLiteral( "GeometryGroup" ) )
4011  << new StaticFunction( QStringLiteral( "translate" ), 3, fcnTranslate, QStringLiteral( "GeometryGroup" ) )
4012  << new StaticFunction( QStringLiteral( "buffer" ), -1, fcnBuffer, QStringLiteral( "GeometryGroup" ) )
4013  << new StaticFunction( QStringLiteral( "offset_curve" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4014  << Parameter( QStringLiteral( "distance" ) )
4015  << Parameter( QStringLiteral( "segments" ), true, 8.0 )
4016  << Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
4017  << Parameter( QStringLiteral( "mitre_limit" ), true, 2.0 ),
4018  fcnOffsetCurve, QStringLiteral( "GeometryGroup" ) )
4019  << new StaticFunction( QStringLiteral( "single_sided_buffer" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4020  << Parameter( QStringLiteral( "distance" ) )
4021  << Parameter( QStringLiteral( "segments" ), true, 8.0 )
4022  << Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
4023  << Parameter( QStringLiteral( "mitre_limit" ), true, 2.0 ),
4024  fcnSingleSidedBuffer, QStringLiteral( "GeometryGroup" ) )
4025  << new StaticFunction( QStringLiteral( "extend" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4026  << Parameter( QStringLiteral( "start_distance" ) )
4027  << Parameter( QStringLiteral( "end_distance" ) ),
4028  fcnExtend, QStringLiteral( "GeometryGroup" ) )
4029  << new StaticFunction( QStringLiteral( "centroid" ), 1, fcnCentroid, QStringLiteral( "GeometryGroup" ) )
4030  << new StaticFunction( QStringLiteral( "point_on_surface" ), 1, fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
4031  << new StaticFunction( QStringLiteral( "pole_of_inaccessibility" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4032  << Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
4033  << new StaticFunction( QStringLiteral( "reverse" ), 1, fcnReverse, QStringLiteral( "GeometryGroup" ) )
4034  << new StaticFunction( QStringLiteral( "exterior_ring" ), 1, fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
4035  << new StaticFunction( QStringLiteral( "interior_ring_n" ), 2, fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
4036  << new StaticFunction( QStringLiteral( "geometry_n" ), 2, fcnGeometryN, QStringLiteral( "GeometryGroup" ) )
4037  << new StaticFunction( QStringLiteral( "boundary" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ), fcnBoundary, QStringLiteral( "GeometryGroup" ) )
4038  << new StaticFunction( QStringLiteral( "line_merge" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ), fcnLineMerge, QStringLiteral( "GeometryGroup" ) )
4039  << new StaticFunction( QStringLiteral( "bounds" ), 1, fcnBounds, QStringLiteral( "GeometryGroup" ) )
4040  << new StaticFunction( QStringLiteral( "simplify" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "tolerance" ) ), fcnSimplify, QStringLiteral( "GeometryGroup" ) )
4041  << new StaticFunction( QStringLiteral( "simplify_vw" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "tolerance" ) ), fcnSimplifyVW, QStringLiteral( "GeometryGroup" ) )
4042  << new StaticFunction( QStringLiteral( "smooth" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "iterations" ), true, 1 )
4043  << Parameter( QStringLiteral( "offset" ), true, 0.25 )
4044  << Parameter( QStringLiteral( "min_length" ), true, -1 )
4045  << Parameter( QStringLiteral( "max_angle" ), true, 180 ), fcnSmooth, QStringLiteral( "GeometryGroup" ) )
4046  << new StaticFunction( QStringLiteral( "num_points" ), 1, fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
4047  << new StaticFunction( QStringLiteral( "num_interior_rings" ), 1, fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
4048  << new StaticFunction( QStringLiteral( "num_rings" ), 1, fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
4049  << new StaticFunction( QStringLiteral( "num_geometries" ), 1, fcnGeomNumGeometries, QStringLiteral( "GeometryGroup" ) )
4050  << new StaticFunction( QStringLiteral( "bounds_width" ), 1, fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
4051  << new StaticFunction( QStringLiteral( "bounds_height" ), 1, fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
4052  << new StaticFunction( QStringLiteral( "is_closed" ), 1, fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
4053  << new StaticFunction( QStringLiteral( "convex_hull" ), 1, fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
4054  << new StaticFunction( QStringLiteral( "difference" ), 2, fcnDifference, QStringLiteral( "GeometryGroup" ) )
4055  << new StaticFunction( QStringLiteral( "distance" ), 2, fcnDistance, QStringLiteral( "GeometryGroup" ) )
4056  << new StaticFunction( QStringLiteral( "intersection" ), 2, fcnIntersection, QStringLiteral( "GeometryGroup" ) )
4057  << new StaticFunction( QStringLiteral( "sym_difference" ), 2, fcnSymDifference, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "symDifference" ) )
4058  << new StaticFunction( QStringLiteral( "combine" ), 2, fcnCombine, QStringLiteral( "GeometryGroup" ) )
4059  << new StaticFunction( QStringLiteral( "union" ), 2, fcnCombine, QStringLiteral( "GeometryGroup" ) )
4060  << new StaticFunction( QStringLiteral( "geom_to_wkt" ), -1, fcnGeomToWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomToWKT" ) )
4061  << new StaticFunction( QStringLiteral( "geometry" ), 1, fcnGetGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
4062  << new StaticFunction( QStringLiteral( "transform" ), 3, fcnTransformGeometry, QStringLiteral( "GeometryGroup" ) )
4063  << new StaticFunction( QStringLiteral( "extrude" ), 3, fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
4064  << new StaticFunction( QStringLiteral( "order_parts" ), 3, fcnOrderParts, QStringLiteral( "GeometryGroup" ), QString() )
4065  << new StaticFunction( QStringLiteral( "closest_point" ), 2, fcnClosestPoint, QStringLiteral( "GeometryGroup" ) )
4066  << new StaticFunction( QStringLiteral( "shortest_line" ), 2, fcnShortestLine, QStringLiteral( "GeometryGroup" ) )
4067  << new StaticFunction( QStringLiteral( "line_interpolate_point" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4068  << Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolatePoint, QStringLiteral( "GeometryGroup" ) )
4069  << new StaticFunction( QStringLiteral( "line_interpolate_angle" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4070  << Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolateAngle, QStringLiteral( "GeometryGroup" ) )
4071  << new StaticFunction( QStringLiteral( "line_locate_point" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4072  << Parameter( QStringLiteral( "point" ) ), fcnLineLocatePoint, QStringLiteral( "GeometryGroup" ) )
4073  << new StaticFunction( QStringLiteral( "angle_at_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4074  << Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
4075  << new StaticFunction( QStringLiteral( "distance_to_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4076  << Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
4077 
4078 
4079  // **Record** functions
4080 
4081  << new StaticFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record" ) )
4082  << new StaticFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record" ) )
4083  << new StaticFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) )
4084  << new StaticFunction( QStringLiteral( "get_feature" ), 3, fcnGetFeature, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "getFeature" ) )
4085 
4086  << new StaticFunction(
4087  QStringLiteral( "is_selected" ),
4088  -1,
4089  fcnIsSelected,
4090  QStringLiteral( "Record" ),
4091  QString(),
4092  false,
4093  QSet<QString>()
4094  )
4095 
4096  << new StaticFunction(
4097  QStringLiteral( "num_selected" ),
4098  -1,
4100  QStringLiteral( "Record" ),
4101  QString(),
4102  false,
4103  QSet<QString>()
4104  )
4105 
4106  // **General** functions
4107 
4108  << new StaticFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
4109  << new StaticFunction( QStringLiteral( "raster_statistic" ), ParameterList() << Parameter( QStringLiteral( "layer" ) )
4110  << Parameter( QStringLiteral( "band" ) )
4111  << Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "General" ) )
4112  << new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
4113 
4114  //return all attributes string for referencedColumns - this is caught by
4115  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
4116  // feature request
4117  << new StaticFunction( QStringLiteral( "eval" ), 1, fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES )
4118  << new StaticFunction( QStringLiteral( "attribute" ), 2, fcnAttribute, QStringLiteral( "Record" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES )
4119 
4120  // functions for arrays
4121  << new StaticFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ) )
4122  << new StaticFunction( QStringLiteral( "array_length" ), 1, fcnArrayLength, QStringLiteral( "Arrays" ) )
4123  << new StaticFunction( QStringLiteral( "array_contains" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayContains, QStringLiteral( "Arrays" ) )
4124  << new StaticFunction( QStringLiteral( "array_find" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayFind, QStringLiteral( "Arrays" ) )
4125  << new StaticFunction( QStringLiteral( "array_get" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ), fcnArrayGet, QStringLiteral( "Arrays" ) )
4126  << new StaticFunction( QStringLiteral( "array_append" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayAppend, QStringLiteral( "Arrays" ) )
4127  << new StaticFunction( QStringLiteral( "array_prepend" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayPrepend, QStringLiteral( "Arrays" ) )
4128  << new StaticFunction( QStringLiteral( "array_insert" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayInsert, QStringLiteral( "Arrays" ) )
4129  << new StaticFunction( QStringLiteral( "array_remove_at" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ), fcnArrayRemoveAt, QStringLiteral( "Arrays" ) )
4130  << new StaticFunction( QStringLiteral( "array_remove_all" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayRemoveAll, QStringLiteral( "Arrays" ) )
4131  << new StaticFunction( QStringLiteral( "array_cat" ), -1, fcnArrayCat, QStringLiteral( "Arrays" ) )
4132  << new StaticFunction( QStringLiteral( "array_intersect" ), ParameterList() << Parameter( QStringLiteral( "array1" ) ) << Parameter( QStringLiteral( "array2" ) ), fcnArrayIntersect, QStringLiteral( "Arrays" ) )
4133  << new StaticFunction( QStringLiteral( "array_distinct" ), 1, fcnArrayDistinct, QStringLiteral( "Arrays" ) )
4134  << new StaticFunction( QStringLiteral( "array_to_string" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "," ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnArrayToString, QStringLiteral( "Arrays" ) )
4135  << new StaticFunction( QStringLiteral( "string_to_array" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "," ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnStringToArray, QStringLiteral( "Arrays" ) )
4136 
4137  //functions for maps
4138  << new StaticFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) )
4139  << new StaticFunction( QStringLiteral( "map_get" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapGet, QStringLiteral( "Maps" ) )
4140  << new StaticFunction( QStringLiteral( "map_exist" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapExist, QStringLiteral( "Maps" ) )
4141  << new StaticFunction( QStringLiteral( "map_delete" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapDelete, QStringLiteral( "Maps" ) )
4142  << new StaticFunction( QStringLiteral( "map_insert" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ) << Parameter( QStringLiteral( "value" ) ), fcnMapInsert, QStringLiteral( "Maps" ) )
4143  << new StaticFunction( QStringLiteral( "map_concat" ), -1, fcnMapConcat, QStringLiteral( "Maps" ) )
4144  << new StaticFunction( QStringLiteral( "map_akeys" ), ParameterList() << Parameter( QStringLiteral( "map" ) ), fcnMapAKeys, QStringLiteral( "Maps" ) )
4145  << new StaticFunction( QStringLiteral( "map_avals" ), ParameterList() << Parameter( QStringLiteral( "map" ) ), fcnMapAVals, QStringLiteral( "Maps" ) )
4146  ;
4147 
4149 
4150  //QgsExpression has ownership of all built-in functions
4151  Q_FOREACH ( QgsExpression::Function* func, sFunctions )
4152  {
4153  sOwnedFunctions << func;
4154  sBuiltinFunctions << func->name();
4155  sBuiltinFunctions.append( func->aliases() );
4156  }
4157  }
4158  return sFunctions;
4159 }
4160 
4161 bool QgsExpression::checkExpression( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
4162 {
4163  QgsExpression exp( text );
4164  exp.prepare( context );
4165  errorMessage = exp.parserErrorString();
4166  return !exp.hasParserError();
4167 }
4168 
4170 {
4171  detach();
4172  d->mRootNode = ::parseExpression( expression, d->mParserErrorString );
4173  d->mEvalErrorString = QString();
4174  d->mExp = expression;
4175 }
4176 
4178 {
4179  if ( !d->mExp.isNull() )
4180  return d->mExp;
4181  else
4182  return dump();
4183 }
4184 
4185 QString QgsExpression::quotedColumnRef( QString name )
4186 {
4187  return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
4188 }
4189 
4190 QString QgsExpression::quotedString( QString text )
4191 {
4192  text.replace( '\'', QLatin1String( "''" ) );
4193  text.replace( '\\', QLatin1String( "\\\\" ) );
4194  text.replace( '\n', QLatin1String( "\\n" ) );
4195  text.replace( '\t', QLatin1String( "\\t" ) );
4196  return QStringLiteral( "'%1'" ).arg( text );
4197 }
4198 
4199 QString QgsExpression::quotedValue( const QVariant &value )
4200 {
4201  return quotedValue( value, value.type() );
4202 }
4203 
4204 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
4205 {
4206  if ( value.isNull() )
4207  return QStringLiteral( "NULL" );
4208 
4209  switch ( type )
4210  {
4211  case QVariant::Int:
4212  case QVariant::LongLong:
4213  case QVariant::Double:
4214  return value.toString();
4215 
4216  case QVariant::Bool:
4217  return value.toBool() ? "TRUE" : "FALSE";
4218 
4219  default:
4220  case QVariant::String:
4221  return quotedString( value.toString() );
4222  }
4223 
4224 }
4225 
4226 bool QgsExpression::isFunctionName( const QString &name )
4227 {
4228  return functionIndex( name ) != -1;
4229 }
4230 
4231 int QgsExpression::functionIndex( const QString &name )
4232 {
4233  int count = functionCount();
4234  for ( int i = 0; i < count; i++ )
4235  {
4236  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
4237  return i;
4238  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
4239  {
4240  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
4241  return i;
4242  }
4243  }
4244  return -1;
4245 }
4246 
4248 {
4249  return Functions().size();
4250 }
4251 
4252 
4253 QgsExpression::QgsExpression( const QString& expr )
4254  : d( new QgsExpressionPrivate )
4255 {
4256  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
4257  d->mExp = expr;
4258  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
4259 }
4260 
4262  : d( other.d )
4263 {
4264  d->ref.ref();
4265 }
4266 
4268 {
4269  if ( !d->ref.deref() )
4270  {
4271  delete d;
4272  }
4273 
4274  d = other.d;
4275  d->ref.ref();
4276  return *this;
4277 }
4278 
4280  : d( new QgsExpressionPrivate )
4281 {
4282 }
4283 
4285 {
4286  Q_ASSERT( d );
4287  if ( !d->ref.deref() )
4288  delete d;
4289 }
4290 
4291 bool QgsExpression::operator==( const QgsExpression& other ) const
4292 {
4293  return ( d == other.d || d->mExp == other.d->mExp );
4294 }
4295 
4297 {
4298  return d->mRootNode;
4299 }
4300 
4301 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
4302 
4303 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
4304 
4306 {
4307  if ( !d->mRootNode )
4308  return QSet<QString>();
4309 
4310  return d->mRootNode->referencedColumns();
4311 }
4312 
4314 {
4315  if ( !d->mRootNode )
4316  return QSet<QString>();
4317 
4318  return d->mRootNode->referencedVariables();
4319 }
4320 
4322 {
4323  bool needs = false;
4324  Q_FOREACH ( Node* n, mList->list() )
4325  needs |= n->needsGeometry();
4326  return needs;
4327 }
4328 
4330 {
4331  if ( !d->mRootNode )
4332  return QSet<int>();
4333 
4334  const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
4335  QSet<int> referencedIndexes;
4336 
4337 for ( const QString& fieldName : referencedFields )
4338  {
4339  if ( fieldName == QgsFeatureRequest::ALL_ATTRIBUTES )
4340  {
4341  referencedIndexes = fields.allAttributesList().toSet();
4342  break;
4343  }
4344  referencedIndexes << fields.lookupField( fieldName );
4345  }
4346 
4347  return referencedIndexes;
4348 }
4349 
4351 {
4352  if ( !d->mRootNode )
4353  return false;
4354  return d->mRootNode->needsGeometry();
4355 }
4356 
4358 {
4359  if ( d->mCalc.get() )
4360  return;
4361 
4362  // Use planimetric as default
4363  d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
4364  d->mCalc->setEllipsoidalMode( false );
4365 }
4366 
4368 {
4369  Q_ASSERT( d );
4370 
4371  if ( d->ref > 1 )
4372  {
4373  ( void )d->ref.deref();
4374 
4375  d = new QgsExpressionPrivate( *d );
4376  }
4377 }
4378 
4380 {
4381  detach();
4382  if ( calc )
4383  d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea( *calc ) );
4384  else
4385  d->mCalc.reset();
4386 }
4387 
4389 {
4390  detach();
4391  d->mEvalErrorString = QString();
4392  if ( !d->mRootNode )
4393  {
4394  //re-parse expression. Creation of QgsExpressionContexts may have added extra
4395  //known functions since this expression was created, so we have another try
4396  //at re-parsing it now that the context must have been created
4397  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
4398  }
4399 
4400  if ( !d->mRootNode )
4401  {
4402  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4403  return false;
4404  }
4405 
4406  return d->mRootNode->prepare( this, context );
4407 }
4408 
4410 {
4411  d->mEvalErrorString = QString();
4412  if ( !d->mRootNode )
4413  {
4414  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4415  return QVariant();
4416  }
4417 
4418  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
4419 }
4420 
4422 {
4423  d->mEvalErrorString = QString();
4424  if ( !d->mRootNode )
4425  {
4426  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4427  return QVariant();
4428  }
4429 
4430  return d->mRootNode->eval( this, context );
4431 }
4432 
4434 {
4435  return !d->mEvalErrorString.isNull();
4436 }
4437 
4439 {
4440  return d->mEvalErrorString;
4441 }
4442 
4443 void QgsExpression::setEvalErrorString( const QString& str )
4444 {
4445  d->mEvalErrorString = str;
4446 }
4447 
4448 QString QgsExpression::dump() const
4449 {
4450  if ( !d->mRootNode )
4451  return QString();
4452 
4453  return d->mRootNode->dump();
4454 }
4455 
4457 {
4458  return d->mCalc.get();
4459 }
4460 
4462 {
4463  return d->mDistanceUnit;
4464 }
4465 
4467 {
4468  d->mDistanceUnit = unit;
4469 }
4470 
4472 {
4473  return d->mAreaUnit;
4474 }
4475 
4477 {
4478  d->mAreaUnit = unit;
4479 }
4480 
4481 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea )
4482 {
4483  QString expr_action;
4484 
4485  int index = 0;
4486  while ( index < action.size() )
4487  {
4488  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
4489 
4490  int pos = rx.indexIn( action, index );
4491  if ( pos < 0 )
4492  break;
4493 
4494  int start = index;
4495  index = pos + rx.matchedLength();
4496  QString to_replace = rx.cap( 1 ).trimmed();
4497  QgsDebugMsg( "Found expression: " + to_replace );
4498 
4499  QgsExpression exp( to_replace );
4500  if ( exp.hasParserError() )
4501  {
4502  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
4503  expr_action += action.midRef( start, index - start );
4504  continue;
4505  }
4506 
4507  if ( distanceArea )
4508  {
4509  //if QgsDistanceArea specified for area/distance conversion, use it
4510  exp.setGeomCalculator( distanceArea );
4511  }
4512 
4513  QVariant result = exp.evaluate( context );
4514 
4515  if ( exp.hasEvalError() )
4516  {
4517  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
4518  expr_action += action.midRef( start, index - start );
4519  continue;
4520  }
4521 
4522  QgsDebugMsg( "Expression result is: " + result.toString() );
4523  expr_action += action.mid( start, pos - start ) + result.toString();
4524  }
4525 
4526  expr_action += action.midRef( index );
4527 
4528  return expr_action;
4529 }
4530 
4531 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
4532 {
4533  bool ok;
4534  //first test if text is directly convertible to double
4535  double convertedValue = text.toDouble( &ok );
4536  if ( ok )
4537  {
4538  return convertedValue;
4539  }
4540 
4541  //otherwise try to evaluate as expression
4542  QgsExpression expr( text );
4543 
4544  QgsExpressionContext context;
4547 
4548  QVariant result = expr.evaluate( &context );
4549  convertedValue = result.toDouble( &ok );
4550  if ( expr.hasEvalError() || !ok )
4551  {
4552  return fallbackValue;
4553  }
4554  return convertedValue;
4555 }
4556 
4557 
4559 // nodes
4560 
4562 {
4563  mList.append( node->node );
4564  mNameList.append( node->name.toLower() );
4565  mHasNamedNodes = true;
4566  delete node;
4567 }
4568 
4570 {
4571  NodeList* nl = new NodeList;
4572  Q_FOREACH ( Node* node, mList )
4573  {
4574  nl->mList.append( node->clone() );
4575  }
4576  nl->mNameList = mNameList;
4577 
4578  return nl;
4579 }
4580 
4582 {
4583  QString msg;
4584  bool first = true;
4585  Q_FOREACH ( Node* n, mList )
4586  {
4587  if ( !first ) msg += QLatin1String( ", " );
4588  else first = false;
4589  msg += n->dump();
4590  }
4591  return msg;
4592 }
4593 
4594 
4595 //
4596 
4598 {
4599  QVariant val = mOperand->eval( parent, context );
4601 
4602  switch ( mOp )
4603  {
4604  case uoNot:
4605  {
4606  TVL tvl = getTVLValue( val, parent );
4608  return tvl2variant( NOT[tvl] );
4609  }
4610 
4611  case uoMinus:
4612  if ( isIntSafe( val ) )
4613  return QVariant( - getIntValue( val, parent ) );
4614  else if ( isDoubleSafe( val ) )
4615  return QVariant( - getDoubleValue( val, parent ) );
4616  else
4617  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
4618  default:
4619  Q_ASSERT( false && "unknown unary operation" );
4620  }
4621  return QVariant();
4622 }
4623 
4625 {
4626  return mOperand->prepare( parent, context );
4627 }
4628 
4630 {
4631  return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
4632 }
4633 
4635 {
4636  return mOperand->referencedColumns();
4637 }
4638 
4640 {
4641  return mOperand->referencedVariables();
4642 }
4643 
4645 {
4646  return new NodeUnaryOperator( mOp, mOperand->clone() );
4647 }
4648 
4649 //
4650 
4652 {
4653  QVariant vL = mOpLeft->eval( parent, context );
4655  QVariant vR = mOpRight->eval( parent, context );
4657 
4658  switch ( mOp )
4659  {
4660  case boPlus:
4661  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4662  {
4663  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4665  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4667  return QVariant( sL + sR );
4668  }
4669  //intentional fall-through
4670  FALLTHROUGH;
4671  case boMinus:
4672  case boMul:
4673  case boDiv:
4674  case boMod:
4675  {
4676  if ( isNull( vL ) || isNull( vR ) )
4677  return QVariant();
4678  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4679  {
4680  // both are integers - let's use integer arithmetics
4681  qlonglong iL = getIntValue( vL, parent );
4683  qlonglong iR = getIntValue( vR, parent );
4685 
4686  if ( mOp == boMod && iR == 0 )
4687  return QVariant();
4688 
4689  return QVariant( computeInt( iL, iR ) );
4690  }
4691  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4692  {
4693  QDateTime dL = getDateTimeValue( vL, parent );
4695  QgsInterval iL = getInterval( vR, parent );
4697  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4698  {
4699  parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
4700  return QVariant();
4701  }
4702  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4703  }
4704  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4705  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4706  {
4707  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4709  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4711  QDateTime dt = QDateTime( date, time );
4712  return QVariant( dt );
4713  }
4714  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
4715  {
4716  QDate date1 = getDateValue( vL, parent );
4718  QDate date2 = getDateValue( vR, parent );
4720  return date1 - date2;
4721  }
4722  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
4723  {
4724  QTime time1 = getTimeValue( vL, parent );
4726  QTime time2 = getTimeValue( vR, parent );
4728  return time1 - time2;
4729  }
4730  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
4731  {
4732  QDateTime datetime1 = getDateTimeValue( vL, parent );
4734  QDateTime datetime2 = getDateTimeValue( vR, parent );
4736  return datetime1 - datetime2;
4737  }
4738  else
4739  {
4740  // general floating point arithmetic
4741  double fL = getDoubleValue( vL, parent );
4743  double fR = getDoubleValue( vR, parent );
4745  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
4746  return QVariant(); // silently handle division by zero and return NULL
4747  return QVariant( computeDouble( fL, fR ) );
4748  }
4749  }
4750  case boIntDiv:
4751  {
4752  //integer division
4753  double fL = getDoubleValue( vL, parent );
4755  double fR = getDoubleValue( vR, parent );
4757  if ( fR == 0. )
4758  return QVariant(); // silently handle division by zero and return NULL
4759  return QVariant( qFloor( fL / fR ) );
4760  }
4761  case boPow:
4762  if ( isNull( vL ) || isNull( vR ) )
4763  return QVariant();
4764  else
4765  {
4766  double fL = getDoubleValue( vL, parent );
4768  double fR = getDoubleValue( vR, parent );
4770  return QVariant( pow( fL, fR ) );
4771  }
4772 
4773  case boAnd:
4774  {
4775  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4777  return tvl2variant( AND[tvlL][tvlR] );
4778  }
4779 
4780  case boOr:
4781  {
4782  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4784  return tvl2variant( OR[tvlL][tvlR] );
4785  }
4786 
4787  case boEQ:
4788  case boNE:
4789  case boLT:
4790  case boGT:
4791  case boLE:
4792  case boGE:
4793  if ( isNull( vL ) || isNull( vR ) )
4794  {
4795  return TVL_Unknown;
4796  }
4797  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4798  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4799  {
4800  // do numeric comparison if both operators can be converted to numbers,
4801  // and they aren't both string
4802  double fL = getDoubleValue( vL, parent );
4804  double fR = getDoubleValue( vR, parent );
4806  return compare( fL - fR ) ? TVL_True : TVL_False;
4807  }
4808  else
4809  {
4810  // do string comparison otherwise
4811  QString sL = getStringValue( vL, parent );
4813  QString sR = getStringValue( vR, parent );
4815  int diff = QString::compare( sL, sR );
4816  return compare( diff ) ? TVL_True : TVL_False;
4817  }
4818 
4819  case boIs:
4820  case boIsNot:
4821  if ( isNull( vL ) && isNull( vR ) ) // both operators null
4822  return ( mOp == boIs ? TVL_True : TVL_False );
4823  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
4824  return ( mOp == boIs ? TVL_False : TVL_True );
4825  else // both operators non-null
4826  {
4827  bool equal = false;
4828  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4829  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4830  {
4831  double fL = getDoubleValue( vL, parent );
4833  double fR = getDoubleValue( vR, parent );
4835  equal = qgsDoubleNear( fL, fR );
4836  }
4837  else
4838  {
4839  QString sL = getStringValue( vL, parent );
4841  QString sR = getStringValue( vR, parent );
4843  equal = QString::compare( sL, sR ) == 0;
4844  }
4845  if ( equal )
4846  return mOp == boIs ? TVL_True : TVL_False;
4847  else
4848  return mOp == boIs ? TVL_False : TVL_True;
4849  }
4850 
4851  case boRegexp:
4852  case boLike:
4853  case boNotLike:
4854  case boILike:
4855  case boNotILike:
4856  if ( isNull( vL ) || isNull( vR ) )
4857  return TVL_Unknown;
4858  else
4859  {
4860  QString str = getStringValue( vL, parent );
4862  QString regexp = getStringValue( vR, parent );
4864  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
4865  bool matches;
4866  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
4867  {
4868  QString esc_regexp = QRegExp::escape( regexp );
4869  // manage escape % and _
4870  if ( esc_regexp.startsWith( '%' ) )
4871  {
4872  esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
4873  }
4874  QRegExp rx( "[^\\\\](%)" );
4875  int pos = 0;
4876  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4877  {
4878  esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
4879  pos += 1;
4880  }
4881  rx.setPattern( QStringLiteral( "\\\\%" ) );
4882  esc_regexp.replace( rx, QStringLiteral( "%" ) );
4883  if ( esc_regexp.startsWith( '_' ) )
4884  {
4885  esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
4886  }
4887  rx.setPattern( QStringLiteral( "[^\\\\](_)" ) );
4888  pos = 0;
4889  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4890  {
4891  esc_regexp.replace( pos + 1, 1, '.' );
4892  pos += 1;
4893  }
4894  rx.setPattern( QStringLiteral( "\\\\_" ) );
4895  esc_regexp.replace( rx, QStringLiteral( "_" ) );
4896  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
4897  }
4898  else
4899  {
4900  matches = QRegExp( regexp ).indexIn( str ) != -1;
4901  }
4902 
4903  if ( mOp == boNotLike || mOp == boNotILike )
4904  {
4905  matches = !matches;
4906  }
4907 
4908  return matches ? TVL_True : TVL_False;
4909  }
4910 
4911  case boConcat:
4912  if ( isNull( vL ) || isNull( vR ) )
4913  return QVariant();
4914  else
4915  {
4916  QString sL = getStringValue( vL, parent );
4918  QString sR = getStringValue( vR, parent );
4920  return QVariant( sL + sR );
4921  }
4922 
4923  default:
4924  break;
4925  }
4926  Q_ASSERT( false );
4927  return QVariant();
4928 }
4929 
4930 bool QgsExpression::NodeBinaryOperator::compare( double diff )
4931 {
4932  switch ( mOp )
4933  {
4934  case boEQ:
4935  return qgsDoubleNear( diff, 0.0 );
4936  case boNE:
4937  return !qgsDoubleNear( diff, 0.0 );
4938  case boLT:
4939  return diff < 0;
4940  case boGT:
4941  return diff > 0;
4942  case boLE:
4943  return diff <= 0;
4944  case boGE:
4945  return diff >= 0;
4946  default:
4947  Q_ASSERT( false );
4948  return false;
4949  }
4950 }
4951 
4952 qlonglong QgsExpression::NodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
4953 {
4954  switch ( mOp )
4955  {
4956  case boPlus:
4957  return x + y;
4958  case boMinus:
4959  return x - y;
4960  case boMul:
4961  return x * y;
4962  case boDiv:
4963  return x / y;
4964  case boMod:
4965  return x % y;
4966  default:
4967  Q_ASSERT( false );
4968  return 0;
4969  }
4970 }
4971 
4972 QDateTime QgsExpression::NodeBinaryOperator::computeDateTimeFromInterval( const QDateTime& d, QgsInterval *i )
4973 {
4974  switch ( mOp )
4975  {
4976  case boPlus:
4977  return d.addSecs( i->seconds() );
4978  case boMinus:
4979  return d.addSecs( -i->seconds() );
4980  default:
4981  Q_ASSERT( false );
4982  return QDateTime();
4983  }
4984 }
4985 
4986 double QgsExpression::NodeBinaryOperator::computeDouble( double x, double y )
4987 {
4988  switch ( mOp )
4989  {
4990  case boPlus:
4991  return x + y;
4992  case boMinus:
4993  return x - y;
4994  case boMul:
4995  return x * y;
4996  case boDiv:
4997  return x / y;
4998  case boMod:
4999  return fmod( x, y );
5000  default:
5001  Q_ASSERT( false );
5002  return 0;
5003  }
5004 }
5005 
5007 {
5008  bool resL = mOpLeft->prepare( parent, context );
5009  bool resR = mOpRight->prepare( parent, context );
5010  return resL && resR;
5011 }
5012 
5014 {
5015  // see left/right in qgsexpressionparser.yy
5016  switch ( mOp )
5017  {
5018  case boOr:
5019  return 1;
5020 
5021  case boAnd:
5022  return 2;
5023 
5024  case boEQ:
5025  case boNE:
5026  case boLE:
5027  case boGE:
5028  case boLT:
5029  case boGT:
5030  case boRegexp:
5031  case boLike:
5032  case boILike:
5033  case boNotLike:
5034  case boNotILike:
5035  case boIs:
5036  case boIsNot:
5037  return 3;
5038 
5039  case boPlus:
5040  case boMinus:
5041  return 4;
5042 
5043  case boMul:
5044  case boDiv:
5045  case boIntDiv:
5046  case boMod:
5047  return 5;
5048 
5049  case boPow:
5050  return 6;
5051 
5052  case boConcat:
5053  return 7;
5054  }
5055  Q_ASSERT( false && "unexpected binary operator" );
5056  return -1;
5057 }
5058 
5060 {
5061  // see left/right in qgsexpressionparser.yy
5062  switch ( mOp )
5063  {
5064  case boOr:
5065  case boAnd:
5066  case boEQ:
5067  case boNE:
5068  case boLE:
5069  case boGE:
5070  case boLT:
5071  case boGT:
5072  case boRegexp:
5073  case boLike:
5074  case boILike:
5075  case boNotLike:
5076  case boNotILike:
5077  case boIs:
5078  case boIsNot:
5079  case boPlus:
5080  case boMinus:
5081  case boMul:
5082  case boDiv:
5083  case boIntDiv:
5084  case boMod:
5085  case boConcat:
5086  return true;
5087 
5088  case boPow:
5089  return false;
5090  }
5091  Q_ASSERT( false && "unexpected binary operator" );
5092  return false;
5093 }
5094 
5096 {
5097  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
5098  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
5099  QgsExpression::NodeUnaryOperator *ruOp = dynamic_cast<QgsExpression::NodeUnaryOperator *>( mOpRight );
5100 
5101  QString rdump( mOpRight->dump() );
5102 
5103  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
5104  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
5105  {
5106  rdump.prepend( '(' ).append( ')' );
5107  }
5108 
5109  QString fmt;
5110  if ( leftAssociative() )
5111  {
5112  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";