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