QGIS API Documentation  2.15.0-Master (94d88e6)
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 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 #include <QMutex>
25 
26 #include <math.h>
27 #include <limits>
28 
29 #include "qgsdistancearea.h"
30 #include "qgsfeature.h"
31 #include "qgsgeometry.h"
32 #include "qgsgeometryengine.h"
33 #include "qgsgeometryutils.h"
34 #include "qgslogger.h"
35 #include "qgsmaplayerregistry.h"
36 #include "qgsogcutils.h"
37 #include "qgsvectorlayer.h"
38 #include "qgssymbollayerv2utils.h"
39 #include "qgsvectorcolorrampv2.h"
40 #include "qgsstylev2.h"
41 #include "qgsexpressioncontext.h"
42 #include "qgsproject.h"
43 #include "qgsstringutils.h"
45 #include "qgspointv2.h"
46 #include "qgspolygonv2.h"
47 #include "qgsmultipointv2.h"
48 #include "qgsmultilinestringv2.h"
49 #include "qgscurvepolygonv2.h"
50 #include "qgsexpressionprivate.h"
51 #include "qgsexpressionsorter.h"
52 
53 #if QT_VERSION < 0x050000
54 #include <qtextdocument.h>
55 #endif
56 
57 // from parser
58 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
59 
61 // three-value logic
62 
63 enum TVL
64 {
68 };
69 
70 static TVL AND[3][3] =
71 {
72  // false true unknown
73  { False, False, False }, // false
74  { False, True, Unknown }, // true
75  { False, Unknown, Unknown } // unknown
76 };
77 
78 static TVL OR[3][3] =
79 {
80  { False, True, Unknown }, // false
81  { True, True, True }, // true
82  { Unknown, True, Unknown } // unknown
83 };
84 
85 static TVL NOT[3] = { True, False, Unknown };
86 
88 {
89  switch ( v )
90  {
91  case False:
92  return 0;
93  case True:
94  return 1;
95  case Unknown:
96  default:
97  return QVariant();
98  }
99 }
100 
101 #define TVL_True QVariant(1)
102 #define TVL_False QVariant(0)
103 #define TVL_Unknown QVariant()
104 
106 // QVariant checks and conversions
107 
108 inline bool isIntSafe( const QVariant& v )
109 {
110  if ( v.type() == QVariant::Int ) return true;
111  if ( v.type() == QVariant::UInt ) return true;
112  if ( v.type() == QVariant::LongLong ) return true;
113  if ( v.type() == QVariant::ULongLong ) return true;
114  if ( v.type() == QVariant::Double ) return false;
115  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
116  return false;
117 }
118 inline bool isDoubleSafe( const QVariant& v )
119 {
120  if ( v.type() == QVariant::Double ) return true;
121  if ( v.type() == QVariant::Int ) return true;
122  if ( v.type() == QVariant::UInt ) return true;
123  if ( v.type() == QVariant::LongLong ) return true;
124  if ( v.type() == QVariant::ULongLong ) return true;
125  if ( v.type() == QVariant::String )
126  {
127  bool ok;
128  double val = v.toString().toDouble( &ok );
129  ok = ok && qIsFinite( val ) && !qIsNaN( val );
130  return ok;
131  }
132  return false;
133 }
134 
135 inline bool isDateTimeSafe( const QVariant& v )
136 {
137  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
138  v.type() == QVariant::Time;
139 }
140 
141 inline bool isIntervalSafe( const QVariant& v )
142 {
143  if ( v.canConvert<QgsInterval>() )
144  {
145  return true;
146  }
147 
148  if ( v.type() == QVariant::String )
149  {
150  return QgsInterval::fromString( v.toString() ).isValid();
151  }
152  return false;
153 }
154 
155 inline bool isNull( const QVariant& v ) { return v.isNull(); }
156 
158 // evaluation error macros
159 
160 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
161 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
162 
164 // operators
165 
166 const char* QgsExpression::BinaryOperatorText[] =
167 {
168  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
169  "OR", "AND",
170  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
171  "+", "-", "*", "/", "//", "%", "^",
172  "||"
173 };
174 
175 const char* QgsExpression::UnaryOperatorText[] =
176 {
177  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
178  "NOT", "-"
179 };
180 
182 // functions
183 
184 // implicit conversion to string
186 {
187  return value.toString();
188 }
189 
190 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
191 {
192  bool ok;
193  double x = value.toDouble( &ok );
194  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
195  {
196  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
197  return 0;
198  }
199  return x;
200 }
201 
202 static int getIntValue( const QVariant& value, QgsExpression* parent )
203 {
204  bool ok;
205  qint64 x = value.toLongLong( &ok );
207  {
208  return x;
209  }
210  else
211  {
212  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
213  return 0;
214  }
215 }
216 
217 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
218 {
219  QDateTime d = value.toDateTime();
220  if ( d.isValid() )
221  {
222  return d;
223  }
224  else
225  {
226  QTime t = value.toTime();
227  if ( t.isValid() )
228  {
229  return QDateTime( QDate( 1, 1, 1 ), t );
230  }
231 
232  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
233  return QDateTime();
234  }
235 }
236 
237 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
238 {
239  QDate d = value.toDate();
240  if ( d.isValid() )
241  {
242  return d;
243  }
244  else
245  {
246  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
247  return QDate();
248  }
249 }
250 
251 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
252 {
253  QTime t = value.toTime();
254  if ( t.isValid() )
255  {
256  return t;
257  }
258  else
259  {
260  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
261  return QTime();
262  }
263 }
264 
265 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
266 {
267  if ( value.canConvert<QgsInterval>() )
268  return value.value<QgsInterval>();
269 
270  QgsInterval inter = QgsInterval::fromString( value.toString() );
271  if ( inter.isValid() )
272  {
273  return inter;
274  }
275  // If we get here then we can't convert so we just error and return invalid.
276  if ( report_error )
277  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
278 
279  return QgsInterval();
280 }
281 
282 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
283 {
284  if ( value.canConvert<QgsGeometry>() )
285  return value.value<QgsGeometry>();
286 
287  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
288  return QgsGeometry();
289 }
290 
291 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
292 {
293  if ( value.canConvert<QgsFeature>() )
294  return value.value<QgsFeature>();
295 
296  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
297  return 0;
298 }
299 
300 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
301  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
302 
303 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
304 {
305  if ( value.canConvert<QgsExpression::Node*>() )
306  return value.value<QgsExpression::Node*>();
307 
308  parent->setEvalErrorString( "Cannot convert to Node" );
309  return nullptr;
310 }
311 
313 {
314  QString layerString = value.toString();
315  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
316  if ( !vl )
317  {
318  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
319  if ( !layersByName.isEmpty() )
320  {
321  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
322  }
323  }
324 
325  return vl;
326 }
327 
328 
329 // this handles also NULL values
330 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
331 {
332  // we need to convert to TVL
333  if ( value.isNull() )
334  return Unknown;
335 
336  //handle some special cases
337  if ( value.canConvert<QgsGeometry>() )
338  {
339  //geom is false if empty
340  QgsGeometry geom = value.value<QgsGeometry>();
341  return geom.isEmpty() ? False : True;
342  }
343  else if ( value.canConvert<QgsFeature>() )
344  {
345  //feat is false if non-valid
346  QgsFeature feat = value.value<QgsFeature>();
347  return feat.isValid() ? True : False;
348  }
349 
350  if ( value.type() == QVariant::Int )
351  return value.toInt() != 0 ? True : False;
352 
353  bool ok;
354  double x = value.toDouble( &ok );
355  if ( !ok )
356  {
357  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
358  return Unknown;
359  }
360  return !qgsDoubleNear( x, 0.0 ) ? True : False;
361 }
362 
364 
365 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
366 {
367  if ( !context )
368  return QVariant();
369 
370  QString name = getStringValue( values.at( 0 ), parent );
371  return context->variable( name );
372 }
373 
374 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
375 {
376  if ( !context )
377  return QVariant();
378 
379  QString expString = getStringValue( values.at( 0 ), parent );
380  QgsExpression expression( expString );
381  return expression.evaluate( context );
382 }
383 
384 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
385 {
386  double x = getDoubleValue( values.at( 0 ), parent );
387  return QVariant( sqrt( x ) );
388 }
389 
390 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
391 {
392  double val = getDoubleValue( values.at( 0 ), parent );
393  return QVariant( fabs( val ) );
394 }
395 
396 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
397 {
398  double deg = getDoubleValue( values.at( 0 ), parent );
399  return ( deg * M_PI ) / 180;
400 }
401 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
402 {
403  double rad = getDoubleValue( values.at( 0 ), parent );
404  return ( 180 * rad ) / M_PI;
405 }
406 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
407 {
408  double x = getDoubleValue( values.at( 0 ), parent );
409  return QVariant( sin( x ) );
410 }
411 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
412 {
413  double x = getDoubleValue( values.at( 0 ), parent );
414  return QVariant( cos( x ) );
415 }
416 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
417 {
418  double x = getDoubleValue( values.at( 0 ), parent );
419  return QVariant( tan( x ) );
420 }
421 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
422 {
423  double x = getDoubleValue( values.at( 0 ), parent );
424  return QVariant( asin( x ) );
425 }
426 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
427 {
428  double x = getDoubleValue( values.at( 0 ), parent );
429  return QVariant( acos( x ) );
430 }
431 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
432 {
433  double x = getDoubleValue( values.at( 0 ), parent );
434  return QVariant( atan( x ) );
435 }
436 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
437 {
438  double y = getDoubleValue( values.at( 0 ), parent );
439  double x = getDoubleValue( values.at( 1 ), parent );
440  return QVariant( atan2( y, x ) );
441 }
442 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
443 {
444  double x = getDoubleValue( values.at( 0 ), parent );
445  return QVariant( exp( x ) );
446 }
447 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
448 {
449  double x = getDoubleValue( values.at( 0 ), parent );
450  if ( x <= 0 )
451  return QVariant();
452  return QVariant( log( x ) );
453 }
454 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
455 {
456  double x = getDoubleValue( values.at( 0 ), parent );
457  if ( x <= 0 )
458  return QVariant();
459  return QVariant( log10( x ) );
460 }
461 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
462 {
463  double b = getDoubleValue( values.at( 0 ), parent );
464  double x = getDoubleValue( values.at( 1 ), parent );
465  if ( x <= 0 || b <= 0 )
466  return QVariant();
467  return QVariant( log( x ) / log( b ) );
468 }
469 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
470 {
471  double min = getDoubleValue( values.at( 0 ), parent );
472  double max = getDoubleValue( values.at( 1 ), parent );
473  if ( max < min )
474  return QVariant();
475 
476  // Return a random double in the range [min, max] (inclusive)
477  double f = static_cast< double >( qrand() ) / RAND_MAX;
478  return QVariant( min + f * ( max - min ) );
479 }
480 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
481 {
482  int min = getIntValue( values.at( 0 ), parent );
483  int max = getIntValue( values.at( 1 ), parent );
484  if ( max < min )
485  return QVariant();
486 
487  // Return a random integer in the range [min, max] (inclusive)
488  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
489 }
490 
491 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
492 {
493  double val = getDoubleValue( values.at( 0 ), parent );
494  double domainMin = getDoubleValue( values.at( 1 ), parent );
495  double domainMax = getDoubleValue( values.at( 2 ), parent );
496  double rangeMin = getDoubleValue( values.at( 3 ), parent );
497  double rangeMax = getDoubleValue( values.at( 4 ), parent );
498 
499  if ( domainMin >= domainMax )
500  {
501  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
502  return QVariant();
503  }
504 
505  // outside of domain?
506  if ( val >= domainMax )
507  {
508  return rangeMax;
509  }
510  else if ( val <= domainMin )
511  {
512  return rangeMin;
513  }
514 
515  // calculate linear scale
516  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
517  double c = rangeMin - ( domainMin * m );
518 
519  // Return linearly scaled value
520  return QVariant( m * val + c );
521 }
522 
523 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
524 {
525  double val = getDoubleValue( values.at( 0 ), parent );
526  double domainMin = getDoubleValue( values.at( 1 ), parent );
527  double domainMax = getDoubleValue( values.at( 2 ), parent );
528  double rangeMin = getDoubleValue( values.at( 3 ), parent );
529  double rangeMax = getDoubleValue( values.at( 4 ), parent );
530  double exponent = getDoubleValue( values.at( 5 ), parent );
531 
532  if ( domainMin >= domainMax )
533  {
534  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
535  return QVariant();
536  }
537  if ( exponent <= 0 )
538  {
539  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
540  return QVariant();
541  }
542 
543  // outside of domain?
544  if ( val >= domainMax )
545  {
546  return rangeMax;
547  }
548  else if ( val <= domainMin )
549  {
550  return rangeMin;
551  }
552 
553  // Return exponentially scaled value
554  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
555 }
556 
557 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
558 {
559  //initially set max as first value
560  double maxVal = getDoubleValue( values.at( 0 ), parent );
561 
562  //check against all other values
563  for ( int i = 1; i < values.length(); ++i )
564  {
565  double testVal = getDoubleValue( values[i], parent );
566  if ( testVal > maxVal )
567  {
568  maxVal = testVal;
569  }
570  }
571 
572  return QVariant( maxVal );
573 }
574 
575 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
576 {
577  //initially set min as first value
578  double minVal = getDoubleValue( values.at( 0 ), parent );
579 
580  //check against all other values
581  for ( int i = 1; i < values.length(); ++i )
582  {
583  double testVal = getDoubleValue( values[i], parent );
584  if ( testVal < minVal )
585  {
586  minVal = testVal;
587  }
588  }
589 
590  return QVariant( minVal );
591 }
592 
593 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
594 {
595  //lazy eval, so we need to evaluate nodes now
596 
597  //first node is layer id or name
598  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
600  QVariant value = node->eval( parent, context );
602  QgsVectorLayer* vl = getVectorLayer( value, parent );
603  if ( !vl )
604  {
605  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
606  return QVariant();
607  }
608 
609  // second node is aggregate type
610  node = getNode( values.at( 1 ), parent );
612  value = node->eval( parent, context );
614  bool ok = false;
616  if ( !ok )
617  {
618  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
619  return QVariant();
620  }
621 
622  // third node is subexpression (or field name)
623  node = getNode( values.at( 2 ), parent );
625  QString subExpression = node->dump();
626 
628  //optional forth node is filter
629  if ( values.count() > 3 )
630  {
631  node = getNode( values.at( 3 ), parent );
633  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
634  if ( !nl || nl->value().isValid() )
635  parameters.filter = node->dump();
636  }
637 
638  //optional fifth node is concatenator
639  if ( values.count() > 4 )
640  {
641  node = getNode( values.at( 4 ), parent );
643  value = node->eval( parent, context );
645  parameters.delimiter = value.toString();
646  }
647 
648  QString cacheKey = QString( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( static_cast< int >( aggregate ) ), subExpression, parameters.filter );
649  if ( context && context->hasCachedValue( cacheKey ) )
650  return context->cachedValue( cacheKey );
651 
652  QVariant result;
653  if ( context )
654  {
655  QgsExpressionContext subContext( *context );
656  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
657  }
658  else
659  {
660  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
661  }
662  if ( !ok )
663  {
664  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
665  return QVariant();
666  }
667 
668  // cache value
669  if ( context )
670  context->setCachedValue( cacheKey, result );
671  return result;
672 }
673 
674 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
675 {
676  if ( !context )
677  {
678  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
679  return QVariant();
680  }
681 
682  // first step - find current layer
683  QString layerId = context->variable( "layer_id" ).toString();
684  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
685  if ( !vl )
686  {
687  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
688  return QVariant();
689  }
690 
691  //lazy eval, so we need to evaluate nodes now
692 
693  //first node is relation name
694  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
696  QVariant value = node->eval( parent, context );
698  QString relationId = value.toString();
699  // check relation exists
700  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
701  if ( !relation.isValid() || relation.referencedLayer() != vl )
702  {
703  // check for relations by name
705  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
706  {
707  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
708  return QVariant();
709  }
710  else
711  {
712  relation = relations.at( 0 );
713  }
714  }
715 
716  QgsVectorLayer* childLayer = relation.referencingLayer();
717 
718  // second node is aggregate type
719  node = getNode( values.at( 1 ), parent );
721  value = node->eval( parent, context );
723  bool ok = false;
725  if ( !ok )
726  {
727  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
728  return QVariant();
729  }
730 
731  //third node is subexpression (or field name)
732  node = getNode( values.at( 2 ), parent );
734  QString subExpression = node->dump();
735 
736  //optional fourth node is concatenator
738  if ( values.count() > 3 )
739  {
740  node = getNode( values.at( 3 ), parent );
742  value = node->eval( parent, context );
744  parameters.delimiter = value.toString();
745  }
746 
747  FEAT_FROM_CONTEXT( context, f );
748  parameters.filter = relation.getRelatedFeaturesFilter( f );
749 
750  QString cacheKey = QString( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
751  QString::number( static_cast< int >( aggregate ) ),
752  subExpression,
753  parameters.filter );
754  if ( context && context->hasCachedValue( cacheKey ) )
755  return context->cachedValue( cacheKey );
756 
757  QVariant result;
758  ok = false;
759 
760 
761  QgsExpressionContext subContext( *context );
762  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
763 
764  if ( !ok )
765  {
766  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
767  return QVariant();
768  }
769 
770  // cache value
771  if ( context )
772  context->setCachedValue( cacheKey, result );
773  return result;
774 }
775 
776 
778 {
779  if ( !context )
780  {
781  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
782  return QVariant();
783  }
784 
785  // first step - find current layer
786  QString layerId = context->variable( "layer_id" ).toString();
787  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
788  if ( !vl )
789  {
790  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
791  return QVariant();
792  }
793 
794  //lazy eval, so we need to evaluate nodes now
795 
796  //first node is subexpression (or field name)
797  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
799  QString subExpression = node->dump();
800 
801  //optional second node is group by
802  QString groupBy;
803  if ( values.count() > 1 )
804  {
805  node = getNode( values.at( 1 ), parent );
807  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
808  if ( !nl || nl->value().isValid() )
809  groupBy = node->dump();
810  }
811 
812  //optional third node is filter
813  if ( values.count() > 2 )
814  {
815  node = getNode( values.at( 2 ), parent );
817  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
818  if ( !nl || nl->value().isValid() )
819  parameters.filter = node->dump();
820  }
821 
822  // build up filter with group by
823 
824  // find current group by value
825  if ( !groupBy.isEmpty() )
826  {
827  QgsExpression groupByExp( groupBy );
828  QVariant groupByValue = groupByExp.evaluate( context );
829  if ( !parameters.filter.isEmpty() )
830  parameters.filter = QString( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
831  else
832  parameters.filter = QString( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
833  }
834 
835  QString cacheKey = QString( "agg:%1:%2:%3:%4" ).arg( vl->id(),
836  QString::number( static_cast< int >( aggregate ) ),
837  subExpression,
838  parameters.filter );
839  if ( context && context->hasCachedValue( cacheKey ) )
840  return context->cachedValue( cacheKey );
841 
842  QVariant result;
843  bool ok = false;
844 
845  QgsExpressionContext subContext( *context );
846  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
847 
848  if ( !ok )
849  {
850  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
851  return QVariant();
852  }
853 
854  // cache value
855  if ( context )
856  context->setCachedValue( cacheKey, result );
857  return result;
858 }
859 
860 
861 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
862 {
864 }
865 
866 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
867 {
869 }
870 
871 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
872 {
874 }
875 
876 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
877 {
879 }
880 
881 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
882 {
884 }
885 
886 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
887 {
889 }
890 
891 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
892 {
894 }
895 
896 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
897 {
899 }
900 
901 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
902 {
904 }
905 
906 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
907 {
909 }
910 
911 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
912 {
914 }
915 
916 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
917 {
919 }
920 
921 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
922 {
924 }
925 
926 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
927 {
929 }
930 
931 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
932 {
934 }
935 
936 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
937 {
939 }
940 
941 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
942 {
944 }
945 
946 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
947 {
949 
950  //fourth node is concatenator
951  if ( values.count() > 3 )
952  {
953  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
955  QVariant value = node->eval( parent, context );
957  parameters.delimiter = value.toString();
958  }
959 
960  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
961 }
962 
963 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
964 {
965  double minValue = getDoubleValue( values.at( 0 ), parent );
966  double testValue = getDoubleValue( values.at( 1 ), parent );
967  double maxValue = getDoubleValue( values.at( 2 ), parent );
968 
969  // force testValue to sit inside the range specified by the min and max value
970  if ( testValue <= minValue )
971  {
972  return QVariant( minValue );
973  }
974  else if ( testValue >= maxValue )
975  {
976  return QVariant( maxValue );
977  }
978  else
979  {
980  return QVariant( testValue );
981  }
982 }
983 
984 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
985 {
986  double x = getDoubleValue( values.at( 0 ), parent );
987  return QVariant( floor( x ) );
988 }
989 
990 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
991 {
992  double x = getDoubleValue( values.at( 0 ), parent );
993  return QVariant( ceil( x ) );
994 }
995 
996 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
997 {
998  return QVariant( getIntValue( values.at( 0 ), parent ) );
999 }
1000 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1001 {
1002  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1003 }
1004 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1005 {
1006  return QVariant( getStringValue( values.at( 0 ), parent ) );
1007 }
1008 
1009 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1010 {
1011  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1012 }
1013 
1014 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1015 {
1016  Q_FOREACH ( const QVariant &value, values )
1017  {
1018  if ( value.isNull() )
1019  continue;
1020  return value;
1021  }
1022  return QVariant();
1023 }
1024 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1025 {
1026  QString str = getStringValue( values.at( 0 ), parent );
1027  return QVariant( str.toLower() );
1028 }
1029 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1030 {
1031  QString str = getStringValue( values.at( 0 ), parent );
1032  return QVariant( str.toUpper() );
1033 }
1034 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1035 {
1036  QString str = getStringValue( values.at( 0 ), parent );
1037  QStringList elems = str.split( ' ' );
1038  for ( int i = 0; i < elems.size(); i++ )
1039  {
1040  if ( elems[i].size() > 1 )
1041  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1042  }
1043  return QVariant( elems.join( " " ) );
1044 }
1045 
1046 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1047 {
1048  QString str = getStringValue( values.at( 0 ), parent );
1049  return QVariant( str.trimmed() );
1050 }
1051 
1052 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1053 {
1054  QString string1 = getStringValue( values.at( 0 ), parent );
1055  QString string2 = getStringValue( values.at( 1 ), parent );
1056  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1057 }
1058 
1059 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1060 {
1061  QString string1 = getStringValue( values.at( 0 ), parent );
1062  QString string2 = getStringValue( values.at( 1 ), parent );
1063  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1064 }
1065 
1066 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1067 {
1068  QString string1 = getStringValue( values.at( 0 ), parent );
1069  QString string2 = getStringValue( values.at( 1 ), parent );
1070  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1071  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1072 }
1073 
1074 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1075 {
1076  QString string = getStringValue( values.at( 0 ), parent );
1077  return QVariant( QgsStringUtils::soundex( string ) );
1078 }
1079 
1080 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1081 {
1082  if ( values.length() == 2 || values.length() == 3 )
1083  {
1084  QString str = getStringValue( values.at( 0 ), parent );
1085  int wrap = getIntValue( values.at( 1 ), parent );
1086 
1087  if ( !str.isEmpty() && wrap != 0 )
1088  {
1089  QString newstr;
1090  QString delimiterstr;
1091  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
1092  if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
1093  int delimiterlength = delimiterstr.length();
1094 
1095  QStringList lines = str.split( '\n' );
1096  int strlength, strcurrent, strhit, lasthit;
1097 
1098  for ( int i = 0; i < lines.size(); i++ )
1099  {
1100  strlength = lines[i].length();
1101  strcurrent = 0;
1102  strhit = 0;
1103  lasthit = 0;
1104 
1105  while ( strcurrent < strlength )
1106  {
1107  // positive wrap value = desired maximum line width to wrap
1108  // negative wrap value = desired minimum line width before wrap
1109  if ( wrap > 0 )
1110  {
1111  //first try to locate delimiter backwards
1112  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
1113  if ( strhit == lasthit || strhit == -1 )
1114  {
1115  //if no new backward delimiter found, try to locate forward
1116  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1117  }
1118  lasthit = strhit;
1119  }
1120  else
1121  {
1122  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1123  }
1124  if ( strhit > -1 )
1125  {
1126  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1127  newstr.append( '\n' );
1128  strcurrent = strhit + delimiterlength;
1129  }
1130  else
1131  {
1132  newstr.append( lines[i].midRef( strcurrent ) );
1133  strcurrent = strlength;
1134  }
1135  }
1136  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1137  }
1138 
1139  return QVariant( newstr );
1140  }
1141  }
1142 
1143  return QVariant();
1144 }
1145 
1146 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1147 {
1148  // two variants, one for geometry, one for string
1149  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1150  {
1151  //geometry variant
1152  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1153  if ( geom.type() != QGis::Line )
1154  return QVariant();
1155 
1156  return QVariant( geom.length() );
1157  }
1158 
1159  //otherwise fall back to string variant
1160  QString str = getStringValue( values.at( 0 ), parent );
1161  return QVariant( str.length() );
1162 }
1163 
1164 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1165 {
1166  QString str = getStringValue( values.at( 0 ), parent );
1167  QString before = getStringValue( values.at( 1 ), parent );
1168  QString after = getStringValue( values.at( 2 ), parent );
1169  return QVariant( str.replace( before, after ) );
1170 }
1171 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1172 {
1173  QString str = getStringValue( values.at( 0 ), parent );
1174  QString regexp = getStringValue( values.at( 1 ), parent );
1175  QString after = getStringValue( values.at( 2 ), parent );
1176 
1177  QRegExp re( regexp );
1178  if ( !re.isValid() )
1179  {
1180  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1181  return QVariant();
1182  }
1183  return QVariant( str.replace( re, after ) );
1184 }
1185 
1186 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1187 {
1188  QString str = getStringValue( values.at( 0 ), parent );
1189  QString regexp = getStringValue( values.at( 1 ), parent );
1190 
1191  QRegExp re( regexp );
1192  if ( !re.isValid() )
1193  {
1194  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1195  return QVariant();
1196  }
1197  return QVariant( str.contains( re ) ? 1 : 0 );
1198 }
1199 
1200 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1201 {
1202  QString str = getStringValue( values.at( 0 ), parent );
1203  QString regexp = getStringValue( values.at( 1 ), parent );
1204 
1205  QRegExp re( regexp );
1206  if ( !re.isValid() )
1207  {
1208  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1209  return QVariant();
1210  }
1211 
1212  // extract substring
1213  ( void )re.indexIn( str );
1214  if ( re.captureCount() > 0 )
1215  {
1216  // return first capture
1217  return QVariant( re.capturedTexts().at( 1 ) );
1218  }
1219  else
1220  {
1221  return QVariant( "" );
1222  }
1223 }
1224 
1225 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1226 {
1227  return QUuid::createUuid().toString();
1228 }
1229 
1230 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1231 {
1232  QString str = getStringValue( values.at( 0 ), parent );
1233  int from = getIntValue( values.at( 1 ), parent );
1234  int len = getIntValue( values.at( 2 ), parent );
1235  return QVariant( str.mid( from -1, len ) );
1236 }
1237 
1238 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1239 {
1240  if ( context && context->hasVariable( "row_number" ) )
1241  return context->variable( "row_number" );
1242 
1244  return QVariant( parent->currentRowNumber() );
1246  //when above is removed - return QVariant()
1247 }
1248 
1249 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1250 {
1251  if ( context && context->hasVariable( "map_id" ) )
1252  return context->variable( "map_id" );
1253 
1255  return QgsExpression::specialColumn( "$map" );
1257 }
1258 
1259 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1260 {
1261  if ( context && context->hasVariable( "layout_numpages" ) )
1262  return context->variable( "layout_numpages" );
1263 
1265  return QgsExpression::specialColumn( "$numpages" );
1267 }
1268 
1269 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1270 {
1271  if ( context && context->hasVariable( "layout_page" ) )
1272  return context->variable( "layout_page" );
1273 
1275  return QgsExpression::specialColumn( "$page" );
1277 }
1278 
1279 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1280 {
1281  if ( context && context->hasVariable( "atlas_featurenumber" ) )
1282  return context->variable( "atlas_featurenumber" );
1283 
1285  return QgsExpression::specialColumn( "$feature" );
1287 }
1288 
1289 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1290 {
1291  if ( context && context->hasVariable( "atlas_featureid" ) )
1292  return context->variable( "atlas_featureid" );
1293 
1295  return QgsExpression::specialColumn( "$atlasfeatureid" );
1297 }
1298 
1299 
1300 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1301 {
1302  if ( context && context->hasVariable( "atlas_feature" ) )
1303  return context->variable( "atlas_feature" );
1304 
1306  return QgsExpression::specialColumn( "$atlasfeature" );
1308 }
1309 
1310 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1311 {
1312  if ( context && context->hasVariable( "atlas_geometry" ) )
1313  return context->variable( "atlas_geometry" );
1314 
1316  return QgsExpression::specialColumn( "$atlasgeometry" );
1318 }
1319 
1320 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1321 {
1322  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
1323  return context->variable( "atlas_totalfeatures" );
1324 
1326  return QgsExpression::specialColumn( "$numfeatures" );
1328 }
1329 
1330 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1331 {
1332  FEAT_FROM_CONTEXT( context, f );
1333  // TODO: handling of 64-bit feature ids?
1334  return QVariant( static_cast< int >( f.id() ) );
1335 }
1336 
1337 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1338 {
1339  if ( !context )
1340  return QVariant();
1341 
1342  return context->variable( QgsExpressionContext::EXPR_FEATURE );
1343 }
1344 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1345 {
1346  QgsFeature feat = getFeature( values.at( 0 ), parent );
1347  QString attr = getStringValue( values.at( 1 ), parent );
1348 
1349  return feat.attribute( attr );
1350 }
1351 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1352 {
1353  QString concat;
1354  Q_FOREACH ( const QVariant &value, values )
1355  {
1356  concat += getStringValue( value, parent );
1357  }
1358  return concat;
1359 }
1360 
1361 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1362 {
1363  QString string = getStringValue( values.at( 0 ), parent );
1364  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) ) + 1;
1365 }
1366 
1367 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1368 {
1369  QString string = getStringValue( values.at( 0 ), parent );
1370  int pos = getIntValue( values.at( 1 ), parent );
1371  return string.right( pos );
1372 }
1373 
1374 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1375 {
1376  QString string = getStringValue( values.at( 0 ), parent );
1377  int pos = getIntValue( values.at( 1 ), parent );
1378  return string.left( pos );
1379 }
1380 
1381 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1382 {
1383  QString string = getStringValue( values.at( 0 ), parent );
1384  int length = getIntValue( values.at( 1 ), parent );
1385  QString fill = getStringValue( values.at( 2 ), parent );
1386  return string.leftJustified( length, fill.at( 0 ), true );
1387 }
1388 
1389 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1390 {
1391  QString string = getStringValue( values.at( 0 ), parent );
1392  int length = getIntValue( values.at( 1 ), parent );
1393  QString fill = getStringValue( values.at( 2 ), parent );
1394  return string.rightJustified( length, fill.at( 0 ), true );
1395 }
1396 
1397 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1398 {
1399  QString string = getStringValue( values.at( 0 ), parent );
1400  for ( int n = 1; n < values.length(); n++ )
1401  {
1402  string = string.arg( getStringValue( values.at( n ), parent ) );
1403  }
1404  return string;
1405 }
1406 
1407 
1408 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1409 {
1411 }
1412 
1413 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1414 {
1415  return QVariant( getDateValue( values.at( 0 ), parent ) );
1416 }
1417 
1418 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1419 {
1420  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1421 }
1422 
1423 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1424 {
1425  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1426 }
1427 
1428 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1429 {
1430  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1431  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1432  int seconds = d2.secsTo( d1 );
1433  return QVariant::fromValue( QgsInterval( seconds ) );
1434 }
1435 
1436 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1437 {
1438  if ( !values.at( 0 ).canConvert<QDate>() )
1439  return QVariant();
1440 
1441  QDate date = getDateValue( values.at( 0 ), parent );
1442  if ( !date.isValid() )
1443  return QVariant();
1444 
1445  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1446  // (to match PostgreSQL behaviour)
1447  return date.dayOfWeek() % 7;
1448 }
1449 
1450 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1451 {
1452  QVariant value = values.at( 0 );
1453  QgsInterval inter = getInterval( value, parent, false );
1454  if ( inter.isValid() )
1455  {
1456  return QVariant( inter.days() );
1457  }
1458  else
1459  {
1460  QDateTime d1 = getDateTimeValue( value, parent );
1461  return QVariant( d1.date().day() );
1462  }
1463 }
1464 
1465 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1466 {
1467  QVariant value = values.at( 0 );
1468  QgsInterval inter = getInterval( value, parent, false );
1469  if ( inter.isValid() )
1470  {
1471  return QVariant( inter.years() );
1472  }
1473  else
1474  {
1475  QDateTime d1 = getDateTimeValue( value, parent );
1476  return QVariant( d1.date().year() );
1477  }
1478 }
1479 
1480 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1481 {
1482  QVariant value = values.at( 0 );
1483  QgsInterval inter = getInterval( value, parent, false );
1484  if ( inter.isValid() )
1485  {
1486  return QVariant( inter.months() );
1487  }
1488  else
1489  {
1490  QDateTime d1 = getDateTimeValue( value, parent );
1491  return QVariant( d1.date().month() );
1492  }
1493 }
1494 
1495 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1496 {
1497  QVariant value = values.at( 0 );
1498  QgsInterval inter = getInterval( value, parent, false );
1499  if ( inter.isValid() )
1500  {
1501  return QVariant( inter.weeks() );
1502  }
1503  else
1504  {
1505  QDateTime d1 = getDateTimeValue( value, parent );
1506  return QVariant( d1.date().weekNumber() );
1507  }
1508 }
1509 
1510 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1511 {
1512  QVariant value = values.at( 0 );
1513  QgsInterval inter = getInterval( value, parent, false );
1514  if ( inter.isValid() )
1515  {
1516  return QVariant( inter.hours() );
1517  }
1518  else
1519  {
1520  QTime t1 = getTimeValue( value, parent );
1521  return QVariant( t1.hour() );
1522  }
1523 }
1524 
1525 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1526 {
1527  QVariant value = values.at( 0 );
1528  QgsInterval inter = getInterval( value, parent, false );
1529  if ( inter.isValid() )
1530  {
1531  return QVariant( inter.minutes() );
1532  }
1533  else
1534  {
1535  QTime t1 = getTimeValue( value, parent );
1536  return QVariant( t1.minute() );
1537  }
1538 }
1539 
1540 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1541 {
1542  QVariant value = values.at( 0 );
1543  QgsInterval inter = getInterval( value, parent, false );
1544  if ( inter.isValid() )
1545  {
1546  return QVariant( inter.seconds() );
1547  }
1548  else
1549  {
1550  QTime t1 = getTimeValue( value, parent );
1551  return QVariant( t1.second() );
1552  }
1553 }
1554 
1555 
1556 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1557  if (!g || g->type() != geomtype) return QVariant();
1558 
1559 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1560 {
1561  FEAT_FROM_CONTEXT( context, f );
1562  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1563  if ( g->isMultipart() )
1564  {
1565  return g->asMultiPoint().at( 0 ).x();
1566  }
1567  else
1568  {
1569  return g->asPoint().x();
1570  }
1571 }
1572 
1573 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1574 {
1575  FEAT_FROM_CONTEXT( context, f );
1576  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1577  if ( g->isMultipart() )
1578  {
1579  return g->asMultiPoint().at( 0 ).y();
1580  }
1581  else
1582  {
1583  return g->asPoint().y();
1584  }
1585 }
1586 
1587 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1588 {
1589  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1590  if ( geom.isEmpty() )
1591  return QVariant();
1592 
1593  //if single point, return the point's x coordinate
1594  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1595  {
1596  return geom.asPoint().x();
1597  }
1598 
1599  //otherwise return centroid x
1600  QgsGeometry* centroid = geom.centroid();
1601  QVariant result( centroid->asPoint().x() );
1602  delete centroid;
1603  return result;
1604 }
1605 
1606 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1607 {
1608  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1609  if ( geom.isEmpty() )
1610  return QVariant();
1611 
1612  //if single point, return the point's y coordinate
1613  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1614  {
1615  return geom.asPoint().y();
1616  }
1617 
1618  //otherwise return centroid y
1619  QgsGeometry* centroid = geom.centroid();
1620  QVariant result( centroid->asPoint().y() );
1621  delete centroid;
1622  return result;
1623 }
1624 
1625 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1626 {
1627  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1628  if ( geom.isEmpty() )
1629  return QVariant(); //or 0?
1630 
1631  //if single point, return the point's z coordinate
1632  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1633  {
1634  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1635  if ( point )
1636  return point->z();
1637  }
1638 
1639  return QVariant();
1640 }
1641 
1642 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1643 {
1644  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1645  if ( geom.isEmpty() )
1646  return QVariant(); //or 0?
1647 
1648  //if single point, return the point's m value
1649  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1650  {
1651  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1652  if ( point )
1653  return point->m();
1654  }
1655 
1656  return QVariant();
1657 }
1658 
1659 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1660 {
1661  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1662 
1663  if ( geom.isEmpty() )
1664  return QVariant();
1665 
1666  //idx is 1 based
1667  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1668 
1669  QgsVertexId vId;
1670  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1671  {
1672  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1673  return QVariant();
1674  }
1675 
1676  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1677  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1678 }
1679 
1680 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1681 {
1682  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1683 
1684  if ( geom.isEmpty() )
1685  return QVariant();
1686 
1687  QgsVertexId vId;
1688  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1689  {
1690  return QVariant();
1691  }
1692 
1693  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1694  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1695 }
1696 
1697 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1698 {
1699  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1700 
1701  if ( geom.isEmpty() )
1702  return QVariant();
1703 
1704  QgsVertexId vId;
1705  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1706  {
1707  return QVariant();
1708  }
1709 
1710  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1711  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1712 }
1713 
1714 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1715 {
1716  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1717 
1718  if ( geom.isEmpty() )
1719  return QVariant();
1720 
1721  bool ignoreClosing = false;
1722  if ( values.length() > 1 )
1723  {
1724  ignoreClosing = getIntValue( values.at( 1 ), parent );
1725  }
1726 
1727  QgsMultiPointV2* mp = new QgsMultiPointV2();
1728 
1729  Q_FOREACH ( const QgsRingSequenceV2 &part, geom.geometry()->coordinateSequence() )
1730  {
1731  Q_FOREACH ( const QgsPointSequenceV2 &ring, part )
1732  {
1733  bool skipLast = false;
1734  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1735  {
1736  skipLast = true;
1737  }
1738 
1739  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1740  {
1741  mp->addGeometry( ring.at( i ).clone() );
1742  }
1743  }
1744  }
1745 
1746  return QVariant::fromValue( QgsGeometry( mp ) );
1747 }
1748 
1749 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1750 {
1751  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1752 
1753  if ( geom.isEmpty() )
1754  return QVariant();
1755 
1757 
1758  //ok, now we have a complete list of segmentized lines from the geometry
1760  Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
1761  {
1762  for ( int i = 0; i < line->numPoints() - 1; ++i )
1763  {
1764  QgsLineStringV2* segment = new QgsLineStringV2();
1765  segment->setPoints( QgsPointSequenceV2()
1766  << line->pointN( i )
1767  << line->pointN( i + 1 ) );
1768  ml->addGeometry( segment );
1769  }
1770  delete line;
1771  }
1772 
1773  return QVariant::fromValue( QgsGeometry( ml ) );
1774 }
1775 
1776 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1777 {
1778  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1779 
1780  if ( geom.isEmpty() )
1781  return QVariant();
1782 
1783  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1784  if ( !curvePolygon )
1785  return QVariant();
1786 
1787  //idx is 1 based
1788  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1789 
1790  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1791  return QVariant();
1792 
1793  QgsCurveV2* curve = static_cast< QgsCurveV2* >( curvePolygon->interiorRing( idx )->clone() );
1794  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1795  return result;
1796 }
1797 
1798 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1799 {
1800  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1801 
1802  if ( geom.isEmpty() )
1803  return QVariant();
1804 
1805  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1806  if ( !collection )
1807  return QVariant();
1808 
1809  //idx is 1 based
1810  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1811 
1812  if ( idx < 0 || idx >= collection->numGeometries() )
1813  return QVariant();
1814 
1815  QgsAbstractGeometryV2* part = collection->geometryN( idx )->clone();
1816  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1817  return result;
1818 }
1819 
1820 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1821 {
1822  if ( values.count() < 2 || values.count() > 4 )
1823  {
1824  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1825  return QVariant();
1826  }
1827 
1828  double x = getDoubleValue( values.at( 0 ), parent );
1829  double y = getDoubleValue( values.at( 1 ), parent );
1830  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1831  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1832  switch ( values.count() )
1833  {
1834  case 2:
1835  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1836  case 3:
1837  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1838  case 4:
1839  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1840  }
1841  return QVariant(); //avoid warning
1842 }
1843 
1844 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1845 {
1846  double x = getDoubleValue( values.at( 0 ), parent );
1847  double y = getDoubleValue( values.at( 1 ), parent );
1848  double m = getDoubleValue( values.at( 2 ), parent );
1849  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
1850 }
1851 
1852 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1853 {
1854  if ( values.count() < 2 )
1855  {
1856  return QVariant();
1857  }
1858 
1859  QgsLineStringV2* lineString = new QgsLineStringV2();
1860  lineString->clear();
1861 
1862  Q_FOREACH ( const QVariant& value, values )
1863  {
1864  QgsGeometry geom = getGeometry( value, parent );
1865  if ( geom.isEmpty() )
1866  continue;
1867 
1868  if ( geom.type() != QGis::Point || geom.isMultipart() )
1869  continue;
1870 
1871  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1872  if ( !point )
1873  continue;
1874 
1875  lineString->addVertex( *point );
1876  }
1877 
1878  return QVariant::fromValue( QgsGeometry( lineString ) );
1879 }
1880 
1881 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1882 {
1883  if ( values.count() < 1 )
1884  {
1885  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
1886  return QVariant();
1887  }
1888 
1889  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
1890  if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
1891  return QVariant();
1892 
1893  QgsPolygonV2* polygon = new QgsPolygonV2();
1894  polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );
1895 
1896  for ( int i = 1; i < values.count(); ++i )
1897  {
1898  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
1899  if ( ringGeom.isEmpty() )
1900  continue;
1901 
1902  if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
1903  continue;
1904 
1905  polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
1906  }
1907 
1908  return QVariant::fromValue( QgsGeometry( polygon ) );
1909 }
1910 
1911 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1912 {
1913  FEAT_FROM_CONTEXT( context, f );
1914  int idx = getIntValue( values.at( 0 ), parent );
1915  const QgsGeometry* g = f.constGeometry();
1916  if ( !g || g->isEmpty() )
1917  return QVariant();
1918 
1919  if ( idx < 0 )
1920  {
1921  idx += g->geometry()->nCoordinates();
1922  }
1923  if ( idx < 0 || idx >= g->geometry()->nCoordinates() )
1924  {
1925  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1926  return QVariant();
1927  }
1928 
1929  QgsPoint p = g->vertexAt( idx );
1930  return QVariant( QPointF( p.x(), p.y() ) );
1931 }
1932 
1933 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1934 {
1935  QVariant v = pointAt( values, f, parent );
1936  if ( v.type() == QVariant::PointF )
1937  return QVariant( v.toPointF().x() );
1938  else
1939  return QVariant();
1940 }
1941 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1942 {
1943  QVariant v = pointAt( values, f, parent );
1944  if ( v.type() == QVariant::PointF )
1945  return QVariant( v.toPointF().y() );
1946  else
1947  return QVariant();
1948 }
1949 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1950 {
1951  FEAT_FROM_CONTEXT( context, f );
1952  const QgsGeometry* geom = f.constGeometry();
1953  if ( geom )
1954  return QVariant::fromValue( *geom );
1955  else
1956  return QVariant();
1957 }
1958 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1959 {
1960  QString wkt = getStringValue( values.at( 0 ), parent );
1961  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1962  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1963  delete geom;
1964  return result;
1965 }
1966 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1967 {
1968  QString gml = getStringValue( values.at( 0 ), parent );
1970  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1971  delete geom;
1972  return result;
1973 }
1974 
1975 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1976 {
1977  FEAT_FROM_CONTEXT( context, f );
1979  QgsDistanceArea* calc = parent->geomCalculator();
1980  if ( calc )
1981  {
1982  double area = calc->measureArea( f.constGeometry() );
1983  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
1984  return QVariant( area );
1985  }
1986  else
1987  {
1988  return QVariant( f.constGeometry()->area() );
1989  }
1990 }
1991 
1992 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1993 {
1994  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1995 
1996  if ( geom.type() != QGis::Polygon )
1997  return QVariant();
1998 
1999  return QVariant( geom.area() );
2000 }
2001 
2002 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2003 {
2004  FEAT_FROM_CONTEXT( context, f );
2005  ENSURE_GEOM_TYPE( f, g, QGis::Line );
2006  QgsDistanceArea* calc = parent->geomCalculator();
2007  if ( calc )
2008  {
2009  double len = calc->measureLength( f.constGeometry() );
2010  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2011  return QVariant( len );
2012  }
2013  else
2014  {
2015  return QVariant( f.constGeometry()->length() );
2016  }
2017 }
2018 
2019 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2020 {
2021  FEAT_FROM_CONTEXT( context, f );
2023  QgsDistanceArea* calc = parent->geomCalculator();
2024  if ( calc )
2025  {
2026  double len = calc->measurePerimeter( f.constGeometry() );
2027  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2028  return QVariant( len );
2029  }
2030  else
2031  {
2032  return f.constGeometry()->isEmpty() ? QVariant( 0 ) : QVariant( f.constGeometry()->geometry()->perimeter() );
2033  }
2034 }
2035 
2036 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2037 {
2038  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2039 
2040  if ( geom.type() != QGis::Polygon )
2041  return QVariant();
2042 
2043  //length for polygons = perimeter
2044  return QVariant( geom.length() );
2045 }
2046 
2047 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2048 {
2049  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2050  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
2051 }
2052 
2053 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2054 {
2055  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2056  if ( geom.isEmpty() )
2057  return QVariant();
2058 
2059  return QVariant( geom.geometry()->partCount() );
2060 }
2061 
2062 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2063 {
2064  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2065 
2066  if ( geom.isEmpty() )
2067  return QVariant();
2068 
2069  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2070  if ( curvePolygon )
2071  return QVariant( curvePolygon->numInteriorRings() );
2072 
2073  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2074  if ( collection )
2075  {
2076  //find first CurvePolygon in collection
2077  for ( int i = 0; i < collection->numGeometries(); ++i )
2078  {
2079  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2080  if ( !curvePolygon )
2081  continue;
2082 
2083  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2084  }
2085  }
2086 
2087  return QVariant();
2088 }
2089 
2090 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2091 {
2092  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2093 
2094  if ( geom.isEmpty() )
2095  return QVariant();
2096 
2097  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2098  if ( curvePolygon )
2099  return QVariant( curvePolygon->ringCount() );
2100 
2101  bool foundPoly = false;
2102  int ringCount = 0;
2103  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2104  if ( collection )
2105  {
2106  //find CurvePolygons in collection
2107  for ( int i = 0; i < collection->numGeometries(); ++i )
2108  {
2109  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2110  if ( !curvePolygon )
2111  continue;
2112 
2113  foundPoly = true;
2114  ringCount += curvePolygon->ringCount();
2115  }
2116  }
2117 
2118  if ( !foundPoly )
2119  return QVariant();
2120 
2121  return QVariant( ringCount );
2122 }
2123 
2124 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2125 {
2126  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2127  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2128  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
2129  delete geomBounds;
2130  return result;
2131 }
2132 
2133 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2134 {
2135  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2136  return QVariant::fromValue( geom.boundingBox().width() );
2137 }
2138 
2139 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2140 {
2141  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2142  return QVariant::fromValue( geom.boundingBox().height() );
2143 }
2144 
2145 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2146 {
2147  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2148  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2149 }
2150 
2151 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2152 {
2153  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2154  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2155 }
2156 
2157 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2158 {
2159  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2160  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2161 }
2162 
2163 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2164 {
2165  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2166  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2167 }
2168 
2169 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2170 {
2171  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2172  if ( fGeom.isEmpty() )
2173  return QVariant();
2174 
2175  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2176  if ( !curve )
2177  return QVariant();
2178 
2179  return QVariant::fromValue( curve->isClosed() );
2180 }
2181 
2182 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2183 {
2184  if ( values.length() < 2 || values.length() > 3 )
2185  return QVariant();
2186 
2187  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2188  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2189 
2190  if ( fGeom.isEmpty() || sGeom.isEmpty() )
2191  return QVariant();
2192 
2194 
2195  if ( values.length() == 2 )
2196  {
2197  //two geometry arguments, return relation
2198  QString result = engine->relate( *sGeom.geometry() );
2199  return QVariant::fromValue( result );
2200  }
2201  else
2202  {
2203  //three arguments, test pattern
2204  QString pattern = getStringValue( values.at( 2 ), parent );
2205  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2206  return QVariant::fromValue( result );
2207  }
2208 }
2209 
2210 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2211 {
2212  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2213  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2214  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2215 }
2216 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2217 {
2218  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2219  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2220  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
2221 }
2222 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2223 {
2224  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2225  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2226  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
2227 }
2228 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2229 {
2230  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2231  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2232  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
2233 }
2234 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2235 {
2236  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2237  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2238  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
2239 }
2240 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2241 {
2242  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2243  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2244  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
2245 }
2246 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2247 {
2248  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2249  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2250  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
2251 }
2252 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2253 {
2254  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2255  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2256  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
2257 }
2258 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2259 {
2260  if ( values.length() < 2 || values.length() > 3 )
2261  return QVariant();
2262 
2263  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2264  double dist = getDoubleValue( values.at( 1 ), parent );
2265  int seg = 8;
2266  if ( values.length() == 3 )
2267  seg = getIntValue( values.at( 2 ), parent );
2268 
2269  QgsGeometry* geom = fGeom.buffer( dist, seg );
2270  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2271  delete geom;
2272  return result;
2273 }
2274 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2275 {
2276  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2277  double dx = getDoubleValue( values.at( 1 ), parent );
2278  double dy = getDoubleValue( values.at( 2 ), parent );
2279  fGeom.translate( dx, dy );
2280  return QVariant::fromValue( fGeom );
2281 }
2282 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2283 {
2284  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2285  QgsGeometry* geom = fGeom.centroid();
2286  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2287  delete geom;
2288  return result;
2289 }
2290 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2291 {
2292  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2293  QgsGeometry* geom = fGeom.pointOnSurface();
2294  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2295  delete geom;
2296  return result;
2297 }
2298 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2299 {
2300  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2301  QgsGeometry* geom = fGeom.convexHull();
2302  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2303  delete geom;
2304  return result;
2305 }
2306 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2307 {
2308  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2309  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2310  QgsGeometry* geom = fGeom.difference( &sGeom );
2311  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2312  delete geom;
2313  return result;
2314 }
2315 
2316 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2317 {
2318  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2319  if ( fGeom.isEmpty() )
2320  return QVariant();
2321 
2322  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2323  if ( !curve )
2324  return QVariant();
2325 
2326  QgsCurveV2* reversed = curve->reversed();
2327  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2328  return result;
2329 }
2330 
2331 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2332 {
2333  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2334  if ( fGeom.isEmpty() )
2335  return QVariant();
2336 
2337  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( fGeom.geometry() );
2338  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2339  return QVariant();
2340 
2341  QgsCurveV2* exterior = static_cast< QgsCurveV2* >( curvePolygon->exteriorRing()->clone() );
2342  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2343  return result;
2344 }
2345 
2346 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2347 {
2348  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2349  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2350  return QVariant( fGeom.distance( sGeom ) );
2351 }
2352 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2353 {
2354  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2355  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2356  QgsGeometry* geom = fGeom.intersection( &sGeom );
2357  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2358  delete geom;
2359  return result;
2360 }
2361 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2362 {
2363  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2364  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2365  QgsGeometry* geom = fGeom.symDifference( &sGeom );
2366  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2367  delete geom;
2368  return result;
2369 }
2370 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2371 {
2372  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2373  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2374  QgsGeometry* geom = fGeom.combine( &sGeom );
2375  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2376  delete geom;
2377  return result;
2378 }
2379 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2380 {
2381  if ( values.length() < 1 || values.length() > 2 )
2382  return QVariant();
2383 
2384  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2385  int prec = 8;
2386  if ( values.length() == 2 )
2387  prec = getIntValue( values.at( 1 ), parent );
2388  QString wkt = fGeom.exportToWkt( prec );
2389  return QVariant( wkt );
2390 }
2391 
2392 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2393 {
2394  if ( values.length() != 2 )
2395  {
2396  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2397  return QVariant();
2398  }
2399 
2400  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2401  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2402 
2403  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2404  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2405 
2406  if ( !pt1 || !pt2 )
2407  {
2408  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2409  return QVariant();
2410  }
2411 
2412  // Code from postgis
2413  if ( pt1->x() == pt2->x() )
2414  {
2415  if ( pt1->y() < pt2->y() )
2416  return 0.0;
2417  else if ( pt1->y() > pt2->y() )
2418  return M_PI;
2419  else
2420  return 0;
2421  }
2422 
2423  if ( pt1->y() == pt2->y() )
2424  {
2425  if ( pt1->x() < pt2->x() )
2426  return M_PI / 2;
2427  else if ( pt1->x() > pt2->x() )
2428  return M_PI + ( M_PI / 2 );
2429  else
2430  return 0;
2431  }
2432 
2433  if ( pt1->x() < pt2->x() )
2434  {
2435  if ( pt1->y() < pt2->y() )
2436  {
2437  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2438  }
2439  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2440  {
2441  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2442  + ( M_PI / 2 );
2443  }
2444  }
2445 
2446  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2447  {
2448  if ( pt1->y() > pt2->y() )
2449  {
2450  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2451  + M_PI;
2452  }
2453  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2454  {
2455  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2456  + ( M_PI + ( M_PI / 2 ) );
2457  }
2458  }
2459 }
2460 
2461 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2462 {
2463  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2464 
2465  if ( geom.type() != QGis::Point )
2466  {
2467  parent->setEvalErrorString( "'project' requires a point geometry" );
2468  return QVariant();
2469  }
2470 
2471  double distance = getDoubleValue( values.at( 1 ), parent );
2472  double bearing = getDoubleValue( values.at( 2 ), parent );
2473 
2474  QgsPoint p = geom.asPoint();
2475  QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );
2476 
2477  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
2478 }
2479 
2480 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2481 {
2482  if ( values.length() != 3 )
2483  return QVariant();
2484 
2485  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2486  double x = getDoubleValue( values.at( 1 ), parent );
2487  double y = getDoubleValue( values.at( 2 ), parent );
2488 
2489  QgsGeometry geom = fGeom.extrude( x, y );
2490 
2491  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2492  return result;
2493 }
2494 
2495 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2496 {
2497  if ( values.length() < 2 )
2498  return QVariant();
2499 
2500  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2501 
2502  if ( !fGeom.isMultipart() )
2503  return values.at( 0 );
2504 
2505  QString expString = getStringValue( values.at( 1 ), parent );
2506  bool asc = values.value( 2 ).toBool();
2507 
2508  QgsExpressionContext* unconstedContext;
2509  QgsFeature f;
2510  if ( ctx )
2511  {
2512  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2513  // so no reason to worry
2514  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2515  f = ctx->feature();
2516  }
2517  else
2518  {
2519  // If there's no context provided, create a fake one
2520  unconstedContext = new QgsExpressionContext();
2521  }
2522 
2523  QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
2524  Q_ASSERT( collection ); // Should have failed the multipart check above
2525 
2527  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2528  QgsExpressionSorter sorter( orderBy );
2529 
2530  QList<QgsFeature> partFeatures;
2531  for ( int i = 0; i < collection->partCount(); ++i )
2532  {
2533  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2534  partFeatures << f;
2535  }
2536 
2537  sorter.sortFeatures( partFeatures, unconstedContext );
2538 
2539  QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );
2540 
2541  Q_ASSERT( orderedGeom );
2542 
2543  while ( orderedGeom->partCount() )
2544  orderedGeom->removeGeometry( 0 );
2545 
2546  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2547  {
2548  orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
2549  }
2550 
2551  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2552 
2553  if ( !ctx )
2554  delete unconstedContext;
2555 
2556  return result;
2557 }
2558 
2559 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2560 {
2561  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2562  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2563 
2564  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2565 
2566  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2567  return result;
2568 }
2569 
2570 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2571 {
2572  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2573  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2574 
2575  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2576 
2577  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2578  return result;
2579 }
2580 
2581 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2582 {
2583  if ( values.length() == 2 )
2584  {
2585  double number = getDoubleValue( values.at( 0 ), parent );
2586  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2587  return QVariant( qRound( number * scaler ) / scaler );
2588  }
2589 
2590  if ( values.length() == 1 )
2591  {
2592  double number = getIntValue( values.at( 0 ), parent );
2593  return QVariant( qRound( number ) ).toInt();
2594  }
2595 
2596  return QVariant();
2597 }
2598 
2599 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2600 {
2601  Q_UNUSED( values );
2602  Q_UNUSED( parent );
2603  return M_PI;
2604 }
2605 
2606 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
2607 {
2608  return QVariant( parent->scale() );
2609 }
2610 
2611 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2612 {
2613  double value = getDoubleValue( values.at( 0 ), parent );
2614  int places = getIntValue( values.at( 1 ), parent );
2615  if ( places < 0 )
2616  {
2617  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2618  return QVariant();
2619  }
2620  return QString( "%L1" ).arg( value, 0, 'f', places );
2621 }
2622 
2623 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2624 {
2625  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2626  QString format = getStringValue( values.at( 1 ), parent );
2627  return dt.toString( format );
2628 }
2629 
2630 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2631 {
2632  int red = getIntValue( values.at( 0 ), parent );
2633  int green = getIntValue( values.at( 1 ), parent );
2634  int blue = getIntValue( values.at( 2 ), parent );
2635  QColor color = QColor( red, green, blue );
2636  if ( ! color.isValid() )
2637  {
2638  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2639  color = QColor( 0, 0, 0 );
2640  }
2641 
2642  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2643 }
2644 
2645 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2646 {
2647  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2649  QVariant value = node->eval( parent, context );
2651  if ( value.toBool() )
2652  {
2653  node = getNode( values.at( 1 ), parent );
2655  value = node->eval( parent, context );
2657  }
2658  else
2659  {
2660  node = getNode( values.at( 2 ), parent );
2662  value = node->eval( parent, context );
2664  }
2665  return value;
2666 }
2667 
2668 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2669 {
2670  int red = getIntValue( values.at( 0 ), parent );
2671  int green = getIntValue( values.at( 1 ), parent );
2672  int blue = getIntValue( values.at( 2 ), parent );
2673  int alpha = getIntValue( values.at( 3 ), parent );
2674  QColor color = QColor( red, green, blue, alpha );
2675  if ( ! color.isValid() )
2676  {
2677  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
2678  color = QColor( 0, 0, 0 );
2679  }
2680  return QgsSymbolLayerV2Utils::encodeColor( color );
2681 }
2682 
2683 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2684 {
2685  QString rampName = getStringValue( values.at( 0 ), parent );
2686  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
2687  if ( ! mRamp )
2688  {
2689  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2690  return QColor( 0, 0, 0 ).name();
2691  }
2692  double value = getDoubleValue( values.at( 1 ), parent );
2693  QColor color = mRamp->color( value );
2694  return QgsSymbolLayerV2Utils::encodeColor( color );
2695 }
2696 
2697 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2698 {
2699  // Hue ranges from 0 - 360
2700  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2701  // Saturation ranges from 0 - 100
2702  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2703  // Lightness ranges from 0 - 100
2704  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2705 
2706  QColor color = QColor::fromHslF( hue, saturation, lightness );
2707 
2708  if ( ! color.isValid() )
2709  {
2710  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
2711  color = QColor( 0, 0, 0 );
2712  }
2713 
2714  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2715 }
2716 
2717 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2718 {
2719  // Hue ranges from 0 - 360
2720  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2721  // Saturation ranges from 0 - 100
2722  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2723  // Lightness ranges from 0 - 100
2724  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2725  // Alpha ranges from 0 - 255
2726  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2727 
2728  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
2729  if ( ! color.isValid() )
2730  {
2731  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
2732  color = QColor( 0, 0, 0 );
2733  }
2734  return QgsSymbolLayerV2Utils::encodeColor( color );
2735 }
2736 
2737 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2738 {
2739  // Hue ranges from 0 - 360
2740  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2741  // Saturation ranges from 0 - 100
2742  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2743  // Value ranges from 0 - 100
2744  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2745 
2746  QColor color = QColor::fromHsvF( hue, saturation, value );
2747 
2748  if ( ! color.isValid() )
2749  {
2750  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
2751  color = QColor( 0, 0, 0 );
2752  }
2753 
2754  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2755 }
2756 
2757 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2758 {
2759  // Hue ranges from 0 - 360
2760  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2761  // Saturation ranges from 0 - 100
2762  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2763  // Value ranges from 0 - 100
2764  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2765  // Alpha ranges from 0 - 255
2766  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2767 
2768  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
2769  if ( ! color.isValid() )
2770  {
2771  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
2772  color = QColor( 0, 0, 0 );
2773  }
2774  return QgsSymbolLayerV2Utils::encodeColor( color );
2775 }
2776 
2777 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2778 {
2779  // Cyan ranges from 0 - 100
2780  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2781  // Magenta ranges from 0 - 100
2782  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2783  // Yellow ranges from 0 - 100
2784  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2785  // Black ranges from 0 - 100
2786  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2787 
2788  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
2789 
2790  if ( ! color.isValid() )
2791  {
2792  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
2793  color = QColor( 0, 0, 0 );
2794  }
2795 
2796  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2797 }
2798 
2799 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2800 {
2801  // Cyan ranges from 0 - 100
2802  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2803  // Magenta ranges from 0 - 100
2804  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2805  // Yellow ranges from 0 - 100
2806  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2807  // Black ranges from 0 - 100
2808  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2809  // Alpha ranges from 0 - 255
2810  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
2811 
2812  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
2813  if ( ! color.isValid() )
2814  {
2815  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
2816  color = QColor( 0, 0, 0 );
2817  }
2818  return QgsSymbolLayerV2Utils::encodeColor( color );
2819 }
2820 
2821 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2822 {
2823  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2824  if ( ! color.isValid() )
2825  {
2826  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2827  return QVariant();
2828  }
2829 
2830  QString part = getStringValue( values.at( 1 ), parent );
2831  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2832  return color.red();
2833  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2834  return color.green();
2835  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2836  return color.blue();
2837  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2838  return color.alpha();
2839  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2840  return color.hsvHueF() * 360;
2841  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2842  return color.hsvSaturationF() * 100;
2843  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2844  return color.valueF() * 100;
2845  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2846  return color.hslHueF() * 360;
2847  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2848  return color.hslSaturationF() * 100;
2849  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2850  return color.lightnessF() * 100;
2851  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2852  return color.cyanF() * 100;
2853  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2854  return color.magentaF() * 100;
2855  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2856  return color.yellowF() * 100;
2857  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2858  return color.blackF() * 100;
2859 
2860  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2861  return QVariant();
2862 }
2863 
2864 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2865 {
2866  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2867  if ( ! color.isValid() )
2868  {
2869  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2870  return QVariant();
2871  }
2872 
2873  QString part = getStringValue( values.at( 1 ), parent );
2874  int value = getIntValue( values.at( 2 ), parent );
2875  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2876  color.setRed( value );
2877  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2878  color.setGreen( value );
2879  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2880  color.setBlue( value );
2881  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2882  color.setAlpha( value );
2883  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2884  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
2885  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2886  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
2887  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2888  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
2889  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2890  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
2891  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2892  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
2893  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2894  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
2895  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2896  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
2897  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2898  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
2899  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2900  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
2901  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2902  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
2903  else
2904  {
2905  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2906  return QVariant();
2907  }
2908  return QgsSymbolLayerV2Utils::encodeColor( color );
2909 }
2910 
2911 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2912 {
2913  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2914  if ( ! color.isValid() )
2915  {
2916  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2917  return QVariant();
2918  }
2919 
2920  color = color.darker( getIntValue( values.at( 1 ), parent ) );
2921 
2922  return QgsSymbolLayerV2Utils::encodeColor( color );
2923 }
2924 
2925 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2926 {
2927  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2928  if ( ! color.isValid() )
2929  {
2930  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2931  return QVariant();
2932  }
2933 
2934  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
2935 
2936  return QgsSymbolLayerV2Utils::encodeColor( color );
2937 }
2938 
2939 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2940 {
2941  QString varName = getStringValue( values.at( 0 ), parent );
2943  return QgsExpression::specialColumn( varName );
2945 }
2946 
2947 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2948 {
2949  QgsFeature feat = getFeature( values.at( 0 ), parent );
2950  const QgsGeometry* geom = feat.constGeometry();
2951  if ( geom )
2952  return QVariant::fromValue( *geom );
2953  return QVariant();
2954 }
2955 
2956 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2957 {
2958  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2959  QString sAuthId = getStringValue( values.at( 1 ), parent );
2960  QString dAuthId = getStringValue( values.at( 2 ), parent );
2961 
2963  if ( ! s.createFromOgcWmsCrs( sAuthId ) )
2964  return QVariant::fromValue( fGeom );
2966  if ( ! d.createFromOgcWmsCrs( dAuthId ) )
2967  return QVariant::fromValue( fGeom );
2968 
2969  QgsCoordinateTransform t( s, d );
2970  if ( fGeom.transform( t ) == 0 )
2971  return QVariant::fromValue( fGeom );
2972  return QVariant();
2973 }
2974 
2975 
2976 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2977 {
2978  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
2979  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
2980 
2981  //no layer found
2982  if ( !vl )
2983  {
2984  return QVariant();
2985  }
2986 
2987  QString attribute = getStringValue( values.at( 1 ), parent );
2988  int attributeId = vl->fieldNameIndex( attribute );
2989  if ( attributeId == -1 )
2990  {
2991  return QVariant();
2992  }
2993 
2994  const QVariant& attVal = values.at( 2 );
2995  QgsFeatureRequest req;
2996  req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
2997  QgsExpression::quotedString( attVal.toString() ) ) );
2998  req.setLimit( 1 );
2999  if ( !parent->needsGeometry() )
3000  {
3002  }
3003  QgsFeatureIterator fIt = vl->getFeatures( req );
3004 
3005  QgsFeature fet;
3006  if ( fIt.nextFeature( fet ) )
3007  return QVariant::fromValue( fet );
3008 
3009  return QVariant();
3010 }
3011 
3012 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3013 {
3014  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3015 
3016  //try to find a matching layer by name
3017  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3018  if ( !layer )
3019  {
3020  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3021  if ( !layersByName.isEmpty() )
3022  {
3023  layer = layersByName.at( 0 );
3024  }
3025  }
3026 
3027  if ( !layer )
3028  return QVariant();
3029 
3030  QString layerProperty = getStringValue( values.at( 1 ), parent );
3031  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
3032  return layer->name();
3033  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
3034  return layer->id();
3035  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
3036  return layer->title();
3037  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
3038  return layer->abstract();
3039  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
3040  return layer->keywordList();
3041  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
3042  return layer->dataUrl();
3043  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
3044  return layer->attribution();
3045  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3046  return layer->attributionUrl();
3047  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
3048  return layer->publicSource();
3049  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3050  return layer->minimumScale();
3051  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3052  return layer->maximumScale();
3053  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
3054  return layer->crs().authid();
3055  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3056  return layer->crs().toProj4();
3057  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
3058  {
3059  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
3060  QVariant result = QVariant::fromValue( *extentGeom );
3061  delete extentGeom;
3062  return result;
3063  }
3064  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
3065  {
3066  switch ( layer->type() )
3067  {
3069  return QCoreApplication::translate( "expressions", "Vector" );
3071  return QCoreApplication::translate( "expressions", "Raster" );
3073  return QCoreApplication::translate( "expressions", "Plugin" );
3074  }
3075  }
3076  else
3077  {
3078  //vector layer methods
3079  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3080  if ( vLayer )
3081  {
3082  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3083  return vLayer->storageType();
3084  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3085  return QGis::vectorGeometryType( vLayer->geometryType() );
3086  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3087  return QVariant::fromValue( vLayer->featureCount() );
3088  }
3089  }
3090 
3091  return QVariant();
3092 }
3093 
3094 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3095 {
3096  int fnIdx = functionIndex( function->name() );
3097  if ( fnIdx != -1 )
3098  {
3099  return false;
3100  }
3101  QgsExpression::gmFunctions.append( function );
3102  if ( transferOwnership )
3103  QgsExpression::gmOwnedFunctions.append( function );
3104  return true;
3105 }
3106 
3108 {
3109  // You can never override the built in functions.
3110  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3111  {
3112  return false;
3113  }
3114  int fnIdx = functionIndex( name );
3115  if ( fnIdx != -1 )
3116  {
3117  QgsExpression::gmFunctions.removeAt( fnIdx );
3118  return true;
3119  }
3120  return false;
3121 }
3122 
3124 {
3125  qDeleteAll( QgsExpression::gmOwnedFunctions );
3127 }
3128 
3130 
3132 {
3133  if ( gmBuiltinFunctions.isEmpty() )
3134  {
3136  << "abs" << "sqrt" << "cos" << "sin" << "tan"
3137  << "asin" << "acos" << "atan" << "atan2"
3138  << "exp" << "ln" << "log10" << "log"
3139  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
3140  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
3141  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
3142  << "todatetime" << "to_datetime" << "todate" << "to_date"
3143  << "totime" << "to_time" << "tointerval" << "to_interval"
3144  << "coalesce" << "if" << "regexp_match" << "age" << "year"
3145  << "month" << "week" << "day" << "hour" << "day_of_week"
3146  << "minute" << "second" << "lower" << "upper"
3147  << "title" << "length" << "replace" << "trim" << "wordwrap"
3148  << "regexp_replace" << "regexp_substr"
3149  << "substr" << "concat" << "strpos" << "left"
3150  << "right" << "rpad" << "lpad" << "format"
3151  << "format_number" << "format_date"
3152  << "color_rgb" << "color_rgba" << "ramp_color"
3153  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
3154  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
3155  << "xat" << "yat" << "$area" << "area" << "perimeter"
3156  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
3157  << "num_interior_rings" << "num_rings" << "num_geometries"
3158  << "geometry_n" << "interior_ring_n"
3159  << "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
3160  << "nodes_to_points" << "segments_to_lines"
3161  << "make_line" << "make_polygon"
3162  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
3163  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
3164  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
3165  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
3166  << "relate"
3167  << "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
3168  << "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
3169  << "distance" << "intersection" << "sym_difference" << "combine"
3170  << "extrude" << "azimuth" << "project" << "closest_point" << "shortest_line"
3171  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
3172  << "transform" << "get_feature" << "getFeature"
3173  << "levenshtein" << "longest_common_substring" << "hamming_distance"
3174  << "soundex"
3175  << "aggregate" << "relation_aggregate" << "count" << "count_distinct"
3176  << "count_missing" << "minimum" << "maximum" << "sum" << "mean"
3177  << "median" << "stdev" << "range" << "minority" << "majority"
3178  << "q1" << "q3" << "iqr" << "min_length" << "max_length" << "concatenate"
3179  << "attribute" << "var" << "layer_property"
3180  << "$id" << "$scale" << "_specialcol_";
3181  }
3182  return gmBuiltinFunctions;
3183 }
3184 
3187 
3189 {
3190  // The construction of the list isn't thread-safe, and without the mutex,
3191  // crashes in the WFS provider may occur, since it can parse expressions
3192  // in parallel.
3193  // The mutex needs to be recursive.
3194  static QMutex sFunctionsMutex( QMutex::Recursive );
3195  QMutexLocker locker( &sFunctionsMutex );
3196 
3197  if ( gmFunctions.isEmpty() )
3198  {
3199  ParameterList aggParams = ParameterList() << Parameter( "expression" )
3200  << Parameter( "group_by", true )
3201  << Parameter( "filter", true );
3202 
3203  gmFunctions
3204  << new StaticFunction( "sqrt", ParameterList() << Parameter( "value" ), fcnSqrt, "Math" )
3205  << new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
3206  << new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
3207  << new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, "Math" )
3208  << new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
3209  << new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
3210  << new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
3211  << new StaticFunction( "sin", ParameterList() << Parameter( "angle" ), fcnSin, "Math" )
3212  << new StaticFunction( "tan", ParameterList() << Parameter( "angle" ), fcnTan, "Math" )
3213  << new StaticFunction( "asin", ParameterList() << Parameter( "value" ), fcnAsin, "Math" )
3214  << new StaticFunction( "acos", ParameterList() << Parameter( "value" ), fcnAcos, "Math" )
3215  << new StaticFunction( "atan", ParameterList() << Parameter( "value" ), fcnAtan, "Math" )
3216  << new StaticFunction( "atan2", ParameterList() << Parameter( "dx" ) << Parameter( "dy" ), fcnAtan2, "Math" )
3217  << new StaticFunction( "exp", ParameterList() << Parameter( "value" ), fcnExp, "Math" )
3218  << new StaticFunction( "ln", ParameterList() << Parameter( "value" ), fcnLn, "Math" )
3219  << new StaticFunction( "log10", ParameterList() << Parameter( "value" ), fcnLog10, "Math" )
3220  << new StaticFunction( "log", ParameterList() << Parameter( "base" ) << Parameter( "value" ), fcnLog, "Math" )
3221  << new StaticFunction( "round", ParameterList() << Parameter( "value" ) << Parameter( "places", true, 0 ), fcnRound, "Math" )
3222  << new StaticFunction( "rand", ParameterList() << Parameter( "min" ) << Parameter( "max" ), fcnRnd, "Math" )
3223  << new StaticFunction( "randf", ParameterList() << Parameter( "min", true, 0.0 ) << Parameter( "max", true, 1.0 ), fcnRndF, "Math" )
3224  << new StaticFunction( "max", -1, fcnMax, "Math" )
3225  << new StaticFunction( "min", -1, fcnMin, "Math" )
3226  << new StaticFunction( "clamp", ParameterList() << Parameter( "min" ) << Parameter( "value" ) << Parameter( "max" ), fcnClamp, "Math" )
3227  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
3228  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
3229  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
3230  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
3231  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
3232  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
3233  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
3234  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
3235  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
3236  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
3237  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
3238  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
3239  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
3240  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
3241  << new StaticFunction( "aggregate", ParameterList() << Parameter( "layer" ) << Parameter( "aggregate" ) << Parameter( "expression" )
3242  << Parameter( "filter", true ) << Parameter( "concatenator", true ), fcnAggregate, "Aggregates", QString(), False, QStringList(), true )
3243  << new StaticFunction( "relation_aggregate", ParameterList() << Parameter( "relation" ) << Parameter( "aggregate" ) << Parameter( "expression" ) << Parameter( "concatenator", true ),
3245 
3246  << new StaticFunction( "count", aggParams, fcnAggregateCount, "Aggregates", QString(), False, QStringList(), true )
3247  << new StaticFunction( "count_distinct", aggParams, fcnAggregateCountDistinct, "Aggregates", QString(), False, QStringList(), true )
3248  << new StaticFunction( "count_missing", aggParams, fcnAggregateCountMissing, "Aggregates", QString(), False, QStringList(), true )
3249  << new StaticFunction( "minimum", aggParams, fcnAggregateMin, "Aggregates", QString(), False, QStringList(), true )
3250  << new StaticFunction( "maximum", aggParams, fcnAggregateMax, "Aggregates", QString(), False, QStringList(), true )
3251  << new StaticFunction( "sum", aggParams, fcnAggregateSum, "Aggregates", QString(), False, QStringList(), true )
3252  << new StaticFunction( "mean", aggParams, fcnAggregateMean, "Aggregates", QString(), False, QStringList(), true )
3253  << new StaticFunction( "median", aggParams, fcnAggregateMedian, "Aggregates", QString(), False, QStringList(), true )
3254  << new StaticFunction( "stdev", aggParams, fcnAggregateStdev, "Aggregates", QString(), False, QStringList(), true )
3255  << new StaticFunction( "range", aggParams, fcnAggregateRange, "Aggregates", QString(), False, QStringList(), true )
3256  << new StaticFunction( "minority", aggParams, fcnAggregateMinority, "Aggregates", QString(), False, QStringList(), true )
3257  << new StaticFunction( "majority", aggParams, fcnAggregateMajority, "Aggregates", QString(), False, QStringList(), true )
3258  << new StaticFunction( "q1", aggParams, fcnAggregateQ1, "Aggregates", QString(), False, QStringList(), true )
3259  << new StaticFunction( "q3", aggParams, fcnAggregateQ3, "Aggregates", QString(), False, QStringList(), true )
3260  << new StaticFunction( "iqr", aggParams, fcnAggregateIQR, "Aggregates", QString(), False, QStringList(), true )
3261  << new StaticFunction( "min_length", aggParams, fcnAggregateMinLength, "Aggregates", QString(), False, QStringList(), true )
3262  << new StaticFunction( "max_length", aggParams, fcnAggregateMaxLength, "Aggregates", QString(), False, QStringList(), true )
3263  << new StaticFunction( "concatenate", aggParams << Parameter( "concatenator", true ), fcnAggregateStringConcat, "Aggregates", QString(), False, QStringList(), true )
3264 
3265  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
3266  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
3267  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
3268  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
3269  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
3270  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
3271  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
3272  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
3273  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
3274  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
3275  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
3276  << new StaticFunction( "lower", 1, fcnLower, "String" )
3277  << new StaticFunction( "upper", 1, fcnUpper, "String" )
3278  << new StaticFunction( "title", 1, fcnTitle, "String" )
3279  << new StaticFunction( "trim", 1, fcnTrim, "String" )
3280  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
3281  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
3282  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
3283  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
3284  << new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, " " ), fcnWordwrap, "String" )
3285  << new StaticFunction( "length", 1, fcnLength, "String" )
3286  << new StaticFunction( "replace", 3, fcnReplace, "String" )
3287  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
3288  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
3289  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
3290  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
3291  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
3292  << new StaticFunction( "left", 2, fcnLeft, "String" )
3293  << new StaticFunction( "right", 2, fcnRight, "String" )
3294  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
3295  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
3296  << new StaticFunction( "format", -1, fcnFormatString, "String" )
3297  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
3298  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
3299  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
3300  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
3301  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
3302  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
3303  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
3304  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
3305  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
3306  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
3307  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
3308  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
3309  << new StaticFunction( "darker", 2, fncDarker, "Color" )
3310  << new StaticFunction( "lighter", 2, fncLighter, "Color" )
3311  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
3312  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
3313  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
3314  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
3315  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
3316  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
3317  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
3318  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
3319  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
3320  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
3321  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
3322  << new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
3323  << new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
3324  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
3325  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
3326  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
3327  << new StaticFunction( "nodes_to_points", -1, fcnNodesToPoints, "GeometryGroup" )
3328  << new StaticFunction( "segments_to_lines", 1, fcnSegmentsToLines, "GeometryGroup" )
3329  << new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
3330  << new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
3331  << new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
3332  << new StaticFunction( "make_polygon", -1, fcnMakePolygon, "GeometryGroup" )
3333  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
3334  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
3335  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
3336  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
3337  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
3338  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
3339  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
3340  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
3341  << new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
3342  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
3343  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
3344  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
3345  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
3346  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
3347  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
3348  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
3349  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
3350  << new StaticFunction( "translate", 3, fcnTranslate, "GeometryGroup" )
3351  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
3352  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
3353  << new StaticFunction( "point_on_surface", 1, fcnPointOnSurface, "GeometryGroup" )
3354  << new StaticFunction( "reverse", 1, fcnReverse, "GeometryGroup" )
3355  << new StaticFunction( "exterior_ring", 1, fcnExteriorRing, "GeometryGroup" )
3356  << new StaticFunction( "interior_ring_n", 2, fcnInteriorRingN, "GeometryGroup" )
3357  << new StaticFunction( "geometry_n", 2, fcnGeometryN, "GeometryGroup" )
3358  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
3359  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
3360  << new StaticFunction( "num_interior_rings", 1, fcnGeomNumInteriorRings, "GeometryGroup" )
3361  << new StaticFunction( "num_rings", 1, fcnGeomNumRings, "GeometryGroup" )
3362  << new StaticFunction( "num_geometries", 1, fcnGeomNumGeometries, "GeometryGroup" )
3363  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
3364  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
3365  << new StaticFunction( "is_closed", 1, fcnIsClosed, "GeometryGroup" )
3366  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
3367  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
3368  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
3369  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
3370  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
3371  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
3372  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
3373  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
3374  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
3375  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
3376  << new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
3377  << new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
3378  << new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
3379  << new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
3380  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
3381  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
3382  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
3383  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
3384  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
3385  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
3386  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
3387  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
3388  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
3389  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
3390  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
3391  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
3392  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
3393  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
3394  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
3395  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
3396 
3397  //return all attributes string for referencedColumns - this is caught by
3398  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
3399  // feature request
3400  << new StaticFunction( "eval", 1, fcnEval, "General", QString(), true, QStringList( QgsFeatureRequest::AllAttributes ) )
3401  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
3402 
3403  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
3404  ;
3405 
3407 
3408  //QgsExpression has ownership of all built-in functions
3409  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
3410  {
3411  gmOwnedFunctions << func;
3412  }
3413  }
3414  return gmFunctions;
3415 }
3416 
3419 
3420 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
3421 {
3422  int fnIdx = functionIndex( name );
3423  if ( fnIdx != -1 )
3424  {
3425  // function of the same name already exists
3426  return;
3427  }
3428  gmSpecialColumns[ name ] = variant;
3429 }
3430 
3432 {
3434  if ( fit != gmSpecialColumns.end() )
3435  {
3436  gmSpecialColumns.erase( fit );
3437  }
3438 }
3439 
3441 {
3442  int fnIdx = functionIndex( name );
3443  if ( fnIdx != -1 )
3444  {
3445  // function of the same name already exists
3446  return QVariant();
3447  }
3449  if ( it == gmSpecialColumns.constEnd() )
3450  {
3451  return QVariant();
3452  }
3453  return it.value();
3454 }
3455 
3457 {
3458  if ( functionIndex( name ) != -1 )
3459  return false;
3460  return gmSpecialColumns.contains( name );
3461 }
3462 
3463 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
3464 {
3466  return isValid( text, &context, errorMessage );
3467 }
3468 
3469 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
3470 {
3471  QgsExpression exp( text );
3472  exp.prepare( context );
3473  errorMessage = exp.parserErrorString();
3474  return !exp.hasParserError();
3475 }
3476 
3477 void QgsExpression::setScale( double scale ) { d->mScale = scale; }
3478 
3479 double QgsExpression::scale() { return d->mScale; }
3480 
3482 {
3483  if ( !d->mExp.isNull() )
3484  return d->mExp;
3485  else
3486  return dump();
3487 }
3488 
3490 {
3491  QList<Function*> defs;
3493  {
3494  //check for special column group name
3495  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
3496  defs << new StaticFunction( it.key(), 0, static_cast< FcnEvalContext >( nullptr ), group );
3497  }
3498  return defs;
3499 }
3500 
3502 {
3503  return QString( "\"%1\"" ).arg( name.replace( '\"', "\"\"" ) );
3504 }
3505 
3507 {
3508  text.replace( '\'', "''" );
3509  text.replace( '\\', "\\\\" );
3510  text.replace( '\n', "\\n" );
3511  text.replace( '\t', "\\t" );
3512  return QString( "'%1'" ).arg( text );
3513 }
3514 
3516 {
3517  return quotedValue( value, value.type() );
3518 }
3519 
3520 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
3521 {
3522  if ( value.isNull() )
3523  return "NULL";
3524 
3525  switch ( type )
3526  {
3527  case QVariant::Int:
3528  case QVariant::LongLong:
3529  case QVariant::Double:
3530  return value.toString();
3531 
3532  case QVariant::Bool:
3533  return value.toBool() ? "TRUE" : "FALSE";
3534 
3535  default:
3536  case QVariant::String:
3537  return quotedString( value.toString() );
3538  }
3539 
3540 }
3541 
3543 {
3544  return functionIndex( name ) != -1;
3545 }
3546 
3548 {
3549  int count = functionCount();
3550  for ( int i = 0; i < count; i++ )
3551  {
3552  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
3553  return i;
3554  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
3555  {
3556  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
3557  return i;
3558  }
3559  }
3560  return -1;
3561 }
3562 
3564 {
3565  return Functions().size();
3566 }
3567 
3568 
3570  : d( new QgsExpressionPrivate )
3571 {
3572  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
3573  d->mExp = expr;
3574  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
3575 }
3576 
3578  : d( other.d )
3579 {
3580  d->ref.ref();
3581 }
3582 
3584 {
3585  d = other.d;
3586  d->ref.ref();
3587  return *this;
3588 }
3589 
3591  : d( new QgsExpressionPrivate )
3592 {
3593 }
3594 
3596 {
3597  Q_ASSERT( d );
3598  if ( !d->ref.deref() )
3599  delete d;
3600 }
3601 
3602 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
3603 
3604 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
3605 
3607 {
3608  if ( !d->mRootNode )
3609  return QStringList();
3610 
3611  QStringList columns = d->mRootNode->referencedColumns();
3612 
3613  // filter out duplicates
3614  for ( int i = 0; i < columns.count(); i++ )
3615  {
3616  QString col = columns.at( i );
3617  for ( int j = i + 1; j < columns.count(); j++ )
3618  {
3619  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
3620  {
3621  // this column is repeated: remove it!
3622  columns.removeAt( j-- );
3623  }
3624  }
3625  }
3626 
3627  return columns;
3628 }
3629 
3631 {
3632  if ( !d->mRootNode )
3633  return false;
3634  return d->mRootNode->needsGeometry();
3635 }
3636 
3638 {
3639  if ( d->mCalc.data() )
3640  return;
3641 
3642  // Use planimetric as default
3644  d->mCalc->setEllipsoidalMode( false );
3645 }
3646 
3648 {
3649  Q_ASSERT( d );
3650 
3651  if ( d->ref > 1 )
3652  {
3653  ( void )d->ref.deref();
3654 
3655  d = new QgsExpressionPrivate( *d );
3656  }
3657 }
3658 
3660 {
3661  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( calc ) );
3662 }
3663 
3664 bool QgsExpression::prepare( const QgsFields& fields )
3665 {
3666  detach();
3668  return prepare( &fc );
3669 }
3670 
3672 {
3673  detach();
3674  d->mEvalErrorString = QString();
3675  if ( !d->mRootNode )
3676  {
3677  //re-parse expression. Creation of QgsExpressionContexts may have added extra
3678  //known functions since this expression was created, so we have another try
3679  //at re-parsing it now that the context must have been created
3680  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
3681  }
3682 
3683  if ( !d->mRootNode )
3684  {
3685  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3686  return false;
3687  }
3688 
3689  return d->mRootNode->prepare( this, context );
3690 }
3691 
3693 {
3694  d->mEvalErrorString = QString();
3695  if ( !d->mRootNode )
3696  {
3697  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3698  return QVariant();
3699  }
3700 
3702  return d->mRootNode->eval( this, &context );
3703 }
3704 
3706 {
3708  return evaluate( &f );
3710 }
3711 
3713 {
3714  // first prepare
3716  bool res = prepare( &context );
3717  if ( !res )
3718  return QVariant();
3719 
3720  // then evaluate
3721  return evaluate( &context );
3722 }
3723 
3724 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
3725 {
3727  return evaluate( &f, fields );
3729 }
3730 
3732 {
3733  d->mEvalErrorString = QString();
3734  if ( !d->mRootNode )
3735  {
3736  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3737  return QVariant();
3738  }
3739 
3740  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
3741 }
3742 
3744 {
3745  d->mEvalErrorString = QString();
3746  if ( !d->mRootNode )
3747  {
3748  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3749  return QVariant();
3750  }
3751 
3752  return d->mRootNode->eval( this, context );
3753 }
3754 
3756 {
3757  return !d->mEvalErrorString.isNull();
3758 }
3759 
3761 {
3762  return d->mEvalErrorString;
3763 }
3764 
3766 {
3767  d->mEvalErrorString = str;
3768 }
3769 
3771 {
3772  d->mRowNumber = rowNumber;
3773 }
3774 
3775 int QgsExpression::currentRowNumber() { return d->mRowNumber; }
3776 
3778 {
3779  if ( !d->mRootNode )
3780  return tr( "(no root)" );
3781 
3782  return d->mRootNode->dump();
3783 }
3784 
3786 {
3787  return d->mCalc.data();
3788 }
3789 
3791 {
3792  return d->mDistanceUnit;
3793 }
3794 
3796 {
3797  d->mDistanceUnit = unit;
3798 }
3799 
3801 {
3802  return d->mAreaUnit;
3803 }
3804 
3806 {
3807  d->mAreaUnit = unit;
3808 }
3809 
3811 {
3812  if ( d->mRootNode )
3813  d->mRootNode->accept( v );
3814 }
3815 
3817  QgsVectorLayer *layer,
3818  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3819 {
3820  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
3821  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
3822 }
3823 
3824 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3825 {
3826  QString expr_action;
3827 
3828  QMap<QString, QVariant> savedValues;
3829  if ( substitutionMap )
3830  {
3831  // variables with a local scope (must be restored after evaluation)
3832  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
3833  {
3835  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
3836  if ( !oldValue.isNull() )
3837  savedValues.insert( sit.key(), oldValue );
3838 
3839  // set the new value
3840  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3842  }
3843  }
3844 
3845  int index = 0;
3846  while ( index < action.size() )
3847  {
3848  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
3849 
3850  int pos = rx.indexIn( action, index );
3851  if ( pos < 0 )
3852  break;
3853 
3854  int start = index;
3855  index = pos + rx.matchedLength();
3856  QString to_replace = rx.cap( 1 ).trimmed();
3857  QgsDebugMsg( "Found expression: " + to_replace );
3858 
3859  QgsExpression exp( to_replace );
3860  if ( exp.hasParserError() )
3861  {
3862  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
3863  expr_action += action.midRef( start, index - start );
3864  continue;
3865  }
3866 
3867  if ( distanceArea )
3868  {
3869  //if QgsDistanceArea specified for area/distance conversion, use it
3870  exp.setGeomCalculator( *distanceArea );
3871  }
3872 
3873  QVariant result = exp.evaluate( context );
3874 
3875  if ( exp.hasEvalError() )
3876  {
3877  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
3878  expr_action += action.midRef( start, index - start );
3879  continue;
3880  }
3881 
3882  QgsDebugMsg( "Expression result is: " + result.toString() );
3883  expr_action += action.mid( start, pos - start ) + result.toString();
3884  }
3885 
3886  expr_action += action.midRef( index );
3887 
3888  // restore overwritten local values
3890  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
3891  {
3892  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3893  }
3895 
3896  return expr_action;
3897 }
3898 
3899 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
3900 {
3901  bool ok;
3902  //first test if text is directly convertible to double
3903  double convertedValue = text.toDouble( &ok );
3904  if ( ok )
3905  {
3906  return convertedValue;
3907  }
3908 
3909  //otherwise try to evalute as expression
3910  QgsExpression expr( text );
3911 
3912  QgsExpressionContext context;
3915 
3916  QVariant result = expr.evaluate( &context );
3917  convertedValue = result.toDouble( &ok );
3918  if ( expr.hasEvalError() || !ok )
3919  {
3920  return fallbackValue;
3921  }
3922  return convertedValue;
3923 }
3924 
3925 
3927 // nodes
3928 
3930 {
3931  NodeList* nl = new NodeList;
3932  Q_FOREACH ( Node* node, mList )
3933  {
3934  nl->mList.append( node->clone() );
3935  }
3936  nl->mNameList = mNameList;
3937 
3938  return nl;
3939 }
3940 
3942 {
3943  QString msg;
3944  bool first = true;
3945  Q_FOREACH ( Node* n, mList )
3946  {
3947  if ( !first ) msg += ", ";
3948  else first = false;
3949  msg += n->dump();
3950  }
3951  return msg;
3952 }
3953 
3954 
3955 //
3956 
3958 {
3959  QVariant val = mOperand->eval( parent, context );
3961 
3962  switch ( mOp )
3963  {
3964  case uoNot:
3965  {
3966  TVL tvl = getTVLValue( val, parent );
3968  return tvl2variant( NOT[tvl] );
3969  }
3970 
3971  case uoMinus:
3972  if ( isIntSafe( val ) )
3973  return QVariant( - getIntValue( val, parent ) );
3974  else if ( isDoubleSafe( val ) )
3975  return QVariant( - getDoubleValue( val, parent ) );
3976  else
3977  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
3978  default:
3979  Q_ASSERT( 0 && "unknown unary operation" );
3980  }
3981  return QVariant();
3982 }
3983 
3985 {
3986  return mOperand->prepare( parent, context );
3987 }
3988 
3990 {
3991  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
3992 }
3993 
3995 {
3996  return new NodeUnaryOperator( mOp, mOperand->clone() );
3997 }
3998 
3999 //
4000 
4002 {
4003  QVariant vL = mOpLeft->eval( parent, context );
4005  QVariant vR = mOpRight->eval( parent, context );
4007 
4008  switch ( mOp )
4009  {
4010  case boPlus:
4011  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4012  {
4013  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4015  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4017  return QVariant( sL + sR );
4018  }
4019  //intentional fall-through
4020  FALLTHROUGH;
4021  case boMinus:
4022  case boMul:
4023  case boDiv:
4024  case boMod:
4025  {
4026  if ( isNull( vL ) || isNull( vR ) )
4027  return QVariant();
4028  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4029  {
4030  // both are integers - let's use integer arithmetics
4031  int iL = getIntValue( vL, parent );
4033  int iR = getIntValue( vR, parent );
4035 
4036  if ( mOp == boMod && iR == 0 )
4037  return QVariant();
4038 
4039  return QVariant( computeInt( iL, iR ) );
4040  }
4041  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4042  {
4043  QDateTime dL = getDateTimeValue( vL, parent );
4045  QgsInterval iL = getInterval( vR, parent );
4047  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4048  {
4049  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
4050  return QVariant();
4051  }
4052  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4053  }
4054  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4055  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4056  {
4057  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4059  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4061  QDateTime dt = QDateTime( date, time );
4062  return QVariant( dt );
4063  }
4064  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
4065  {
4066  QDate date1 = getDateValue( vL, parent );
4068  QDate date2 = getDateValue( vR, parent );
4070  return date1 - date2;
4071  }
4072  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
4073  {
4074  QTime time1 = getTimeValue( vL, parent );
4076  QTime time2 = getTimeValue( vR, parent );
4078  return time1 - time2;
4079  }
4080  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
4081  {
4082  QDateTime datetime1 = getDateTimeValue( vL, parent );
4084  QDateTime datetime2 = getDateTimeValue( vR, parent );
4086  return datetime1 - datetime2;
4087  }
4088  else
4089  {
4090  // general floating point arithmetic
4091  double fL = getDoubleValue( vL, parent );
4093  double fR = getDoubleValue( vR, parent );
4095  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
4096  return QVariant(); // silently handle division by zero and return NULL
4097  return QVariant( computeDouble( fL, fR ) );
4098  }
4099  }
4100  case boIntDiv:
4101  {
4102  //integer division
4103  double fL = getDoubleValue( vL, parent );
4105  double fR = getDoubleValue( vR, parent );
4107  if ( fR == 0. )
4108  return QVariant(); // silently handle division by zero and return NULL
4109  return QVariant( qFloor( fL / fR ) );
4110  }
4111  case boPow:
4112  if ( isNull( vL ) || isNull( vR ) )
4113  return QVariant();
4114  else
4115  {
4116  double fL = getDoubleValue( vL, parent );
4118  double fR = getDoubleValue( vR, parent );
4120  return QVariant( pow( fL, fR ) );
4121  }
4122 
4123  case boAnd:
4124  {
4125  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4127  return tvl2variant( AND[tvlL][tvlR] );
4128  }
4129 
4130  case boOr:
4131  {
4132  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4134  return tvl2variant( OR[tvlL][tvlR] );
4135  }
4136 
4137  case boEQ:
4138  case boNE:
4139  case boLT:
4140  case boGT:
4141  case boLE:
4142  case boGE:
4143  if ( isNull( vL ) || isNull( vR ) )
4144  {
4145  return TVL_Unknown;
4146  }
4147  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
4148  {
4149  // do numeric comparison if both operators can be converted to numbers
4150  double fL = getDoubleValue( vL, parent );
4152  double fR = getDoubleValue( vR, parent );
4154  return compare( fL - fR ) ? TVL_True : TVL_False;
4155  }
4156  else
4157  {
4158  // do string comparison otherwise
4159  QString sL = getStringValue( vL, parent );
4161  QString sR = getStringValue( vR, parent );
4163  int diff = QString::compare( sL, sR );
4164  return compare( diff ) ? TVL_True : TVL_False;
4165  }
4166 
4167  case boIs:
4168  case boIsNot:
4169  if ( isNull( vL ) && isNull( vR ) ) // both operators null
4170  return ( mOp == boIs ? TVL_True : TVL_False );
4171  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
4172  return ( mOp == boIs ? TVL_False : TVL_True );
4173  else // both operators non-null
4174  {
4175  bool equal = false;
4176  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
4177  {
4178  double fL = getDoubleValue( vL, parent );
4180  double fR = getDoubleValue( vR, parent );
4182  equal = qgsDoubleNear( fL, fR );
4183  }
4184  else
4185  {
4186  QString sL = getStringValue( vL, parent );
4188  QString sR = getStringValue( vR, parent );
4190  equal = QString::compare( sL, sR ) == 0;
4191  }
4192  if ( equal )
4193  return mOp == boIs ? TVL_True : TVL_False;
4194  else
4195  return mOp == boIs ? TVL_False : TVL_True;
4196  }
4197 
4198  case boRegexp:
4199  case boLike:
4200  case boNotLike: