Quantum GIS API Documentation  1.8
src/core/qgsexpression.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               qgsexpression.cpp
00003                              -------------------
00004     begin                : August 2011
00005     copyright            : (C) 2011 Martin Dobias
00006     email                : wonder.sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgsexpression.h"
00017 
00018 #include <QtDebug>
00019 #include <QDomDocument>
00020 #include <QSettings>
00021 
00022 #include <math.h>
00023 #include <limits>
00024 
00025 #include "qgsdistancearea.h"
00026 #include "qgsfeature.h"
00027 #include "qgsgeometry.h"
00028 #include "qgslogger.h"
00029 
00030 // from parser
00031 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
00032 
00033 
00035 // three-value logic
00036 
00037 enum TVL
00038 {
00039   False,
00040   True,
00041   Unknown
00042 };
00043 
00044 static TVL AND[3][3] =
00045 {
00046   // false  true    unknown
00047   { False, False,   False },   // false
00048   { False, True,    Unknown }, // true
00049   { False, Unknown, Unknown }  // unknown
00050 };
00051 
00052 static TVL OR[3][3] =
00053 {
00054   { False,   True, Unknown },  // false
00055   { True,    True, True },     // true
00056   { Unknown, True, Unknown }   // unknown
00057 };
00058 
00059 static TVL NOT[3] = { True, False, Unknown };
00060 
00061 static QVariant tvl2variant( TVL v )
00062 {
00063   switch ( v )
00064   {
00065     case False: return 0;
00066     case True: return 1;
00067     case Unknown:
00068     default:
00069       return QVariant();
00070   }
00071 }
00072 
00073 #define TVL_True     QVariant(1)
00074 #define TVL_False    QVariant(0)
00075 #define TVL_Unknown  QVariant()
00076 
00078 // QVariant checks and conversions
00079 
00080 inline bool isIntSafe( const QVariant& v )
00081 {
00082   if ( v.type() == QVariant::Int ) return true;
00083   if ( v.type() == QVariant::Double ) return false;
00084   if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
00085   return false;
00086 }
00087 inline bool isDoubleSafe( const QVariant& v )
00088 {
00089   if ( v.type() == QVariant::Double || v.type() == QVariant::Int ) return true;
00090   if ( v.type() == QVariant::String ) { bool ok; v.toString().toDouble( &ok ); return ok; }
00091   return false;
00092 }
00093 
00094 inline bool isNull( const QVariant& v ) { return v.isNull(); }
00095 
00097 // evaluation error macros
00098 
00099 #define ENSURE_NO_EVAL_ERROR   {  if (parent->hasEvalError()) return QVariant(); }
00100 #define SET_EVAL_ERROR(x)   { parent->setEvalErrorString(x); return QVariant(); }
00101 
00103 // operators
00104 
00105 const char* QgsExpression::BinaryOperatorText[] =
00106 {
00107   "OR", "AND",
00108   "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
00109   "+", "-", "*", "/", "%", "^",
00110   "||"
00111 };
00112 
00113 const char* QgsExpression::BinaryOgcOperatorText[] =
00114 {
00115   "Or", "And",
00116   "PropertyIsEqualTo", "PropertyIsNotEqualTo",
00117   "PropertyIsGreaterThanOrEqualTo", "PropertyIsLessThanOrEqualTo",
00118   "PropertyIsLessThan", "PropertyIsGreaterThan",
00119   "", "PropertyIsLike", "", "", "",
00120   "Add", "Sub", "Mul", "Div", "", "",
00121   ""
00122 };
00123 
00124 const char* QgsExpression::UnaryOperatorText[] =
00125 {
00126   "NOT", "-"
00127 };
00128 
00129 const char* QgsExpression::UnaryOgcOperatorText[] =
00130 {
00131   "Not", ""
00132 };
00133 
00135 // functions
00136 
00137 // implicit conversion to string
00138 static QString getStringValue( const QVariant& value, QgsExpression* )
00139 {
00140   return value.toString();
00141 }
00142 
00143 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
00144 {
00145   bool ok;
00146   double x = value.toDouble( &ok );
00147   if ( !ok )
00148   {
00149     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
00150     return 0;
00151   }
00152   return x;
00153 }
00154 
00155 static int getIntValue( const QVariant& value, QgsExpression* parent )
00156 {
00157   bool ok;
00158   qint64 x = value.toLongLong( &ok );
00159   if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() )
00160   {
00161     return x;
00162   }
00163   else
00164   {
00165     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
00166     return 0;
00167   }
00168 }
00169 
00170 
00171 // this handles also NULL values
00172 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
00173 {
00174   // we need to convert to TVL
00175   if ( value.isNull() )
00176     return Unknown;
00177 
00178   if ( value.type() == QVariant::Int )
00179     return value.toInt() != 0 ? True : False;
00180 
00181   bool ok;
00182   double x = value.toDouble( &ok );
00183   if ( !ok )
00184   {
00185     parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
00186     return Unknown;
00187   }
00188   return x != 0 ? True : False;
00189 }
00190 
00192 
00193 static QVariant fcnSqrt( const QVariantList& values, QgsFeature* /*f*/, QgsExpression* parent )
00194 {
00195   double x = getDoubleValue( values.at( 0 ), parent );
00196   return QVariant( sqrt( x ) );
00197 }
00198 static QVariant fcnSin( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00199 {
00200   double x = getDoubleValue( values.at( 0 ), parent );
00201   return QVariant( sin( x ) );
00202 }
00203 static QVariant fcnCos( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00204 {
00205   double x = getDoubleValue( values.at( 0 ), parent );
00206   return QVariant( cos( x ) );
00207 }
00208 static QVariant fcnTan( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00209 {
00210   double x = getDoubleValue( values.at( 0 ), parent );
00211   return QVariant( tan( x ) );
00212 }
00213 static QVariant fcnAsin( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00214 {
00215   double x = getDoubleValue( values.at( 0 ), parent );
00216   return QVariant( asin( x ) );
00217 }
00218 static QVariant fcnAcos( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00219 {
00220   double x = getDoubleValue( values.at( 0 ), parent );
00221   return QVariant( acos( x ) );
00222 }
00223 static QVariant fcnAtan( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00224 {
00225   double x = getDoubleValue( values.at( 0 ), parent );
00226   return QVariant( atan( x ) );
00227 }
00228 static QVariant fcnAtan2( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00229 {
00230   double y = getDoubleValue( values.at( 0 ), parent );
00231   double x = getDoubleValue( values.at( 1 ), parent );
00232   return QVariant( atan2( y, x ) );
00233 }
00234 static QVariant fcnExp( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00235 {
00236   double x = getDoubleValue( values.at( 0 ), parent );
00237   return QVariant( exp( x ) );
00238 }
00239 static QVariant fcnLn( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00240 {
00241   double x = getDoubleValue( values.at( 0 ), parent );
00242   if ( x <= 0 )
00243     return QVariant();
00244   return QVariant( log( x ) );
00245 }
00246 static QVariant fcnLog10( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00247 {
00248   double x = getDoubleValue( values.at( 0 ), parent );
00249   if ( x <= 0 )
00250     return QVariant();
00251   return QVariant( log10( x ) );
00252 }
00253 static QVariant fcnLog( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00254 {
00255   double b = getDoubleValue( values.at( 0 ), parent );
00256   double x = getDoubleValue( values.at( 1 ), parent );
00257   if ( x <= 0 || b <= 0 )
00258     return QVariant();
00259   return QVariant( log( x ) / log( b ) );
00260 }
00261 static QVariant fcnToInt( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00262 {
00263   return QVariant( getIntValue( values.at( 0 ), parent ) );
00264 }
00265 static QVariant fcnToReal( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00266 {
00267   return QVariant( getDoubleValue( values.at( 0 ), parent ) );
00268 }
00269 static QVariant fcnToString( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00270 {
00271   return QVariant( getStringValue( values.at( 0 ), parent ) );
00272 }
00273 static QVariant fcnLower( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00274 {
00275   QString str = getStringValue( values.at( 0 ), parent );
00276   return QVariant( str.toLower() );
00277 }
00278 static QVariant fcnUpper( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00279 {
00280   QString str = getStringValue( values.at( 0 ), parent );
00281   return QVariant( str.toUpper() );
00282 }
00283 static QVariant fcnLength( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00284 {
00285   QString str = getStringValue( values.at( 0 ), parent );
00286   return QVariant( str.length() );
00287 }
00288 static QVariant fcnReplace( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00289 {
00290   QString str = getStringValue( values.at( 0 ), parent );
00291   QString before = getStringValue( values.at( 1 ), parent );
00292   QString after = getStringValue( values.at( 2 ), parent );
00293   return QVariant( str.replace( before, after ) );
00294 }
00295 static QVariant fcnRegexpReplace( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00296 {
00297   QString str = getStringValue( values.at( 0 ), parent );
00298   QString regexp = getStringValue( values.at( 1 ), parent );
00299   QString after = getStringValue( values.at( 2 ), parent );
00300 
00301   QRegExp re( regexp );
00302   if ( !re.isValid() )
00303   {
00304     parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
00305     return QVariant();
00306   }
00307   return QVariant( str.replace( re, after ) );
00308 }
00309 static QVariant fcnSubstr( const QVariantList& values, QgsFeature* , QgsExpression* parent )
00310 {
00311   QString str = getStringValue( values.at( 0 ), parent );
00312   int from = getIntValue( values.at( 1 ), parent );
00313   int len = getIntValue( values.at( 2 ), parent );
00314   return QVariant( str.mid( from -1, len ) );
00315 }
00316 
00317 static QVariant fcnRowNumber( const QVariantList& , QgsFeature* , QgsExpression* parent )
00318 {
00319   return QVariant( parent->currentRowNumber() );
00320 }
00321 
00322 static QVariant fcnFeatureId( const QVariantList& , QgsFeature* f, QgsExpression* )
00323 {
00324   // TODO: handling of 64-bit feature ids?
00325   return f ? QVariant(( int )f->id() ) : QVariant();
00326 }
00327 
00328 #define ENSURE_GEOM_TYPE(f, g, geomtype)   if (!f) return QVariant(); \
00329   QgsGeometry* g = f->geometry(); \
00330   if (!g || g->type() != geomtype) return QVariant();
00331 
00332 
00333 static QVariant fcnX( const QVariantList& , QgsFeature* f, QgsExpression* )
00334 {
00335   ENSURE_GEOM_TYPE( f, g, QGis::Point );
00336   if ( g->isMultipart() )
00337   {
00338     return g->asMultiPoint()[ 0 ].x();
00339   }
00340   else
00341   {
00342     return g->asPoint().x();
00343   }
00344 }
00345 static QVariant fcnY( const QVariantList& , QgsFeature* f, QgsExpression* )
00346 {
00347   ENSURE_GEOM_TYPE( f, g, QGis::Point );
00348   if ( g->isMultipart() )
00349   {
00350     return g->asMultiPoint()[ 0 ].y();
00351   }
00352   else
00353   {
00354     return g->asPoint().y();
00355   }
00356 }
00357 
00358 static QVariant pointAt( const QVariantList& values, QgsFeature* f, QgsExpression* parent ) // helper function
00359 {
00360   int idx = getIntValue( values.at( 0 ), parent );
00361   ENSURE_GEOM_TYPE( f, g, QGis::Line );
00362   QgsPolyline polyline = g->asPolyline();
00363   if ( idx < 0 )
00364     idx += polyline.count();
00365 
00366   if ( idx < 0 || idx >= polyline.count() )
00367   {
00368     parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
00369     return QVariant();
00370   }
00371   return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) );
00372 }
00373 
00374 static QVariant fcnXat( const QVariantList& values, QgsFeature* f, QgsExpression* parent )
00375 {
00376   QVariant v = pointAt( values, f, parent );
00377   if ( v.type() == QVariant::PointF )
00378     return QVariant( v.toPointF().x() );
00379   else
00380     return QVariant();
00381 }
00382 static QVariant fcnYat( const QVariantList& values, QgsFeature* f, QgsExpression* parent )
00383 {
00384   QVariant v = pointAt( values, f, parent );
00385   if ( v.type() == QVariant::PointF )
00386     return QVariant( v.toPointF().y() );
00387   else
00388     return QVariant();
00389 }
00390 
00391 static QVariant fcnGeomArea( const QVariantList& , QgsFeature* f, QgsExpression* parent )
00392 {
00393   ENSURE_GEOM_TYPE( f, g, QGis::Polygon );
00394   QgsDistanceArea* calc = parent->geomCalculator();
00395   return QVariant( calc->measure( f->geometry() ) );
00396 }
00397 static QVariant fcnGeomLength( const QVariantList& , QgsFeature* f, QgsExpression* parent )
00398 {
00399   ENSURE_GEOM_TYPE( f, g, QGis::Line );
00400   QgsDistanceArea* calc = parent->geomCalculator();
00401   return QVariant( calc->measure( f->geometry() ) );
00402 }
00403 static QVariant fcnGeomPerimeter( const QVariantList& , QgsFeature* f, QgsExpression* parent )
00404 {
00405   ENSURE_GEOM_TYPE( f, g, QGis::Polygon );
00406   QgsDistanceArea* calc = parent->geomCalculator();
00407   return QVariant( calc->measurePerimeter( f->geometry() ) );
00408 }
00409 
00410 QList<QgsExpression::FunctionDef> QgsExpression::gmBuiltinFunctions;
00411 
00412 const QList<QgsExpression::FunctionDef> &QgsExpression::BuiltinFunctions()
00413 {
00414   if ( gmBuiltinFunctions.isEmpty() )
00415   {
00416     // math
00417     gmBuiltinFunctions
00418     << FunctionDef( "sqrt", 1, fcnSqrt, QObject::tr( "Math" ) )
00419     << FunctionDef( "sin", 1, fcnSin, QObject::tr( "Math" ) )
00420     << FunctionDef( "cos", 1, fcnCos, QObject::tr( "Math" ) )
00421     << FunctionDef( "tan", 1, fcnTan, QObject::tr( "Math" ) )
00422     << FunctionDef( "asin", 1, fcnAsin, QObject::tr( "Math" ) )
00423     << FunctionDef( "acos", 1, fcnAcos, QObject::tr( "Math" ) )
00424     << FunctionDef( "atan", 1, fcnAtan, QObject::tr( "Math" ) )
00425     << FunctionDef( "atan2", 2, fcnAtan2, QObject::tr( "Math" ) )
00426     << FunctionDef( "exp", 1, fcnExp, QObject::tr( "Math" ) )
00427     << FunctionDef( "ln", 1, fcnLn, QObject::tr( "Math" ) )
00428     << FunctionDef( "log10", 1, fcnLog10, QObject::tr( "Math" ) )
00429     << FunctionDef( "log", 2, fcnLog, QObject::tr( "Math" ) )
00430     // casts
00431     << FunctionDef( "toint", 1, fcnToInt, QObject::tr( "Conversions" ) )
00432     << FunctionDef( "toreal", 1, fcnToReal, QObject::tr( "Conversions" ) )
00433     << FunctionDef( "tostring", 1, fcnToString, QObject::tr( "Conversions" ) )
00434     // string manipulation
00435     << FunctionDef( "lower", 1, fcnLower, QObject::tr( "String" ) )
00436     << FunctionDef( "upper", 1, fcnUpper, QObject::tr( "String" ) )
00437     << FunctionDef( "length", 1, fcnLength, QObject::tr( "String" ) )
00438     << FunctionDef( "replace", 3, fcnReplace, QObject::tr( "String" ) )
00439     << FunctionDef( "regexp_replace", 3, fcnRegexpReplace, QObject::tr( "String" ) )
00440     << FunctionDef( "substr", 3, fcnSubstr, QObject::tr( "String" ) )
00441     // geometry accessors
00442     << FunctionDef( "xat", 1, fcnXat, QObject::tr( "Geometry" ), "", true )
00443     << FunctionDef( "yat", 1, fcnYat, QObject::tr( "Geometry" ), "", true )
00444     << FunctionDef( "$area", 0, fcnGeomArea, QObject::tr( "Geometry" ), "", true )
00445     << FunctionDef( "$length", 0, fcnGeomLength, QObject::tr( "Geometry" ), "", true )
00446     << FunctionDef( "$perimeter", 0, fcnGeomPerimeter, QObject::tr( "Geometry" ), "", true )
00447     << FunctionDef( "$x", 0, fcnX, QObject::tr( "Geometry" ), "", true )
00448     << FunctionDef( "$y", 0, fcnY, QObject::tr( "Geometry" ), "" , true )
00449     // special columns
00450     << FunctionDef( "$rownum", 0, fcnRowNumber, QObject::tr( "Record" ) )
00451     << FunctionDef( "$id", 0, fcnFeatureId, QObject::tr( "Record" ) )
00452     ;
00453   }
00454 
00455   return gmBuiltinFunctions;
00456 }
00457 
00458 
00459 bool QgsExpression::isFunctionName( QString name )
00460 {
00461   return functionIndex( name ) != -1;
00462 }
00463 
00464 int QgsExpression::functionIndex( QString name )
00465 {
00466   int count = functionCount();
00467   for ( int i = 0; i < count; i++ )
00468   {
00469     if ( QString::compare( name, BuiltinFunctions()[i].mName, Qt::CaseInsensitive ) == 0 )
00470       return i;
00471   }
00472   return -1;
00473 }
00474 
00475 int QgsExpression::functionCount()
00476 {
00477   return BuiltinFunctions().size();
00478 }
00479 
00480 
00481 QgsExpression::QgsExpression( const QString& expr )
00482     : mExpression( expr ), mRowNumber( 0 ), mCalc( NULL )
00483 {
00484   mRootNode = ::parseExpression( mExpression, mParserErrorString );
00485 
00486   if ( mParserErrorString.isNull() )
00487   {
00488     Q_ASSERT( mRootNode != NULL );
00489   }
00490 }
00491 
00492 QgsExpression::~QgsExpression()
00493 {
00494   delete mRootNode;
00495   delete mCalc;
00496 }
00497 
00498 QStringList QgsExpression::referencedColumns()
00499 {
00500   if ( !mRootNode )
00501     return QStringList();
00502   QStringList columns = mRootNode->referencedColumns();
00503 
00504   // filter out duplicates
00505   for ( int i = 0; i < columns.count(); i++ )
00506   {
00507     QString col = columns.at( i );
00508     for ( int j = i + 1; j < columns.count(); j++ )
00509     {
00510       if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
00511       {
00512         // this column is repeated: remove it!
00513         columns.removeAt( j-- );
00514       }
00515     }
00516   }
00517 
00518   return columns;
00519 }
00520 
00521 bool QgsExpression::needsGeometry()
00522 {
00523   if ( !mRootNode )
00524     return false;
00525   return mRootNode->needsGeometry();
00526 }
00527 
00528 void QgsExpression::initGeomCalculator()
00529 {
00530   mCalc = new QgsDistanceArea;
00531   mCalc->setProjectionsEnabled( false );
00532   QSettings settings;
00533   QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString();
00534   mCalc->setEllipsoid( ellipsoid );
00535 }
00536 
00537 bool QgsExpression::prepare( const QgsFieldMap& fields )
00538 {
00539   mEvalErrorString = QString();
00540   if ( !mRootNode )
00541   {
00542     mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
00543     return false;
00544   }
00545 
00546   return mRootNode->prepare( this, fields );
00547 }
00548 
00549 QVariant QgsExpression::evaluate( QgsFeature* f )
00550 {
00551   mEvalErrorString = QString();
00552   if ( !mRootNode )
00553   {
00554     mEvalErrorString = QObject::tr( "No root node! Parsing failed?" );
00555     return QVariant();
00556   }
00557 
00558   return mRootNode->eval( this, f );
00559 }
00560 
00561 QVariant QgsExpression::evaluate( QgsFeature* f, const QgsFieldMap& fields )
00562 {
00563   // first prepare
00564   bool res = prepare( fields );
00565   if ( !res )
00566     return QVariant();
00567 
00568   // then evaluate
00569   return evaluate( f );
00570 }
00571 
00572 QString QgsExpression::dump() const
00573 {
00574   if ( !mRootNode )
00575     return QObject::tr( "(no root)" );
00576 
00577   return mRootNode->dump();
00578 }
00579 
00580 void QgsExpression::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
00581 {
00582   if ( !mRootNode )
00583     return;
00584 
00585   mRootNode->toOgcFilter( doc, element );
00586 }
00587 
00588 QgsExpression* QgsExpression::createFromOgcFilter( QDomElement &element )
00589 {
00590   if ( element.isNull() || !element.hasChildNodes() )
00591     return NULL;
00592 
00593   QgsExpression *expr = new QgsExpression();
00594 
00595   QDomElement childElem = element.firstChildElement();
00596   while ( !childElem.isNull() )
00597   {
00598     QString errorMsg;
00599     QgsExpression::Node *node = QgsExpression::Node::createFromOgcFilter( childElem, errorMsg );
00600     if ( !node )
00601     {
00602       // invalid expression, parser error
00603       expr->mParserErrorString = errorMsg;
00604       return expr;
00605     }
00606 
00607     // use the concat binary operator to append to the root node
00608     if ( !expr->mRootNode )
00609     {
00610       expr->mRootNode = node;
00611     }
00612     else
00613     {
00614       expr->mRootNode = new QgsExpression::NodeBinaryOperator( boConcat, expr->mRootNode, node );
00615     }
00616 
00617     childElem = childElem.nextSiblingElement();
00618   }
00619 
00620   return expr;
00621 }
00622 
00623 void QgsExpression::acceptVisitor( QgsExpression::Visitor& v )
00624 {
00625   if ( mRootNode )
00626     mRootNode->accept( v );
00627 }
00628 
00629 
00630 QgsExpression::Node* QgsExpression::Node::createFromOgcFilter( QDomElement &element, QString &errorMessage )
00631 {
00632   if ( element.isNull() )
00633     return NULL;
00634 
00635   // check for unary operators
00636   int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] );
00637   for ( int i = 0; i < unaryOpCount; i++ )
00638   {
00639     QString ogcOperatorName = UnaryOgcOperatorText[ i ];
00640     if ( ogcOperatorName.isEmpty() )
00641       continue;
00642 
00643     if ( element.localName() == ogcOperatorName )
00644     {
00645       QgsExpression::Node *node = QgsExpression::NodeUnaryOperator::createFromOgcFilter( element, errorMessage );
00646       if ( node )
00647         return node;
00648 
00649       return NULL;
00650     }
00651   }
00652 
00653   // check for binary operators
00654   int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] );
00655   for ( int i = 0; i < binaryOpCount; i++ )
00656   {
00657     QString ogcOperatorName = BinaryOgcOperatorText[ i ];
00658     if ( ogcOperatorName.isEmpty() )
00659       continue;
00660 
00661     if ( element.localName() == ogcOperatorName )
00662     {
00663       QgsExpression::Node *node = QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage );
00664       if ( node )
00665         return node;
00666 
00667       return NULL;
00668     }
00669   }
00670 
00671   // check for other OGC operators, convert them to expressions
00672 
00673   if ( element.localName() == "PropertyIsNull" )
00674   {
00675     return QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage );
00676   }
00677   else if ( element.localName() == "Literal" )
00678   {
00679     return QgsExpression::NodeLiteral::createFromOgcFilter( element, errorMessage );
00680   }
00681   else if ( element.localName() == "Function" )
00682   {
00683     return QgsExpression::NodeFunction::createFromOgcFilter( element, errorMessage );
00684   }
00685   else if ( element.localName() == "PropertyName" )
00686   {
00687     return QgsExpression::NodeColumnRef::createFromOgcFilter( element, errorMessage );
00688   }
00689   else if ( element.localName() == "PropertyIsBetween" )
00690   {
00691     // <ogc:PropertyIsBetween> encode a Range check
00692     QgsExpression::Node *operand = 0, *lowerBound = 0, *upperBound = 0;
00693 
00694     QDomElement operandElem = element.firstChildElement( "LowerBoundary" );
00695     if ( !operandElem.isNull() )
00696       lowerBound = createFromOgcFilter( operandElem, errorMessage );
00697 
00698     operandElem = element.firstChildElement( "UpperBoundary" );
00699     if ( !operandElem.isNull() )
00700       upperBound = createFromOgcFilter( operandElem, errorMessage );
00701 
00702     // <ogc:expression>
00703     operandElem = element.firstChildElement();
00704     while ( !operandElem.isNull() )
00705     {
00706       if ( operandElem.localName() != "LowerBoundary" &&
00707            operandElem.localName() != "UpperBoundary" )
00708       {
00709         operand = createFromOgcFilter( operandElem, errorMessage );
00710         break;
00711       }
00712 
00713       operandElem = operandElem.nextSiblingElement();
00714     }
00715 
00716     if ( !operand || !lowerBound || !upperBound )
00717     {
00718       if ( operand )
00719         delete operand;
00720 
00721       if ( lowerBound )
00722         delete lowerBound;
00723 
00724       if ( upperBound )
00725         delete upperBound;
00726 
00727       errorMessage = "missing some required sub-elements in ogc:PropertyIsBetween";
00728       return NULL;
00729     }
00730 
00731     QgsExpression::Node *geOperator = new QgsExpression::NodeBinaryOperator( boGE, operand, lowerBound );
00732     QgsExpression::Node *leOperator = new QgsExpression::NodeBinaryOperator( boLE, operand, upperBound );
00733     return new QgsExpression::NodeBinaryOperator( boAnd, geOperator, leOperator );
00734   }
00735 
00736   errorMessage += QString( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() );
00737   return NULL;
00738 }
00739 
00741 // nodes
00742 
00743 QString QgsExpression::NodeList::dump() const
00744 {
00745   QString msg; bool first = true;
00746   foreach( Node* n, mList )
00747   {
00748     if ( !first ) msg += ", "; else first = false;
00749     msg += n->dump();
00750   }
00751   return msg;
00752 }
00753 
00754 void QgsExpression::NodeList::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
00755 {
00756   foreach( Node* n, mList )
00757   {
00758     n->toOgcFilter( doc, element );
00759   }
00760 }
00761 
00762 //
00763 
00764 QVariant QgsExpression::NodeUnaryOperator::eval( QgsExpression* parent, QgsFeature* f )
00765 {
00766   QVariant val = mOperand->eval( parent, f );
00767   ENSURE_NO_EVAL_ERROR;
00768 
00769   switch ( mOp )
00770   {
00771     case uoNot:
00772     {
00773       TVL tvl = getTVLValue( val, parent );
00774       ENSURE_NO_EVAL_ERROR;
00775       return tvl2variant( NOT[tvl] );
00776     }
00777 
00778     case uoMinus:
00779       if ( isIntSafe( val ) )
00780         return QVariant( - getIntValue( val, parent ) );
00781       else if ( isDoubleSafe( val ) )
00782         return QVariant( - getDoubleValue( val, parent ) );
00783       else
00784         SET_EVAL_ERROR( QObject::tr( "Unary minus only for numeric values." ) );
00785       break;
00786     default:
00787       Q_ASSERT( 0 && "unknown unary operation" );
00788   }
00789   return QVariant();
00790 }
00791 
00792 bool QgsExpression::NodeUnaryOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields )
00793 {
00794   return mOperand->prepare( parent, fields );
00795 }
00796 
00797 QString QgsExpression::NodeUnaryOperator::dump() const
00798 {
00799   return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() );
00800 }
00801 
00802 void QgsExpression::NodeUnaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
00803 {
00804   QDomElement uoElem;
00805   switch ( mOp )
00806   {
00807     case uoMinus:
00808       uoElem = doc.createElement( "ogc:Literal" );
00809       uoElem.appendChild( doc.createTextNode( "-" ) );
00810       break;
00811     case uoNot:
00812       uoElem = doc.createElement( "ogc:Not" );
00813       break;
00814 
00815     default:
00816       element.appendChild( doc.createComment( QString( "Unary operator %1 not implemented yet" ).arg( UnaryOperatorText[mOp] ) ) );
00817       return;
00818   }
00819   mOperand->toOgcFilter( doc, uoElem );
00820   element.appendChild( uoElem );
00821 }
00822 
00823 QgsExpression::Node* QgsExpression::NodeUnaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage )
00824 {
00825   if ( element.isNull() )
00826     return NULL;
00827 
00828   int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] );
00829   for ( int i = 0; i < unaryOpCount; i++ )
00830   {
00831     QString ogcOperatorName = UnaryOgcOperatorText[ i ];
00832     if ( ogcOperatorName.isEmpty() )
00833       continue;
00834 
00835     if ( element.localName() != ogcOperatorName )
00836       continue;
00837 
00838     QDomElement operandElem = element.firstChildElement();
00839     QgsExpression::Node* operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
00840     if ( !operand )
00841     {
00842       if ( errorMessage.isEmpty() )
00843         errorMessage = QString( "invalid operand for '%1' unary operator" ).arg( ogcOperatorName );
00844       return NULL;
00845     }
00846 
00847     return new QgsExpression::NodeUnaryOperator(( UnaryOperator ) i, operand );
00848   }
00849 
00850   errorMessage = QString( "%1 unary operator not supported." ).arg( element.tagName() );
00851   return NULL;
00852 }
00853 
00854 //
00855 
00856 QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, QgsFeature* f )
00857 {
00858   QVariant vL = mOpLeft->eval( parent, f );
00859   ENSURE_NO_EVAL_ERROR;
00860   QVariant vR = mOpRight->eval( parent, f );
00861   ENSURE_NO_EVAL_ERROR;
00862 
00863   switch ( mOp )
00864   {
00865     case boPlus:
00866     case boMinus:
00867     case boMul:
00868     case boDiv:
00869     case boMod:
00870       if ( isNull( vL ) || isNull( vR ) )
00871         return QVariant();
00872       else if ( isIntSafe( vL ) && isIntSafe( vR ) )
00873       {
00874         // both are integers - let's use integer arithmetics
00875         int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00876         int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00877         if ( mOp == boDiv && iR == 0 ) return QVariant(); // silently handle division by zero and return NULL
00878         return QVariant( computeInt( iL, iR ) );
00879       }
00880       else
00881       {
00882         // general floating point arithmetic
00883         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00884         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00885         if ( mOp == boDiv && fR == 0 )
00886           return QVariant(); // silently handle division by zero and return NULL
00887         return QVariant( computeDouble( fL, fR ) );
00888       }
00889 
00890     case boPow:
00891       if ( isNull( vL ) || isNull( vR ) )
00892         return QVariant();
00893       else
00894       {
00895         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00896         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00897         return QVariant( pow( fL, fR ) );
00898       }
00899 
00900     case boAnd:
00901     {
00902       TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
00903       ENSURE_NO_EVAL_ERROR;
00904       return tvl2variant( AND[tvlL][tvlR] );
00905     }
00906 
00907     case boOr:
00908     {
00909       TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
00910       ENSURE_NO_EVAL_ERROR;
00911       return tvl2variant( OR[tvlL][tvlR] );
00912     }
00913 
00914     case boEQ:
00915     case boNE:
00916     case boLT:
00917     case boGT:
00918     case boLE:
00919     case boGE:
00920       if ( isNull( vL ) || isNull( vR ) )
00921       {
00922         return TVL_Unknown;
00923       }
00924       else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
00925       {
00926         // do numeric comparison if both operators can be converted to numbers
00927         double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00928         double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00929         return compare( fL - fR ) ? TVL_True : TVL_False;
00930       }
00931       else
00932       {
00933         // do string comparison otherwise
00934         QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00935         QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00936         int diff = QString::compare( sL, sR );
00937         return compare( diff ) ? TVL_True : TVL_False;
00938       }
00939 
00940     case boIs:
00941     case boIsNot:
00942       if ( isNull( vL ) && isNull( vR ) ) // both operators null
00943         return ( mOp == boIs ? TVL_True : TVL_False );
00944       else if ( isNull( vL ) || isNull( vR ) ) // one operator null
00945         return ( mOp == boIs ? TVL_False : TVL_True );
00946       else // both operators non-null
00947       {
00948         bool equal = false;
00949         if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) )
00950         {
00951           double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00952           double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00953           equal = fL == fR;
00954         }
00955         else
00956         {
00957           QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00958           QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00959           equal = QString::compare( sL, sR ) == 0;
00960         }
00961         if ( equal )
00962           return mOp == boIs ? TVL_True : TVL_False;
00963         else
00964           return mOp == boIs ? TVL_False : TVL_True;
00965       }
00966 
00967     case boRegexp:
00968     case boLike:
00969     case boNotLike:
00970     case boILike:
00971     case boNotILike:
00972       if ( isNull( vL ) || isNull( vR ) )
00973         return TVL_Unknown;
00974       else
00975       {
00976         QString str    = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
00977         QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
00978         // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
00979         bool matches;
00980         if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
00981         {
00982           // XXX escape % and _  ???
00983           regexp.replace( "%", ".*" );
00984           regexp.replace( "_", "." );
00985           matches = QRegExp( regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
00986         }
00987         else
00988         {
00989           matches = QRegExp( regexp ).indexIn( str ) != -1;
00990         }
00991 
00992         if ( mOp == boNotLike || mOp == boNotILike )
00993         {
00994           matches = !matches;
00995         }
00996 
00997         return matches ? TVL_True : TVL_False;
00998       }
00999 
01000     case boConcat:
01001       if ( isNull( vL ) || isNull( vR ) )
01002         return QVariant();
01003       else
01004       {
01005         QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR;
01006         QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR;
01007         return QVariant( sL + sR );
01008       }
01009 
01010     default: break;
01011   }
01012   Q_ASSERT( false );
01013   return QVariant();
01014 }
01015 
01016 bool QgsExpression::NodeBinaryOperator::compare( double diff )
01017 {
01018   switch ( mOp )
01019   {
01020     case boEQ: return diff == 0;
01021     case boNE: return diff != 0;
01022     case boLT: return diff < 0;
01023     case boGT: return diff > 0;
01024     case boLE: return diff <= 0;
01025     case boGE: return diff >= 0;
01026     default: Q_ASSERT( false ); return false;
01027   }
01028 }
01029 
01030 int QgsExpression::NodeBinaryOperator::computeInt( int x, int y )
01031 {
01032   switch ( mOp )
01033   {
01034     case boPlus: return x+y;
01035     case boMinus: return x-y;
01036     case boMul: return x*y;
01037     case boDiv: return x/y;
01038     case boMod: return x%y;
01039     default: Q_ASSERT( false ); return 0;
01040   }
01041 }
01042 
01043 double QgsExpression::NodeBinaryOperator::computeDouble( double x, double y )
01044 {
01045   switch ( mOp )
01046   {
01047     case boPlus: return x+y;
01048     case boMinus: return x-y;
01049     case boMul: return x*y;
01050     case boDiv: return x/y;
01051     case boMod: return fmod( x,y );
01052     default: Q_ASSERT( false ); return 0;
01053   }
01054 }
01055 
01056 
01057 bool QgsExpression::NodeBinaryOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields )
01058 {
01059   bool resL = mOpLeft->prepare( parent, fields );
01060   bool resR = mOpRight->prepare( parent, fields );
01061   return resL && resR;
01062 }
01063 
01064 QString QgsExpression::NodeBinaryOperator::dump() const
01065 {
01066   return QString( "%1 %2 %3" ).arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
01067 }
01068 
01069 void QgsExpression::NodeBinaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01070 {
01071   if ( mOp == boConcat )
01072   {
01073     // the concat binary operator must only convert its operands
01074     mOpLeft->toOgcFilter( doc, element );
01075     mOpRight->toOgcFilter( doc, element );
01076     return;
01077   }
01078 
01079   if ( mOp == boIs || mOp == boIsNot )
01080   {
01081     // check if one of the operands is NULL
01082     QgsExpression::NodeLiteral *opLeftLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpLeft );
01083     QgsExpression::NodeLiteral *opRightLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpRight );
01084 
01085     if ( opLeftLiteral && opLeftLiteral->value().isNull() &&
01086          opRightLiteral && opRightLiteral->value().isNull() )
01087     {
01088       // why could anybody find useful to use NULL IS NULL???
01089       // BTW avoid issues by converting it to 1 = 1
01090       QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" );
01091 
01092       QDomElement literalElem = doc.createElement( "ogc:Literal" );
01093       literalElem.appendChild( doc.createTextNode( "1" ) );
01094       eqElem.appendChild( literalElem );
01095 
01096       literalElem = doc.createElement( "ogc:Literal" );
01097       literalElem.appendChild( doc.createTextNode( "1" ) );
01098       eqElem.appendChild( literalElem );
01099 
01100       element.appendChild( eqElem );
01101     }
01102     else if (( opLeftLiteral && opLeftLiteral->value().isNull() ) ||
01103              ( opRightLiteral && opRightLiteral->value().isNull() ) )
01104     {
01105       // at least one operand is NULL, use <ogc:PropertyIsNull> element
01106       QDomElement isNullElem = doc.createElement( "ogc:PropertyIsNull" );
01107       QgsExpression::Node *operand = opLeftLiteral->value().isNull() ? mOpRight : mOpLeft;
01108       operand->toOgcFilter( doc, isNullElem );
01109 
01110       if ( mOp == boIsNot )
01111       {
01112         // append to <ogc:Not> element if IS NOT operator was required
01113         QDomElement notOpElem = doc.createElement( "ogc:Not" );
01114         notOpElem.appendChild( isNullElem );
01115         element.appendChild( notOpElem );
01116       }
01117       else
01118       {
01119         element.appendChild( isNullElem );
01120       }
01121     }
01122     else
01123     {
01124       // both operands are not null, use <ogc:PropertyIsEqual> element
01125       QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" );
01126       mOpLeft->toOgcFilter( doc, eqElem );
01127       mOpRight->toOgcFilter( doc, eqElem );
01128       element.appendChild( eqElem );
01129     }
01130     return;
01131   }
01132 
01133   if ( mOp == boILike )
01134   {
01135     // XXX why ogc:PropertyIsLikeType extends ogc:ComparisonOpsType
01136     // which has no matchCase attribute? Shouldn't it be better if
01137     // would extend BinaryComparisonOpType which has that attribute
01138     // and doesn't require to have a ogc:PropertyName as first parameter?
01139     QgsExpression ilikeExpr( QString( "upper( %1 ) LIKE upper( %2 )" ).arg( mOpLeft->dump() ).arg( mOpRight->dump() ) );
01140     ilikeExpr.toOgcFilter( doc, element );
01141     return;
01142   }
01143 
01144   QString opText = BinaryOgcOperatorText[mOp];
01145   if ( opText.isEmpty() )
01146   {
01147     // not implemented binary operators
01148     // TODO: regex, % (mod), ^ (pow) are not supported yet
01149     element.appendChild( doc.createComment( QString( "Binary operator %1 not implemented yet" ).arg( BinaryOperatorText[mOp] ) ) );
01150     return;
01151   }
01152 
01153   QDomElement boElem = doc.createElement( "ogc:" + opText );
01154   if ( mOp == boLike )
01155   {
01156     // setup wildcards to <ogc:PropertyIsLike>
01157     boElem.setAttribute( "wildCard", "%" );
01158     boElem.setAttribute( "singleChar", "?" );
01159     boElem.setAttribute( "escapeChar", "!" );
01160   }
01161 
01162   mOpLeft->toOgcFilter( doc, boElem );
01163   mOpRight->toOgcFilter( doc, boElem );
01164   element.appendChild( boElem );
01165 }
01166 
01167 QgsExpression::Node* QgsExpression::NodeBinaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage )
01168 {
01169   if ( element.isNull() )
01170     return NULL;
01171 
01172   QgsExpression::Node* opLeft = 0;
01173   QgsExpression::Node* opRight = 0;
01174 
01175   // convert ogc:PropertyIsNull to IS operator with NULL right operand
01176   if ( element.localName() == "PropertyIsNull" )
01177   {
01178     QDomElement operandElem = element.firstChildElement();
01179     opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
01180     if ( !opLeft )
01181       return NULL;
01182 
01183     opRight = new QgsExpression::NodeLiteral( QVariant() );
01184     return new QgsExpression::NodeBinaryOperator( boIs, opLeft, opRight );
01185   }
01186 
01187   // the other binary operators
01188   int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] );
01189   for ( int i = 0; i < binaryOpCount; i++ )
01190   {
01191     QString ogcOperatorName = BinaryOgcOperatorText[ i ];
01192     if ( ogcOperatorName.isEmpty() )
01193       continue;
01194 
01195     if ( element.localName() != ogcOperatorName )
01196       continue;
01197 
01198     QDomElement operandElem = element.firstChildElement();
01199     opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
01200     if ( !opLeft )
01201     {
01202       if ( errorMessage.isEmpty() )
01203         errorMessage = QString( "invalid left operand for '%1' binary operator" ).arg( ogcOperatorName );
01204       break;
01205     }
01206 
01207     operandElem = operandElem.nextSiblingElement();
01208     opRight = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
01209     if ( !opRight )
01210     {
01211       if ( errorMessage.isEmpty() )
01212         errorMessage = QString( "invalid right operand for '%1' binary operator" ).arg( ogcOperatorName );
01213       break;
01214     }
01215 
01216     return new QgsExpression::NodeBinaryOperator(( BinaryOperator ) i, opLeft, opRight );
01217   }
01218 
01219   if ( !opLeft && !opRight )
01220   {
01221     errorMessage = QString( "'%1' binary operator not supported." ).arg( element.tagName() );
01222     return NULL;
01223   }
01224 
01225   if ( opLeft )
01226     delete opLeft;
01227 
01228   if ( opRight )
01229     delete opRight;
01230 
01231   return NULL;
01232 }
01233 
01234 //
01235 
01236 QVariant QgsExpression::NodeInOperator::eval( QgsExpression* parent, QgsFeature* f )
01237 {
01238   if ( mList->count() == 0 )
01239     return mNotIn ? TVL_True : TVL_False;
01240   QVariant v1 = mNode->eval( parent, f );
01241   ENSURE_NO_EVAL_ERROR;
01242   if ( isNull( v1 ) )
01243     return TVL_Unknown;
01244 
01245   bool listHasNull = false;
01246 
01247   foreach( Node* n, mList->list() )
01248   {
01249     QVariant v2 = n->eval( parent, f );
01250     ENSURE_NO_EVAL_ERROR;
01251     if ( isNull( v2 ) )
01252       listHasNull = true;
01253     else
01254     {
01255       bool equal = false;
01256       // check whether they are equal
01257       if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
01258       {
01259         double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
01260         double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
01261         equal = f1 == f2;
01262       }
01263       else
01264       {
01265         QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR;
01266         QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR;
01267         equal = QString::compare( s1, s2 ) == 0;
01268       }
01269 
01270       if ( equal ) // we know the result
01271         return mNotIn ? TVL_False : TVL_True;
01272     }
01273   }
01274 
01275   // item not found
01276   if ( listHasNull )
01277     return TVL_Unknown;
01278   else
01279     return mNotIn ? TVL_True : TVL_False;
01280 }
01281 
01282 bool QgsExpression::NodeInOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields )
01283 {
01284   bool res = mNode->prepare( parent, fields );
01285   foreach( Node* n, mList->list() )
01286   {
01287     res = res && n->prepare( parent, fields );
01288   }
01289   return res;
01290 }
01291 
01292 QString QgsExpression::NodeInOperator::dump() const
01293 {
01294   return QString( "%1 IN (%2)" ).arg( mNode->dump() ).arg( mList->dump() );
01295 }
01296 
01297 void QgsExpression::NodeInOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01298 {
01299   // XXX use a function instead of multiple comparations?
01300 
01301   QDomElement *parent = &element;
01302 
01303   QDomElement orElem;
01304   if ( mList->list().size() > 1 )
01305   {
01306     orElem = doc.createElement( "ogc:Or" );
01307     element.appendChild( orElem );
01308 
01309     parent = &orElem;
01310   }
01311 
01312   foreach( Node* n, mList->list() )
01313   {
01314     QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqualTo" );
01315     mNode->toOgcFilter( doc, eqElem );
01316     n->toOgcFilter( doc, eqElem );
01317 
01318     parent->appendChild( eqElem );
01319   }
01320 }
01321 
01322 //
01323 
01324 QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, QgsFeature* f )
01325 {
01326   const FunctionDef& fd = BuiltinFunctions()[mFnIndex];
01327 
01328   // evaluate arguments
01329   QVariantList argValues;
01330   if ( mArgs )
01331   {
01332     foreach( Node* n, mArgs->list() )
01333     {
01334       QVariant v = n->eval( parent, f );
01335       ENSURE_NO_EVAL_ERROR;
01336       if ( isNull( v ) )
01337         return QVariant(); // all "normal" functions return NULL when any parameter is NULL
01338       argValues.append( v );
01339     }
01340   }
01341 
01342   // run the function
01343   QVariant res = fd.mFcn( argValues, f, parent );
01344   ENSURE_NO_EVAL_ERROR;
01345 
01346   // everything went fine
01347   return res;
01348 }
01349 
01350 bool QgsExpression::NodeFunction::prepare( QgsExpression* parent, const QgsFieldMap& fields )
01351 {
01352   bool res = true;
01353   if ( mArgs )
01354   {
01355     foreach( Node* n, mArgs->list() )
01356     {
01357       res = res && n->prepare( parent, fields );
01358     }
01359   }
01360   return res;
01361 }
01362 
01363 QString QgsExpression::NodeFunction::dump() const
01364 {
01365   const FunctionDef& fd = BuiltinFunctions()[mFnIndex];
01366   if ( fd.mParams == 0 )
01367     return fd.mName; // special column
01368   else
01369     return QString( "%1(%2)" ).arg( fd.mName ).arg( mArgs ? mArgs->dump() : QString() ); // function
01370 }
01371 
01372 void QgsExpression::NodeFunction::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01373 {
01374   const FunctionDef& fd = BuiltinFunctions()[mFnIndex];
01375   if ( fd.mParams == 0 )
01376     return; // TODO: special column
01377 
01378   QDomElement funcElem = doc.createElement( "ogc:Function" );
01379   funcElem.setAttribute( "name", fd.mName );
01380   mArgs->toOgcFilter( doc, funcElem );
01381   element.appendChild( funcElem );
01382 }
01383 
01384 QgsExpression::Node* QgsExpression::NodeFunction::createFromOgcFilter( QDomElement &element, QString &errorMessage )
01385 {
01386   if ( element.isNull() )
01387     return NULL;
01388 
01389   if ( element.localName() != "Function" )
01390   {
01391     errorMessage = QString( "ogc:Function expected, got %1" ).arg( element.tagName() );
01392     return NULL;
01393   }
01394 
01395   for ( int i = 0; i < BuiltinFunctions().size(); i++ )
01396   {
01397     QgsExpression::FunctionDef funcDef = BuiltinFunctions()[i];
01398 
01399     if ( element.attribute( "name" ) != funcDef.mName )
01400       continue;
01401 
01402     QgsExpression::NodeList *args = new QgsExpression::NodeList();
01403 
01404     QDomElement operandElem = element.firstChildElement();
01405     while ( !operandElem.isNull() )
01406     {
01407       QgsExpression::Node* op = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
01408       if ( !op )
01409       {
01410         delete args;
01411         return NULL;
01412       }
01413       args->append( op );
01414 
01415       operandElem = operandElem.nextSiblingElement();
01416     }
01417 
01418     return new QgsExpression::NodeFunction( i, args );
01419   }
01420 
01421   return NULL;
01422 }
01423 
01424 //
01425 
01426 QVariant QgsExpression::NodeLiteral::eval( QgsExpression* , QgsFeature* )
01427 {
01428   return mValue;
01429 }
01430 
01431 bool QgsExpression::NodeLiteral::prepare( QgsExpression* /*parent*/, const QgsFieldMap& /*fields*/ )
01432 {
01433   return true;
01434 }
01435 
01436 
01437 QString QgsExpression::NodeLiteral::dump() const
01438 {
01439   if ( mValue.isNull() )
01440     return "NULL";
01441 
01442   switch ( mValue.type() )
01443   {
01444     case QVariant::Int: return QString::number( mValue.toInt() );
01445     case QVariant::Double: return QString::number( mValue.toDouble() );
01446     case QVariant::String: return QString( "'%1'" ).arg( mValue.toString() );
01447     default: return QObject::tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName() ).arg( mValue.toString() );
01448   }
01449 }
01450 
01451 void QgsExpression::NodeLiteral::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01452 {
01453   QString value;
01454   if ( !mValue.isNull() )
01455   {
01456     switch ( mValue.type() )
01457     {
01458       case QVariant::Int:
01459         value = QString::number( mValue.toInt() );
01460         break;
01461       case QVariant::Double:
01462         value = QString::number( mValue.toDouble() );
01463         break;
01464       case QVariant::String:
01465         value = mValue.toString();
01466         break;
01467       default:
01468         break;
01469     }
01470   }
01471   QDomElement litElem = doc.createElement( "ogc:Literal" );
01472   litElem.appendChild( doc.createTextNode( value ) );
01473   element.appendChild( litElem );
01474 }
01475 
01476 QgsExpression::Node* QgsExpression::NodeLiteral::createFromOgcFilter( QDomElement &element, QString &errorMessage )
01477 {
01478   if ( element.isNull() )
01479     return NULL;
01480 
01481   if ( element.localName() != "Literal" )
01482   {
01483     errorMessage = QString( "ogc:Literal expected, got %1" ).arg( element.tagName() );
01484     return NULL;
01485   }
01486 
01487   QgsExpression::Node *root = 0;
01488 
01489   // the literal content can have more children (e.g. CDATA section, text, ...)
01490   QDomNode childNode = element.firstChild();
01491   while ( !childNode.isNull() )
01492   {
01493     QgsExpression::Node* operand = 0;
01494 
01495     if ( childNode.nodeType() == QDomNode::ElementNode )
01496     {
01497       // found a element node (e.g. PropertyName), convert it
01498       QDomElement operandElem = childNode.toElement();
01499       operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
01500       if ( !operand )
01501       {
01502         if ( root )
01503           delete root;
01504 
01505         errorMessage = QString( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() );
01506         return NULL;
01507       }
01508     }
01509     else
01510     {
01511       // probably a text/CDATA node, convert its content to string
01512       operand = new QgsExpression::NodeLiteral( childNode.nodeValue() );
01513     }
01514 
01515     if ( !operand )
01516       continue;
01517 
01518     // use the concat operator to merge the ogc:Literal children
01519     if ( !root )
01520     {
01521       root = operand;
01522     }
01523     else
01524     {
01525       root = new QgsExpression::NodeBinaryOperator( boConcat, root, operand );
01526     }
01527 
01528     childNode = childNode.nextSibling();
01529   }
01530 
01531   if ( root )
01532     return root;
01533 
01534   return NULL;
01535 }
01536 
01537 //
01538 
01539 QVariant QgsExpression::NodeColumnRef::eval( QgsExpression* /*parent*/, QgsFeature* f )
01540 {
01541   return f->attributeMap()[mIndex];
01542 }
01543 
01544 bool QgsExpression::NodeColumnRef::prepare( QgsExpression* parent, const QgsFieldMap& fields )
01545 {
01546   foreach( int i, fields.keys() )
01547   {
01548     if ( QString::compare( fields[i].name(), mName, Qt::CaseInsensitive ) == 0 )
01549     {
01550       mIndex = i;
01551       return true;
01552     }
01553   }
01554   parent->mEvalErrorString = QObject::tr( "Column '%1'' not found" ).arg( mName );
01555   mIndex = -1;
01556   return false;
01557 }
01558 
01559 QString QgsExpression::NodeColumnRef::dump() const
01560 {
01561   return mName;
01562 }
01563 
01564 void QgsExpression::NodeColumnRef::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01565 {
01566   QDomElement propElem = doc.createElement( "ogc:PropertyName" );
01567   propElem.appendChild( doc.createTextNode( mName ) );
01568   element.appendChild( propElem );
01569 }
01570 
01571 QgsExpression::Node* QgsExpression::NodeColumnRef::createFromOgcFilter( QDomElement &element, QString &errorMessage )
01572 {
01573   if ( element.isNull() )
01574     return NULL;
01575 
01576   if ( element.localName() != "PropertyName" )
01577   {
01578     errorMessage = QString( "ogc:PropertyName expected, got %1" ).arg( element.tagName() );
01579     return NULL;
01580   }
01581 
01582   return new QgsExpression::NodeColumnRef( element.firstChild().nodeValue() );
01583 }
01584 
01585 //
01586 
01587 QVariant QgsExpression::NodeCondition::eval( QgsExpression* parent, QgsFeature* f )
01588 {
01589   foreach( WhenThen* cond, mConditions )
01590   {
01591     QVariant vWhen = cond->mWhenExp->eval( parent, f );
01592     TVL tvl = getTVLValue( vWhen, parent );
01593     ENSURE_NO_EVAL_ERROR;
01594     if ( tvl == True )
01595     {
01596       QVariant vRes = cond->mThenExp->eval( parent, f );
01597       ENSURE_NO_EVAL_ERROR;
01598       return vRes;
01599     }
01600   }
01601 
01602   if ( mElseExp )
01603   {
01604     QVariant vElse = mElseExp->eval( parent, f );
01605     ENSURE_NO_EVAL_ERROR;
01606     return vElse;
01607   }
01608 
01609   // return NULL if no condition is matching
01610   return QVariant();
01611 }
01612 
01613 bool QgsExpression::NodeCondition::prepare( QgsExpression* parent, const QgsFieldMap& fields )
01614 {
01615   bool res;
01616   foreach( WhenThen* cond, mConditions )
01617   {
01618     res = cond->mWhenExp->prepare( parent, fields )
01619           & cond->mThenExp->prepare( parent, fields );
01620     if ( !res ) return false;
01621   }
01622 
01623   if ( mElseExp )
01624     return mElseExp->prepare( parent, fields );
01625 
01626   return true;
01627 }
01628 
01629 QString QgsExpression::NodeCondition::dump() const
01630 {
01631   QString msg = "CONDITION:\n";
01632   foreach( WhenThen* cond, mConditions )
01633   {
01634     msg += QString( "- WHEN %1 THEN %2\n" ).arg( cond->mWhenExp->dump() ).arg( cond->mThenExp->dump() );
01635   }
01636   if ( mElseExp )
01637     msg += QString( "- ELSE %1" ).arg( mElseExp->dump() );
01638   return msg;
01639 }
01640 
01641 void QgsExpression::NodeCondition::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
01642 {
01643   // TODO: if(cond) ... [else if (cond2) ...]* [else ...]
01644   element.appendChild( doc.createComment( "CASE operator not implemented yet" ) );
01645 }
01646 
01647 QStringList QgsExpression::NodeCondition::referencedColumns() const
01648 {
01649   QStringList lst;
01650   foreach( WhenThen* cond, mConditions )
01651   {
01652     lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
01653   }
01654 
01655   if ( mElseExp )
01656     lst += mElseExp->referencedColumns();
01657 
01658   return lst;
01659 }
01660 
01661 bool QgsExpression::NodeCondition::needsGeometry() const
01662 {
01663   foreach( WhenThen* cond, mConditions )
01664   {
01665     if ( cond->mWhenExp->needsGeometry() ||
01666          cond->mThenExp->needsGeometry() )
01667       return true;
01668   }
01669 
01670   if ( mElseExp && mElseExp->needsGeometry() )
01671     return true;
01672 
01673   return false;
01674 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines