LCOV - code coverage report
Current view: top level - core/expression - qgsexpressionnodeimpl.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 1020 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                                qgsexpressionnodeimpl.cpp
       3                 :            :                              -------------------
       4                 :            :     begin                : May 2017
       5                 :            :     copyright            : (C) 2017 Matthias Kuhn
       6                 :            :     email                : matthias@opengis.ch
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgsexpressionnodeimpl.h"
      17                 :            : #include "qgsexpressionutils.h"
      18                 :            : #include "qgsexpression.h"
      19                 :            : 
      20                 :            : #include "qgsgeometry.h"
      21                 :            : #include "qgsfeaturerequest.h"
      22                 :            : 
      23                 :            : #include <QRegularExpression>
      24                 :            : 
      25                 :            : const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
      26                 :            : {
      27                 :            :   // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
      28                 :            :   "OR", "AND",
      29                 :            :   "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
      30                 :            :   "+", "-", "*", "/", "//", "%", "^",
      31                 :            :   "||"
      32                 :            : };
      33                 :            : 
      34                 :            : const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
      35                 :            : {
      36                 :            :   // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
      37                 :            :   "NOT", "-"
      38                 :            : };
      39                 :            : 
      40                 :          0 : bool QgsExpressionNodeInOperator::needsGeometry() const
      41                 :            : {
      42                 :          0 :   bool needs = false;
      43                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
      44                 :          0 :   for ( QgsExpressionNode *n : nodeList )
      45                 :          0 :     needs |= n->needsGeometry();
      46                 :          0 :   return needs;
      47                 :          0 : }
      48                 :            : 
      49                 :          0 : QgsExpressionNode::NodeList::~NodeList()
      50                 :          0 : {
      51                 :          0 :   qDeleteAll( mList );
      52                 :          0 : }
      53                 :            : 
      54                 :          0 : void QgsExpressionNode::NodeList::append( QgsExpressionNode::NamedNode *node )
      55                 :            : {
      56                 :          0 :   mList.append( node->node );
      57                 :          0 :   mNameList.append( cleanNamedNodeName( node->name ) );
      58                 :          0 :   mHasNamedNodes = true;
      59                 :          0 :   delete node;
      60                 :          0 : }
      61                 :            : 
      62                 :          0 : QgsExpressionNode::NodeList *QgsExpressionNode::NodeList::clone() const
      63                 :            : {
      64                 :          0 :   NodeList *nl = new NodeList;
      65                 :          0 :   for ( QgsExpressionNode *node : mList )
      66                 :            :   {
      67                 :          0 :     nl->mList.append( node->clone() );
      68                 :            :   }
      69                 :          0 :   nl->mNameList = mNameList;
      70                 :            : 
      71                 :          0 :   return nl;
      72                 :            : }
      73                 :            : 
      74                 :          0 : QString QgsExpressionNode::NodeList::dump() const
      75                 :            : {
      76                 :          0 :   QString msg;
      77                 :          0 :   bool first = true;
      78                 :          0 :   for ( QgsExpressionNode *n : mList )
      79                 :            :   {
      80                 :          0 :     if ( !first ) msg += QLatin1String( ", " );
      81                 :          0 :     else first = false;
      82                 :          0 :     msg += n->dump();
      83                 :            :   }
      84                 :          0 :   return msg;
      85                 :          0 : }
      86                 :            : 
      87                 :          0 : QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
      88                 :            : {
      89                 :          0 :   QString cleaned = name.toLower();
      90                 :            : 
      91                 :            :   // upgrade older argument names to standard versions
      92                 :          0 :   if ( cleaned == QLatin1String( "geom" ) )
      93                 :          0 :     cleaned = QStringLiteral( "geometry" );
      94                 :          0 :   else if ( cleaned == QLatin1String( "val" ) )
      95                 :          0 :     cleaned = QStringLiteral( "value" );
      96                 :          0 :   else if ( cleaned == QLatin1String( "geometry a" ) )
      97                 :          0 :     cleaned = QStringLiteral( "geometry1" );
      98                 :          0 :   else if ( cleaned == QLatin1String( "geometry b" ) )
      99                 :          0 :     cleaned = QStringLiteral( "geometry2" );
     100                 :            : 
     101                 :          0 :   return cleaned;
     102                 :          0 : }
     103                 :            : 
     104                 :            : 
     105                 :            : //
     106                 :            : 
     107                 :          0 : QVariant QgsExpressionNodeUnaryOperator::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
     108                 :            : {
     109                 :          0 :   QVariant val = mOperand->eval( parent, context );
     110                 :          0 :   ENSURE_NO_EVAL_ERROR
     111                 :            : 
     112                 :          0 :   switch ( mOp )
     113                 :            :   {
     114                 :            :     case uoNot:
     115                 :            :     {
     116                 :          0 :       QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
     117                 :          0 :       ENSURE_NO_EVAL_ERROR
     118                 :          0 :       return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
     119                 :            :     }
     120                 :            : 
     121                 :            :     case uoMinus:
     122                 :          0 :       if ( QgsExpressionUtils::isIntSafe( val ) )
     123                 :          0 :         return QVariant( - QgsExpressionUtils::getIntValue( val, parent ) );
     124                 :          0 :       else if ( QgsExpressionUtils::isDoubleSafe( val ) )
     125                 :          0 :         return QVariant( - QgsExpressionUtils::getDoubleValue( val, parent ) );
     126                 :            :       else
     127                 :          0 :         SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
     128                 :            :       }
     129                 :          0 :   return QVariant();
     130                 :          0 : }
     131                 :            : 
     132                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeUnaryOperator::nodeType() const
     133                 :            : {
     134                 :          0 :   return ntUnaryOperator;
     135                 :            : }
     136                 :            : 
     137                 :          0 : bool QgsExpressionNodeUnaryOperator::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
     138                 :            : {
     139                 :          0 :   return mOperand->prepare( parent, context );
     140                 :            : }
     141                 :            : 
     142                 :          0 : QString QgsExpressionNodeUnaryOperator::dump() const
     143                 :            : {
     144                 :          0 :   if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand ) )
     145                 :          0 :     return QStringLiteral( "%1 ( %2 )" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
     146                 :            :   else
     147                 :          0 :     return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
     148                 :          0 : }
     149                 :            : 
     150                 :          0 : QSet<QString> QgsExpressionNodeUnaryOperator::referencedColumns() const
     151                 :            : {
     152                 :          0 :   if ( hasCachedStaticValue() )
     153                 :          0 :     return QSet< QString >();
     154                 :            : 
     155                 :          0 :   return mOperand->referencedColumns();
     156                 :          0 : }
     157                 :            : 
     158                 :          0 : QSet<QString> QgsExpressionNodeUnaryOperator::referencedVariables() const
     159                 :            : {
     160                 :          0 :   return mOperand->referencedVariables();
     161                 :            : }
     162                 :            : 
     163                 :          0 : QSet<QString> QgsExpressionNodeUnaryOperator::referencedFunctions() const
     164                 :            : {
     165                 :          0 :   return mOperand->referencedFunctions();
     166                 :            : }
     167                 :            : 
     168                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
     169                 :            : {
     170                 :          0 :   QList<const QgsExpressionNode *> lst;
     171                 :          0 :   lst.append( this );
     172                 :          0 :   lst += mOperand->nodes();
     173                 :          0 :   return lst;
     174                 :          0 : }
     175                 :            : 
     176                 :          0 : bool QgsExpressionNodeUnaryOperator::needsGeometry() const
     177                 :            : {
     178                 :          0 :   return mOperand->needsGeometry();
     179                 :            : }
     180                 :            : 
     181                 :          0 : QgsExpressionNode *QgsExpressionNodeUnaryOperator::clone() const
     182                 :            : {
     183                 :          0 :   QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
     184                 :          0 :   cloneTo( copy );
     185                 :          0 :   return copy;
     186                 :          0 : }
     187                 :            : 
     188                 :          0 : bool QgsExpressionNodeUnaryOperator::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
     189                 :            : {
     190                 :          0 :   return mOperand->isStatic( parent, context );
     191                 :            : }
     192                 :            : 
     193                 :          0 : QString QgsExpressionNodeUnaryOperator::text() const
     194                 :            : {
     195                 :          0 :   return UNARY_OPERATOR_TEXT[mOp];
     196                 :            : }
     197                 :            : 
     198                 :            : //
     199                 :            : 
     200                 :          0 : QVariant QgsExpressionNodeBinaryOperator::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
     201                 :            : {
     202                 :          0 :   QVariant vL = mOpLeft->eval( parent, context );
     203                 :          0 :   ENSURE_NO_EVAL_ERROR
     204                 :            : 
     205                 :          0 :   if ( mOp == boAnd || mOp == boOr )
     206                 :            :   {
     207                 :          0 :     QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
     208                 :          0 :     ENSURE_NO_EVAL_ERROR
     209                 :          0 :     if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
     210                 :          0 :       return TVL_False;  // shortcut -- no need to evaluate right-hand side
     211                 :          0 :     if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
     212                 :          0 :       return TVL_True;  // shortcut -- no need to evaluate right-hand side
     213                 :          0 :   }
     214                 :            : 
     215                 :          0 :   QVariant vR = mOpRight->eval( parent, context );
     216                 :          0 :   ENSURE_NO_EVAL_ERROR
     217                 :            : 
     218                 :          0 :   switch ( mOp )
     219                 :            :   {
     220                 :            :     case boPlus:
     221                 :          0 :       if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
     222                 :            :       {
     223                 :          0 :         QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
     224                 :          0 :         ENSURE_NO_EVAL_ERROR
     225                 :          0 :         QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
     226                 :          0 :         ENSURE_NO_EVAL_ERROR
     227                 :          0 :         return QVariant( sL + sR );
     228                 :          0 :       }
     229                 :            :       //intentional fall-through
     230                 :            :       FALLTHROUGH
     231                 :            :     case boMinus:
     232                 :            :     case boMul:
     233                 :            :     case boDiv:
     234                 :            :     case boMod:
     235                 :            :     {
     236                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
     237                 :          0 :         return QVariant();
     238                 :          0 :       else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
     239                 :            :       {
     240                 :            :         // both are integers - let's use integer arithmetic
     241                 :          0 :         qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
     242                 :          0 :         ENSURE_NO_EVAL_ERROR
     243                 :          0 :         qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
     244                 :          0 :         ENSURE_NO_EVAL_ERROR
     245                 :            : 
     246                 :          0 :         if ( mOp == boMod && iR == 0 )
     247                 :          0 :           return QVariant();
     248                 :            : 
     249                 :          0 :         return QVariant( computeInt( iL, iR ) );
     250                 :            :       }
     251                 :          0 :       else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
     252                 :            :       {
     253                 :          0 :         QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
     254                 :          0 :         ENSURE_NO_EVAL_ERROR
     255                 :          0 :         QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
     256                 :          0 :         ENSURE_NO_EVAL_ERROR
     257                 :          0 :         if ( mOp == boDiv || mOp == boMul || mOp == boMod )
     258                 :            :         {
     259                 :          0 :           parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
     260                 :          0 :           return QVariant();
     261                 :            :         }
     262                 :          0 :         return QVariant( computeDateTimeFromInterval( dL, &iL ) );
     263                 :          0 :       }
     264                 :          0 :       else if ( mOp == boPlus && ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
     265                 :          0 :                                    ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
     266                 :            :       {
     267                 :          0 :         QDate date = QgsExpressionUtils::getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
     268                 :          0 :         ENSURE_NO_EVAL_ERROR
     269                 :          0 :         QTime time = QgsExpressionUtils::getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
     270                 :          0 :         ENSURE_NO_EVAL_ERROR
     271                 :          0 :         QDateTime dt = QDateTime( date, time );
     272                 :          0 :         return QVariant( dt );
     273                 :          0 :       }
     274                 :          0 :       else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
     275                 :            :       {
     276                 :          0 :         QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
     277                 :          0 :         ENSURE_NO_EVAL_ERROR
     278                 :          0 :         QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
     279                 :          0 :         ENSURE_NO_EVAL_ERROR
     280                 :          0 :         return date1 - date2;
     281                 :            :       }
     282                 :          0 :       else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
     283                 :            :       {
     284                 :          0 :         QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
     285                 :          0 :         ENSURE_NO_EVAL_ERROR
     286                 :          0 :         QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
     287                 :          0 :         ENSURE_NO_EVAL_ERROR
     288                 :          0 :         return time1 - time2;
     289                 :            :       }
     290                 :          0 :       else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
     291                 :            :       {
     292                 :          0 :         QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
     293                 :          0 :         ENSURE_NO_EVAL_ERROR
     294                 :          0 :         QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
     295                 :          0 :         ENSURE_NO_EVAL_ERROR
     296                 :          0 :         return datetime1 - datetime2;
     297                 :          0 :       }
     298                 :            :       else
     299                 :            :       {
     300                 :            :         // general floating point arithmetic
     301                 :          0 :         double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
     302                 :          0 :         ENSURE_NO_EVAL_ERROR
     303                 :          0 :         double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
     304                 :          0 :         ENSURE_NO_EVAL_ERROR
     305                 :          0 :         if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
     306                 :          0 :           return QVariant(); // silently handle division by zero and return NULL
     307                 :          0 :         return QVariant( computeDouble( fL, fR ) );
     308                 :            :       }
     309                 :            :     }
     310                 :            :     case boIntDiv:
     311                 :            :     {
     312                 :            :       //integer division
     313                 :          0 :       double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
     314                 :          0 :       ENSURE_NO_EVAL_ERROR
     315                 :          0 :       double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
     316                 :          0 :       ENSURE_NO_EVAL_ERROR
     317                 :          0 :       if ( fR == 0. )
     318                 :          0 :         return QVariant(); // silently handle division by zero and return NULL
     319                 :          0 :       return QVariant( qlonglong( std::floor( fL / fR ) ) );
     320                 :            :     }
     321                 :            :     case boPow:
     322                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
     323                 :          0 :         return QVariant();
     324                 :            :       else
     325                 :            :       {
     326                 :          0 :         double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
     327                 :          0 :         ENSURE_NO_EVAL_ERROR
     328                 :          0 :         double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
     329                 :          0 :         ENSURE_NO_EVAL_ERROR
     330                 :          0 :         return QVariant( std::pow( fL, fR ) );
     331                 :            :       }
     332                 :            : 
     333                 :            :     case boAnd:
     334                 :            :     {
     335                 :          0 :       QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
     336                 :          0 :       ENSURE_NO_EVAL_ERROR
     337                 :          0 :       return  QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
     338                 :            :     }
     339                 :            : 
     340                 :            :     case boOr:
     341                 :            :     {
     342                 :          0 :       QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
     343                 :          0 :       ENSURE_NO_EVAL_ERROR
     344                 :          0 :       return  QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
     345                 :            :     }
     346                 :            : 
     347                 :            :     case boEQ:
     348                 :            :     case boNE:
     349                 :            :     case boLT:
     350                 :            :     case boGT:
     351                 :            :     case boLE:
     352                 :            :     case boGE:
     353                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
     354                 :            :       {
     355                 :          0 :         return TVL_Unknown;
     356                 :            :       }
     357                 :          0 :       else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
     358                 :            :       {
     359                 :            :         // verify that we have two lists
     360                 :          0 :         if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
     361                 :          0 :           return TVL_Unknown;
     362                 :            : 
     363                 :            :         // and search for not equal respective items
     364                 :          0 :         QVariantList lL = vL.toList();
     365                 :          0 :         QVariantList lR = vR.toList();
     366                 :          0 :         for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
     367                 :            :         {
     368                 :          0 :           if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
     369                 :          0 :             continue;  // same behavior as PostgreSQL
     370                 :            : 
     371                 :          0 :           if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
     372                 :            :           {
     373                 :          0 :             switch ( mOp )
     374                 :            :             {
     375                 :            :               case boEQ:
     376                 :          0 :                 return false;
     377                 :            :               case boNE:
     378                 :          0 :                 return true;
     379                 :            :               case boLT:
     380                 :            :               case boLE:
     381                 :          0 :                 return QgsExpressionUtils::isNull( lR.at( i ) );
     382                 :            :               case boGT:
     383                 :            :               case boGE:
     384                 :          0 :                 return QgsExpressionUtils::isNull( lL.at( i ) );
     385                 :            :               default:
     386                 :            :                 Q_ASSERT( false );
     387                 :          0 :                 return TVL_Unknown;
     388                 :            :             }
     389                 :            :           }
     390                 :            : 
     391                 :          0 :           QgsExpressionNodeLiteral nL( lL.at( i ) );
     392                 :          0 :           QgsExpressionNodeLiteral nR( lR.at( i ) );
     393                 :          0 :           QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
     394                 :          0 :           QVariant eq = eqNode.eval( parent, context );
     395                 :          0 :           ENSURE_NO_EVAL_ERROR
     396                 :          0 :           if ( eq == TVL_False )
     397                 :            :           {
     398                 :            :             // return the two items comparison
     399                 :          0 :             QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
     400                 :          0 :             QVariant v = node.eval( parent, context );
     401                 :          0 :             ENSURE_NO_EVAL_ERROR
     402                 :          0 :             return v;
     403                 :          0 :           }
     404                 :          0 :         }
     405                 :            : 
     406                 :            :         // default to length comparison
     407                 :          0 :         switch ( mOp )
     408                 :            :         {
     409                 :            :           case boEQ:
     410                 :          0 :             return lL.length() == lR.length();
     411                 :            :           case boNE:
     412                 :          0 :             return lL.length() != lR.length();
     413                 :            :           case boLT:
     414                 :          0 :             return lL.length() < lR.length();
     415                 :            :           case boGT:
     416                 :          0 :             return lL.length() > lR.length();
     417                 :            :           case boLE:
     418                 :          0 :             return lL.length() <= lR.length();
     419                 :            :           case boGE:
     420                 :          0 :             return lL.length() >= lR.length();
     421                 :            :           default:
     422                 :            :             Q_ASSERT( false );
     423                 :          0 :             return TVL_Unknown;
     424                 :            :         }
     425                 :          0 :       }
     426                 :          0 :       else if ( ( vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime ) )
     427                 :            :       {
     428                 :          0 :         QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
     429                 :          0 :         ENSURE_NO_EVAL_ERROR
     430                 :          0 :         QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
     431                 :          0 :         ENSURE_NO_EVAL_ERROR
     432                 :            : 
     433                 :            :         // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
     434                 :            :         // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
     435                 :            :         // results (due to different hidden timezones), we force all datetime comparisons to treat
     436                 :            :         // all datetime values as having the same time zone
     437                 :          0 :         dL.setTimeSpec( Qt::UTC );
     438                 :          0 :         dR.setTimeSpec( Qt::UTC );
     439                 :            : 
     440                 :          0 :         return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
     441                 :          0 :       }
     442                 :          0 :       else if ( ( vL.type() == QVariant::Date && vR.type() == QVariant::Date ) )
     443                 :            :       {
     444                 :          0 :         const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
     445                 :          0 :         ENSURE_NO_EVAL_ERROR
     446                 :          0 :         const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
     447                 :          0 :         ENSURE_NO_EVAL_ERROR
     448                 :          0 :         return compare( dR.daysTo( dL ) ) ? TVL_True : TVL_False;
     449                 :            :       }
     450                 :          0 :       else if ( ( vL.type() == QVariant::Time && vR.type() == QVariant::Time ) )
     451                 :            :       {
     452                 :          0 :         const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
     453                 :          0 :         ENSURE_NO_EVAL_ERROR
     454                 :          0 :         const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
     455                 :          0 :         ENSURE_NO_EVAL_ERROR
     456                 :          0 :         return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
     457                 :            :       }
     458                 :          0 :       else if ( ( vL.type() != QVariant::String || vR.type() != QVariant::String ) &&
     459                 :          0 :                 QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
     460                 :            :       {
     461                 :            :         // do numeric comparison if both operators can be converted to numbers,
     462                 :            :         // and they aren't both string
     463                 :          0 :         double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
     464                 :          0 :         ENSURE_NO_EVAL_ERROR
     465                 :          0 :         double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
     466                 :          0 :         ENSURE_NO_EVAL_ERROR
     467                 :          0 :         return compare( fL - fR ) ? TVL_True : TVL_False;
     468                 :            :       }
     469                 :            :       // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
     470                 :          0 :       else if ( vL.canConvert< QgsInterval >() && vR.canConvert< QgsInterval >() )
     471                 :            :       {
     472                 :          0 :         double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
     473                 :          0 :         ENSURE_NO_EVAL_ERROR
     474                 :          0 :         double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
     475                 :          0 :         ENSURE_NO_EVAL_ERROR
     476                 :          0 :         return compare( fL - fR ) ? TVL_True : TVL_False;
     477                 :            :       }
     478                 :            :       else
     479                 :            :       {
     480                 :            :         // do string comparison otherwise
     481                 :          0 :         QString sL = QgsExpressionUtils::getStringValue( vL, parent );
     482                 :          0 :         ENSURE_NO_EVAL_ERROR
     483                 :          0 :         QString sR = QgsExpressionUtils::getStringValue( vR, parent );
     484                 :          0 :         ENSURE_NO_EVAL_ERROR
     485                 :          0 :         int diff = QString::compare( sL, sR );
     486                 :          0 :         return compare( diff ) ? TVL_True : TVL_False;
     487                 :          0 :       }
     488                 :            : 
     489                 :            :     case boIs:
     490                 :            :     case boIsNot:
     491                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
     492                 :          0 :         return ( mOp == boIs ? TVL_True : TVL_False );
     493                 :          0 :       else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
     494                 :          0 :         return ( mOp == boIs ? TVL_False : TVL_True );
     495                 :            :       else // both operators non-null
     496                 :            :       {
     497                 :          0 :         bool equal = false;
     498                 :          0 :         if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
     499                 :          0 :              ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
     500                 :            :         {
     501                 :          0 :           double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
     502                 :          0 :           ENSURE_NO_EVAL_ERROR
     503                 :          0 :           double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
     504                 :          0 :           ENSURE_NO_EVAL_ERROR
     505                 :          0 :           equal = qgsDoubleNear( fL, fR );
     506                 :          0 :         }
     507                 :            :         else
     508                 :            :         {
     509                 :          0 :           QString sL = QgsExpressionUtils::getStringValue( vL, parent );
     510                 :          0 :           ENSURE_NO_EVAL_ERROR
     511                 :          0 :           QString sR = QgsExpressionUtils::getStringValue( vR, parent );
     512                 :          0 :           ENSURE_NO_EVAL_ERROR
     513                 :          0 :           equal = QString::compare( sL, sR ) == 0;
     514                 :          0 :         }
     515                 :          0 :         if ( equal )
     516                 :          0 :           return mOp == boIs ? TVL_True : TVL_False;
     517                 :            :         else
     518                 :          0 :           return mOp == boIs ? TVL_False : TVL_True;
     519                 :            :       }
     520                 :            : 
     521                 :            :     case boRegexp:
     522                 :            :     case boLike:
     523                 :            :     case boNotLike:
     524                 :            :     case boILike:
     525                 :            :     case boNotILike:
     526                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
     527                 :          0 :         return TVL_Unknown;
     528                 :            :       else
     529                 :            :       {
     530                 :          0 :         QString str    = QgsExpressionUtils::getStringValue( vL, parent );
     531                 :          0 :         ENSURE_NO_EVAL_ERROR
     532                 :          0 :         QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
     533                 :          0 :         ENSURE_NO_EVAL_ERROR
     534                 :            :         // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
     535                 :            :         bool matches;
     536                 :          0 :         if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
     537                 :            :         {
     538                 :          0 :           QString esc_regexp = QRegExp::escape( regexp );
     539                 :            :           // manage escape % and _
     540                 :          0 :           if ( esc_regexp.startsWith( '%' ) )
     541                 :            :           {
     542                 :          0 :             esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
     543                 :          0 :           }
     544                 :          0 :           thread_local QRegExp rx1( QStringLiteral( "[^\\\\](%)" ) );
     545                 :          0 :           int pos = 0;
     546                 :          0 :           while ( ( pos = rx1.indexIn( esc_regexp, pos ) ) != -1 )
     547                 :            :           {
     548                 :          0 :             esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
     549                 :          0 :             pos += 1;
     550                 :            :           }
     551                 :          0 :           thread_local QRegExp rx2( QStringLiteral( "\\\\%" ) );
     552                 :          0 :           esc_regexp.replace( rx2, QStringLiteral( "%" ) );
     553                 :          0 :           if ( esc_regexp.startsWith( '_' ) )
     554                 :            :           {
     555                 :          0 :             esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
     556                 :          0 :           }
     557                 :          0 :           thread_local QRegExp rx3( QStringLiteral( "[^\\\\](_)" ) );
     558                 :          0 :           pos = 0;
     559                 :          0 :           while ( ( pos = rx3.indexIn( esc_regexp, pos ) ) != -1 )
     560                 :            :           {
     561                 :          0 :             esc_regexp.replace( pos + 1, 1, '.' );
     562                 :          0 :             pos += 1;
     563                 :            :           }
     564                 :          0 :           esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
     565                 :            : 
     566                 :          0 :           matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
     567                 :          0 :         }
     568                 :            :         else
     569                 :            :         {
     570                 :          0 :           matches = QRegularExpression( regexp ).match( str ).hasMatch();
     571                 :            :         }
     572                 :            : 
     573                 :          0 :         if ( mOp == boNotLike || mOp == boNotILike )
     574                 :            :         {
     575                 :          0 :           matches = !matches;
     576                 :          0 :         }
     577                 :            : 
     578                 :          0 :         return matches ? TVL_True : TVL_False;
     579                 :          0 :       }
     580                 :            : 
     581                 :            :     case boConcat:
     582                 :          0 :       if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
     583                 :          0 :         return QVariant();
     584                 :            :       else
     585                 :            :       {
     586                 :          0 :         QString sL = QgsExpressionUtils::getStringValue( vL, parent );
     587                 :          0 :         ENSURE_NO_EVAL_ERROR
     588                 :          0 :         QString sR = QgsExpressionUtils::getStringValue( vR, parent );
     589                 :          0 :         ENSURE_NO_EVAL_ERROR
     590                 :          0 :         return QVariant( sL + sR );
     591                 :          0 :       }
     592                 :            :   }
     593                 :            :   Q_ASSERT( false );
     594                 :          0 :   return QVariant();
     595                 :          0 : }
     596                 :            : 
     597                 :          0 : bool QgsExpressionNodeBinaryOperator::compare( double diff )
     598                 :            : {
     599                 :          0 :   switch ( mOp )
     600                 :            :   {
     601                 :            :     case boEQ:
     602                 :          0 :       return qgsDoubleNear( diff, 0.0 );
     603                 :            :     case boNE:
     604                 :          0 :       return !qgsDoubleNear( diff, 0.0 );
     605                 :            :     case boLT:
     606                 :          0 :       return diff < 0;
     607                 :            :     case boGT:
     608                 :          0 :       return diff > 0;
     609                 :            :     case boLE:
     610                 :          0 :       return diff <= 0;
     611                 :            :     case boGE:
     612                 :          0 :       return diff >= 0;
     613                 :            :     default:
     614                 :            :       Q_ASSERT( false );
     615                 :          0 :       return false;
     616                 :            :   }
     617                 :          0 : }
     618                 :            : 
     619                 :          0 : qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
     620                 :            : {
     621                 :          0 :   switch ( mOp )
     622                 :            :   {
     623                 :            :     case boPlus:
     624                 :          0 :       return x + y;
     625                 :            :     case boMinus:
     626                 :          0 :       return x - y;
     627                 :            :     case boMul:
     628                 :          0 :       return x * y;
     629                 :            :     case boDiv:
     630                 :          0 :       return x / y;
     631                 :            :     case boMod:
     632                 :          0 :       return x % y;
     633                 :            :     default:
     634                 :            :       Q_ASSERT( false );
     635                 :          0 :       return 0;
     636                 :            :   }
     637                 :          0 : }
     638                 :            : 
     639                 :          0 : QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
     640                 :            : {
     641                 :          0 :   switch ( mOp )
     642                 :            :   {
     643                 :            :     case boPlus:
     644                 :          0 :       return d.addSecs( i->seconds() );
     645                 :            :     case boMinus:
     646                 :          0 :       return d.addSecs( -i->seconds() );
     647                 :            :     default:
     648                 :            :       Q_ASSERT( false );
     649                 :          0 :       return QDateTime();
     650                 :            :   }
     651                 :          0 : }
     652                 :            : 
     653                 :          0 : double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
     654                 :            : {
     655                 :          0 :   switch ( mOp )
     656                 :            :   {
     657                 :            :     case boPlus:
     658                 :          0 :       return x + y;
     659                 :            :     case boMinus:
     660                 :          0 :       return x - y;
     661                 :            :     case boMul:
     662                 :          0 :       return x * y;
     663                 :            :     case boDiv:
     664                 :          0 :       return x / y;
     665                 :            :     case boMod:
     666                 :          0 :       return std::fmod( x, y );
     667                 :            :     default:
     668                 :            :       Q_ASSERT( false );
     669                 :          0 :       return 0;
     670                 :            :   }
     671                 :          0 : }
     672                 :            : 
     673                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeBinaryOperator::nodeType() const
     674                 :            : {
     675                 :          0 :   return ntBinaryOperator;
     676                 :            : }
     677                 :            : 
     678                 :          0 : bool QgsExpressionNodeBinaryOperator::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
     679                 :            : {
     680                 :          0 :   bool resL = mOpLeft->prepare( parent, context );
     681                 :          0 :   bool resR = mOpRight->prepare( parent, context );
     682                 :          0 :   return resL && resR;
     683                 :            : }
     684                 :            : 
     685                 :          0 : int QgsExpressionNodeBinaryOperator::precedence() const
     686                 :            : {
     687                 :            :   // see left/right in qgsexpressionparser.yy
     688                 :          0 :   switch ( mOp )
     689                 :            :   {
     690                 :            :     case boOr:
     691                 :          0 :       return 1;
     692                 :            : 
     693                 :            :     case boAnd:
     694                 :          0 :       return 2;
     695                 :            : 
     696                 :            :     case boEQ:
     697                 :            :     case boNE:
     698                 :            :     case boLE:
     699                 :            :     case boGE:
     700                 :            :     case boLT:
     701                 :            :     case boGT:
     702                 :            :     case boRegexp:
     703                 :            :     case boLike:
     704                 :            :     case boILike:
     705                 :            :     case boNotLike:
     706                 :            :     case boNotILike:
     707                 :            :     case boIs:
     708                 :            :     case boIsNot:
     709                 :          0 :       return 3;
     710                 :            : 
     711                 :            :     case boPlus:
     712                 :            :     case boMinus:
     713                 :          0 :       return 4;
     714                 :            : 
     715                 :            :     case boMul:
     716                 :            :     case boDiv:
     717                 :            :     case boIntDiv:
     718                 :            :     case boMod:
     719                 :          0 :       return 5;
     720                 :            : 
     721                 :            :     case boPow:
     722                 :          0 :       return 6;
     723                 :            : 
     724                 :            :     case boConcat:
     725                 :          0 :       return 7;
     726                 :            :   }
     727                 :            :   Q_ASSERT( false && "unexpected binary operator" );
     728                 :          0 :   return -1;
     729                 :          0 : }
     730                 :            : 
     731                 :          0 : bool QgsExpressionNodeBinaryOperator::leftAssociative() const
     732                 :            : {
     733                 :            :   // see left/right in qgsexpressionparser.yy
     734                 :          0 :   switch ( mOp )
     735                 :            :   {
     736                 :            :     case boOr:
     737                 :            :     case boAnd:
     738                 :            :     case boEQ:
     739                 :            :     case boNE:
     740                 :            :     case boLE:
     741                 :            :     case boGE:
     742                 :            :     case boLT:
     743                 :            :     case boGT:
     744                 :            :     case boRegexp:
     745                 :            :     case boLike:
     746                 :            :     case boILike:
     747                 :            :     case boNotLike:
     748                 :            :     case boNotILike:
     749                 :            :     case boIs:
     750                 :            :     case boIsNot:
     751                 :            :     case boPlus:
     752                 :            :     case boMinus:
     753                 :            :     case boMul:
     754                 :            :     case boDiv:
     755                 :            :     case boIntDiv:
     756                 :            :     case boMod:
     757                 :            :     case boConcat:
     758                 :          0 :       return true;
     759                 :            : 
     760                 :            :     case boPow:
     761                 :          0 :       return false;
     762                 :            :   }
     763                 :            :   Q_ASSERT( false && "unexpected binary operator" );
     764                 :          0 :   return false;
     765                 :          0 : }
     766                 :            : 
     767                 :          0 : QString QgsExpressionNodeBinaryOperator::dump() const
     768                 :            : {
     769                 :          0 :   QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft );
     770                 :          0 :   QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
     771                 :          0 :   QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
     772                 :            : 
     773                 :          0 :   QString rdump( mOpRight->dump() );
     774                 :            : 
     775                 :            :   // avoid dumping "IS (NOT ...)" as "IS NOT ..."
     776                 :          0 :   if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
     777                 :            :   {
     778                 :          0 :     rdump.prepend( '(' ).append( ')' );
     779                 :          0 :   }
     780                 :            : 
     781                 :          0 :   QString fmt;
     782                 :          0 :   if ( leftAssociative() )
     783                 :            :   {
     784                 :          0 :     fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
     785                 :          0 :     fmt += QLatin1String( " %2 " );
     786                 :          0 :     fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
     787                 :          0 :   }
     788                 :            :   else
     789                 :            :   {
     790                 :          0 :     fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
     791                 :          0 :     fmt += QLatin1String( " %2 " );
     792                 :          0 :     fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
     793                 :            :   }
     794                 :            : 
     795                 :          0 :   return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
     796                 :          0 : }
     797                 :            : 
     798                 :          0 : QSet<QString> QgsExpressionNodeBinaryOperator::referencedColumns() const
     799                 :            : {
     800                 :          0 :   if ( hasCachedStaticValue() )
     801                 :          0 :     return QSet< QString >();
     802                 :            : 
     803                 :          0 :   return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
     804                 :          0 : }
     805                 :            : 
     806                 :          0 : QSet<QString> QgsExpressionNodeBinaryOperator::referencedVariables() const
     807                 :            : {
     808                 :          0 :   return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
     809                 :          0 : }
     810                 :            : 
     811                 :          0 : QSet<QString> QgsExpressionNodeBinaryOperator::referencedFunctions() const
     812                 :            : {
     813                 :          0 :   return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
     814                 :          0 : }
     815                 :            : 
     816                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
     817                 :            : {
     818                 :          0 :   QList<const QgsExpressionNode *> lst;
     819                 :          0 :   lst << this;
     820                 :          0 :   lst += mOpLeft->nodes() + mOpRight->nodes();
     821                 :          0 :   return lst;
     822                 :          0 : }
     823                 :            : 
     824                 :          0 : bool QgsExpressionNodeBinaryOperator::needsGeometry() const
     825                 :            : {
     826                 :          0 :   return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
     827                 :            : }
     828                 :            : 
     829                 :          0 : QgsExpressionNode *QgsExpressionNodeBinaryOperator::clone() const
     830                 :            : {
     831                 :          0 :   QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
     832                 :          0 :   cloneTo( copy );
     833                 :          0 :   return copy;
     834                 :          0 : }
     835                 :            : 
     836                 :          0 : bool QgsExpressionNodeBinaryOperator::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
     837                 :            : {
     838                 :          0 :   const bool leftStatic = mOpLeft->isStatic( parent, context );
     839                 :          0 :   const bool rightStatic = mOpRight->isStatic( parent, context );
     840                 :            : 
     841                 :          0 :   if ( leftStatic && rightStatic )
     842                 :          0 :     return true;
     843                 :            : 
     844                 :            :   // special logic for certain ops...
     845                 :          0 :   switch ( mOp )
     846                 :            :   {
     847                 :            :     case QgsExpressionNodeBinaryOperator::boOr:
     848                 :            :     {
     849                 :            :       // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
     850                 :            :       // of the value of the other node!
     851                 :          0 :       if ( leftStatic )
     852                 :            :       {
     853                 :          0 :         mOpLeft->prepare( parent, context );
     854                 :          0 :         if ( mOpLeft->hasCachedStaticValue() )
     855                 :            :         {
     856                 :          0 :           QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
     857                 :          0 :           if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
     858                 :            :           {
     859                 :          0 :             mCachedStaticValue = true;
     860                 :          0 :             mHasCachedValue = true;
     861                 :          0 :             return true;
     862                 :            :           }
     863                 :          0 :         }
     864                 :          0 :       }
     865                 :          0 :       else if ( rightStatic )
     866                 :            :       {
     867                 :          0 :         mOpRight->prepare( parent, context );
     868                 :          0 :         if ( mOpRight->hasCachedStaticValue() )
     869                 :            :         {
     870                 :          0 :           QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
     871                 :          0 :           if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
     872                 :            :           {
     873                 :          0 :             mCachedStaticValue = true;
     874                 :          0 :             mHasCachedValue = true;
     875                 :          0 :             return true;
     876                 :            :           }
     877                 :          0 :         }
     878                 :          0 :       }
     879                 :            : 
     880                 :          0 :       break;
     881                 :            :     }
     882                 :            :     case QgsExpressionNodeBinaryOperator::boAnd:
     883                 :            :     {
     884                 :            :       // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
     885                 :            :       // of the value of the other node!
     886                 :            : 
     887                 :          0 :       if ( leftStatic )
     888                 :            :       {
     889                 :          0 :         mOpLeft->prepare( parent, context );
     890                 :          0 :         if ( mOpLeft->hasCachedStaticValue() )
     891                 :            :         {
     892                 :          0 :           QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
     893                 :          0 :           if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
     894                 :            :           {
     895                 :          0 :             mCachedStaticValue = false;
     896                 :          0 :             mHasCachedValue = true;
     897                 :          0 :             return true;
     898                 :            :           }
     899                 :          0 :         }
     900                 :          0 :       }
     901                 :          0 :       else if ( rightStatic )
     902                 :            :       {
     903                 :          0 :         mOpRight->prepare( parent, context );
     904                 :          0 :         if ( mOpRight->hasCachedStaticValue() )
     905                 :            :         {
     906                 :          0 :           QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
     907                 :          0 :           if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
     908                 :            :           {
     909                 :          0 :             mCachedStaticValue = false;
     910                 :          0 :             mHasCachedValue = true;
     911                 :          0 :             return true;
     912                 :            :           }
     913                 :          0 :         }
     914                 :          0 :       }
     915                 :            : 
     916                 :          0 :       break;
     917                 :            :     }
     918                 :            : 
     919                 :            :     case QgsExpressionNodeBinaryOperator::boEQ:
     920                 :            :     case QgsExpressionNodeBinaryOperator::boNE:
     921                 :            :     case QgsExpressionNodeBinaryOperator::boLE:
     922                 :            :     case QgsExpressionNodeBinaryOperator::boGE:
     923                 :            :     case QgsExpressionNodeBinaryOperator::boLT:
     924                 :            :     case QgsExpressionNodeBinaryOperator::boGT:
     925                 :            :     case QgsExpressionNodeBinaryOperator::boRegexp:
     926                 :            :     case QgsExpressionNodeBinaryOperator::boLike:
     927                 :            :     case QgsExpressionNodeBinaryOperator::boNotLike:
     928                 :            :     case QgsExpressionNodeBinaryOperator::boILike:
     929                 :            :     case QgsExpressionNodeBinaryOperator::boNotILike:
     930                 :            :     case QgsExpressionNodeBinaryOperator::boIs:
     931                 :            :     case QgsExpressionNodeBinaryOperator::boIsNot:
     932                 :            :     case QgsExpressionNodeBinaryOperator::boPlus:
     933                 :            :     case QgsExpressionNodeBinaryOperator::boMinus:
     934                 :            :     case QgsExpressionNodeBinaryOperator::boMul:
     935                 :            :     case QgsExpressionNodeBinaryOperator::boDiv:
     936                 :            :     case QgsExpressionNodeBinaryOperator::boIntDiv:
     937                 :            :     case QgsExpressionNodeBinaryOperator::boMod:
     938                 :            :     case QgsExpressionNodeBinaryOperator::boPow:
     939                 :            :     case QgsExpressionNodeBinaryOperator::boConcat:
     940                 :          0 :       break;
     941                 :            :   }
     942                 :            : 
     943                 :          0 :   return false;
     944                 :          0 : }
     945                 :            : 
     946                 :            : //
     947                 :            : 
     948                 :          0 : QVariant QgsExpressionNodeInOperator::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
     949                 :            : {
     950                 :          0 :   if ( mList->count() == 0 )
     951                 :          0 :     return mNotIn ? TVL_True : TVL_False;
     952                 :          0 :   QVariant v1 = mNode->eval( parent, context );
     953                 :          0 :   ENSURE_NO_EVAL_ERROR
     954                 :          0 :   if ( QgsExpressionUtils::isNull( v1 ) )
     955                 :          0 :     return TVL_Unknown;
     956                 :            : 
     957                 :          0 :   bool listHasNull = false;
     958                 :            : 
     959                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
     960                 :          0 :   for ( QgsExpressionNode *n : nodeList )
     961                 :            :   {
     962                 :          0 :     QVariant v2 = n->eval( parent, context );
     963                 :          0 :     ENSURE_NO_EVAL_ERROR
     964                 :          0 :     if ( QgsExpressionUtils::isNull( v2 ) )
     965                 :          0 :       listHasNull = true;
     966                 :            :     else
     967                 :            :     {
     968                 :          0 :       bool equal = false;
     969                 :            :       // check whether they are equal
     970                 :          0 :       if ( ( v1.type() != QVariant::String || v2.type() != QVariant::String ) &&
     971                 :          0 :            QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
     972                 :            :       {
     973                 :            :         // do numeric comparison if both operators can be converted to numbers,
     974                 :            :         // and they aren't both string
     975                 :          0 :         double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
     976                 :          0 :         ENSURE_NO_EVAL_ERROR
     977                 :          0 :         double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
     978                 :          0 :         ENSURE_NO_EVAL_ERROR
     979                 :          0 :         equal = qgsDoubleNear( f1, f2 );
     980                 :          0 :       }
     981                 :            :       else
     982                 :            :       {
     983                 :          0 :         QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
     984                 :          0 :         ENSURE_NO_EVAL_ERROR
     985                 :          0 :         QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
     986                 :          0 :         ENSURE_NO_EVAL_ERROR
     987                 :          0 :         equal = QString::compare( s1, s2 ) == 0;
     988                 :          0 :       }
     989                 :            : 
     990                 :          0 :       if ( equal ) // we know the result
     991                 :          0 :         return mNotIn ? TVL_False : TVL_True;
     992                 :            :     }
     993                 :          0 :   }
     994                 :            : 
     995                 :            :   // item not found
     996                 :          0 :   if ( listHasNull )
     997                 :          0 :     return TVL_Unknown;
     998                 :            :   else
     999                 :          0 :     return mNotIn ? TVL_True : TVL_False;
    1000                 :          0 : }
    1001                 :            : 
    1002                 :          0 : QgsExpressionNodeInOperator::~QgsExpressionNodeInOperator()
    1003                 :          0 : {
    1004                 :          0 :   delete mNode;
    1005                 :          0 :   delete mList;
    1006                 :          0 : }
    1007                 :            : 
    1008                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeInOperator::nodeType() const
    1009                 :            : {
    1010                 :          0 :   return ntInOperator;
    1011                 :            : }
    1012                 :            : 
    1013                 :          0 : bool QgsExpressionNodeInOperator::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1014                 :            : {
    1015                 :          0 :   bool res = mNode->prepare( parent, context );
    1016                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1017                 :          0 :   for ( QgsExpressionNode *n : nodeList )
    1018                 :            :   {
    1019                 :          0 :     res = res && n->prepare( parent, context );
    1020                 :            :   }
    1021                 :          0 :   return res;
    1022                 :          0 : }
    1023                 :            : 
    1024                 :          0 : QString QgsExpressionNodeInOperator::dump() const
    1025                 :            : {
    1026                 :          0 :   return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
    1027                 :          0 : }
    1028                 :            : 
    1029                 :          0 : QgsExpressionNode *QgsExpressionNodeInOperator::clone() const
    1030                 :            : {
    1031                 :          0 :   QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
    1032                 :          0 :   cloneTo( copy );
    1033                 :          0 :   return copy;
    1034                 :          0 : }
    1035                 :            : 
    1036                 :          0 : bool QgsExpressionNodeInOperator::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1037                 :            : {
    1038                 :          0 :   if ( !mNode->isStatic( parent, context ) )
    1039                 :          0 :     return false;
    1040                 :            : 
    1041                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1042                 :          0 :   for ( QgsExpressionNode *n : nodeList )
    1043                 :            :   {
    1044                 :          0 :     if ( !n->isStatic( parent, context ) )
    1045                 :          0 :       return false;
    1046                 :            :   }
    1047                 :            : 
    1048                 :          0 :   return true;
    1049                 :          0 : }
    1050                 :            : 
    1051                 :            : //
    1052                 :            : 
    1053                 :          0 : QVariant QgsExpressionNodeFunction::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
    1054                 :            : {
    1055                 :          0 :   QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
    1056                 :          0 :   QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
    1057                 :            : 
    1058                 :          0 :   QVariant res = fd->run( mArgs, context, parent, this );
    1059                 :          0 :   ENSURE_NO_EVAL_ERROR
    1060                 :            : 
    1061                 :            :   // everything went fine
    1062                 :          0 :   return res;
    1063                 :          0 : }
    1064                 :            : 
    1065                 :          0 : QgsExpressionNodeFunction::QgsExpressionNodeFunction( int fnIndex, QgsExpressionNode::NodeList *args )
    1066                 :          0 :   : mFnIndex( fnIndex )
    1067                 :          0 : {
    1068                 :          0 :   const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
    1069                 :          0 :   if ( !args || functionParams.isEmpty() )
    1070                 :            :   {
    1071                 :            :     // no QgsExpressionFunction::Parameters, or function does not support them
    1072                 :          0 :     mArgs = args;
    1073                 :          0 :   }
    1074                 :            :   else
    1075                 :            :   {
    1076                 :          0 :     mArgs = new NodeList();
    1077                 :            : 
    1078                 :          0 :     int idx = 0;
    1079                 :            :     //first loop through unnamed arguments
    1080                 :          0 :     while ( idx < args->names().size() && args->names().at( idx ).isEmpty() )
    1081                 :            :     {
    1082                 :          0 :       mArgs->append( args->list().at( idx )->clone() );
    1083                 :          0 :       idx++;
    1084                 :            :     }
    1085                 :            : 
    1086                 :            :     //next copy named QgsExpressionFunction::Parameters in order expected by function
    1087                 :          0 :     for ( ; idx < functionParams.count(); ++idx )
    1088                 :            :     {
    1089                 :          0 :       int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
    1090                 :          0 :       if ( nodeIdx < 0 )
    1091                 :            :       {
    1092                 :            :         //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
    1093                 :          0 :         mArgs->append( new QgsExpressionNodeLiteral( functionParams.at( idx ).defaultValue() ) );
    1094                 :          0 :       }
    1095                 :            :       else
    1096                 :            :       {
    1097                 :          0 :         mArgs->append( args->list().at( nodeIdx )->clone() );
    1098                 :            :       }
    1099                 :          0 :     }
    1100                 :            : 
    1101                 :          0 :     delete args;
    1102                 :            :   }
    1103                 :          0 : }
    1104                 :            : 
    1105                 :          0 : QgsExpressionNodeFunction::~QgsExpressionNodeFunction()
    1106                 :          0 : {
    1107                 :          0 :   delete mArgs;
    1108                 :          0 : }
    1109                 :            : 
    1110                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeFunction::nodeType() const
    1111                 :            : {
    1112                 :          0 :   return ntFunction;
    1113                 :            : }
    1114                 :            : 
    1115                 :          0 : bool QgsExpressionNodeFunction::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1116                 :            : {
    1117                 :          0 :   QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
    1118                 :            : 
    1119                 :          0 :   bool res = fd->prepare( this, parent, context );
    1120                 :          0 :   if ( mArgs && !fd->lazyEval() )
    1121                 :            :   {
    1122                 :          0 :     const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1123                 :          0 :     for ( QgsExpressionNode *n : nodeList )
    1124                 :            :     {
    1125                 :          0 :       res = res && n->prepare( parent, context );
    1126                 :            :     }
    1127                 :          0 :   }
    1128                 :          0 :   return res;
    1129                 :          0 : }
    1130                 :            : 
    1131                 :          0 : QString QgsExpressionNodeFunction::dump() const
    1132                 :            : {
    1133                 :          0 :   QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
    1134                 :          0 :   if ( fd->params() == 0 )
    1135                 :          0 :     return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
    1136                 :            :   else
    1137                 :          0 :     return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
    1138                 :          0 : }
    1139                 :            : 
    1140                 :          0 : QSet<QString> QgsExpressionNodeFunction::referencedColumns() const
    1141                 :            : {
    1142                 :          0 :   if ( hasCachedStaticValue() )
    1143                 :          0 :     return QSet< QString >();
    1144                 :            : 
    1145                 :          0 :   QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
    1146                 :          0 :   QSet<QString> functionColumns = fd->referencedColumns( this );
    1147                 :            : 
    1148                 :          0 :   if ( !mArgs )
    1149                 :            :   {
    1150                 :            :     //no referenced columns in arguments, just return function's referenced columns
    1151                 :          0 :     return functionColumns;
    1152                 :            :   }
    1153                 :            : 
    1154                 :          0 :   int paramIndex = 0;
    1155                 :          0 :   const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1156                 :          0 :   for ( QgsExpressionNode *n : nodeList )
    1157                 :            :   {
    1158                 :          0 :     if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
    1159                 :          0 :       functionColumns.unite( n->referencedColumns() );
    1160                 :          0 :     paramIndex++;
    1161                 :            :   }
    1162                 :            : 
    1163                 :          0 :   return functionColumns;
    1164                 :          0 : }
    1165                 :            : 
    1166                 :          0 : QSet<QString> QgsExpressionNodeFunction::referencedVariables() const
    1167                 :            : {
    1168                 :          0 :   QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
    1169                 :          0 :   if ( fd->name() == QLatin1String( "var" ) )
    1170                 :            :   {
    1171                 :          0 :     if ( !mArgs->list().isEmpty() )
    1172                 :            :     {
    1173                 :          0 :       QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
    1174                 :          0 :       if ( var )
    1175                 :          0 :         return QSet<QString>() << var->value().toString();
    1176                 :          0 :     }
    1177                 :          0 :     return QSet<QString>() << QString();
    1178                 :            :   }
    1179                 :            :   else
    1180                 :            :   {
    1181                 :          0 :     QSet<QString> functionVariables = QSet<QString>();
    1182                 :            : 
    1183                 :          0 :     if ( !mArgs )
    1184                 :          0 :       return functionVariables;
    1185                 :            : 
    1186                 :          0 :     const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1187                 :          0 :     for ( QgsExpressionNode *n : nodeList )
    1188                 :            :     {
    1189                 :          0 :       functionVariables.unite( n->referencedVariables() );
    1190                 :            :     }
    1191                 :            : 
    1192                 :          0 :     return functionVariables;
    1193                 :          0 :   }
    1194                 :          0 : }
    1195                 :            : 
    1196                 :          0 : QSet<QString> QgsExpressionNodeFunction::referencedFunctions() const
    1197                 :            : {
    1198                 :          0 :   QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
    1199                 :          0 :   QSet<QString> functions = QSet<QString>();
    1200                 :          0 :   functions.insert( fd->name() );
    1201                 :            : 
    1202                 :          0 :   if ( !mArgs )
    1203                 :          0 :     return functions;
    1204                 :            : 
    1205                 :          0 :   const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1206                 :          0 :   for ( QgsExpressionNode *n : nodeList )
    1207                 :            :   {
    1208                 :          0 :     functions.unite( n->referencedFunctions() );
    1209                 :            :   }
    1210                 :          0 :   return functions;
    1211                 :          0 : }
    1212                 :            : 
    1213                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
    1214                 :            : {
    1215                 :          0 :   QList<const QgsExpressionNode *> lst;
    1216                 :          0 :   lst << this;
    1217                 :          0 :   if ( !mArgs )
    1218                 :          0 :     return lst;
    1219                 :            : 
    1220                 :          0 :   const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1221                 :          0 :   for ( QgsExpressionNode *n : nodeList )
    1222                 :            :   {
    1223                 :          0 :     lst += n->nodes();
    1224                 :            :   }
    1225                 :          0 :   return lst;
    1226                 :          0 : }
    1227                 :            : 
    1228                 :          0 : bool QgsExpressionNodeFunction::needsGeometry() const
    1229                 :            : {
    1230                 :          0 :   bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
    1231                 :          0 :   if ( mArgs )
    1232                 :            :   {
    1233                 :          0 :     const QList< QgsExpressionNode * > nodeList = mArgs->list();
    1234                 :          0 :     for ( QgsExpressionNode *n : nodeList )
    1235                 :          0 :       needs |= n->needsGeometry();
    1236                 :          0 :   }
    1237                 :          0 :   return needs;
    1238                 :          0 : }
    1239                 :            : 
    1240                 :          0 : QgsExpressionNode *QgsExpressionNodeFunction::clone() const
    1241                 :            : {
    1242                 :          0 :   QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
    1243                 :          0 :   cloneTo( copy );
    1244                 :          0 :   return copy;
    1245                 :          0 : }
    1246                 :            : 
    1247                 :          0 : bool QgsExpressionNodeFunction::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1248                 :            : {
    1249                 :          0 :   return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
    1250                 :            : }
    1251                 :            : 
    1252                 :          0 : bool QgsExpressionNodeFunction::validateParams( int fnIndex, QgsExpressionNode::NodeList *args, QString &error )
    1253                 :            : {
    1254                 :          0 :   if ( !args || !args->hasNamedNodes() )
    1255                 :          0 :     return true;
    1256                 :            : 
    1257                 :          0 :   const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
    1258                 :          0 :   if ( functionParams.isEmpty() )
    1259                 :            :   {
    1260                 :          0 :     error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
    1261                 :          0 :     return false;
    1262                 :            :   }
    1263                 :            :   else
    1264                 :            :   {
    1265                 :          0 :     QSet< int > providedArgs;
    1266                 :          0 :     QSet< int > handledArgs;
    1267                 :          0 :     int idx = 0;
    1268                 :            :     //first loop through unnamed arguments
    1269                 :          0 :     while ( args->names().at( idx ).isEmpty() )
    1270                 :            :     {
    1271                 :          0 :       providedArgs << idx;
    1272                 :          0 :       handledArgs << idx;
    1273                 :          0 :       idx++;
    1274                 :            :     }
    1275                 :            : 
    1276                 :            :     //next check named QgsExpressionFunction::Parameters
    1277                 :          0 :     for ( ; idx < functionParams.count(); ++idx )
    1278                 :            :     {
    1279                 :          0 :       int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
    1280                 :          0 :       if ( nodeIdx < 0 )
    1281                 :            :       {
    1282                 :          0 :         if ( !functionParams.at( idx ).optional() )
    1283                 :            :         {
    1284                 :          0 :           error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
    1285                 :          0 :           return false;
    1286                 :            :         }
    1287                 :          0 :       }
    1288                 :            :       else
    1289                 :            :       {
    1290                 :          0 :         if ( providedArgs.contains( idx ) )
    1291                 :            :         {
    1292                 :          0 :           error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
    1293                 :          0 :           return false;
    1294                 :            :         }
    1295                 :            :       }
    1296                 :          0 :       providedArgs << idx;
    1297                 :          0 :       handledArgs << nodeIdx;
    1298                 :          0 :     }
    1299                 :            : 
    1300                 :            :     //last check for bad names
    1301                 :          0 :     idx = 0;
    1302                 :          0 :     const QStringList nameList = args->names();
    1303                 :          0 :     for ( const QString &name : nameList )
    1304                 :            :     {
    1305                 :          0 :       if ( !name.isEmpty() && !functionParams.contains( name ) )
    1306                 :            :       {
    1307                 :          0 :         error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
    1308                 :          0 :         return false;
    1309                 :            :       }
    1310                 :          0 :       if ( !name.isEmpty() && !handledArgs.contains( idx ) )
    1311                 :            :       {
    1312                 :          0 :         int functionIdx = functionParams.indexOf( name );
    1313                 :          0 :         if ( providedArgs.contains( functionIdx ) )
    1314                 :            :         {
    1315                 :          0 :           error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
    1316                 :          0 :           return false;
    1317                 :            :         }
    1318                 :          0 :       }
    1319                 :          0 :       idx++;
    1320                 :            :     }
    1321                 :            : 
    1322                 :          0 :   }
    1323                 :          0 :   return true;
    1324                 :          0 : }
    1325                 :            : 
    1326                 :            : //
    1327                 :            : 
    1328                 :          0 : QVariant QgsExpressionNodeLiteral::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
    1329                 :            : {
    1330                 :            :   Q_UNUSED( context )
    1331                 :            :   Q_UNUSED( parent )
    1332                 :          0 :   return mValue;
    1333                 :            : }
    1334                 :            : 
    1335                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeLiteral::nodeType() const
    1336                 :            : {
    1337                 :          0 :   return ntLiteral;
    1338                 :            : }
    1339                 :            : 
    1340                 :          0 : bool QgsExpressionNodeLiteral::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1341                 :            : {
    1342                 :            :   Q_UNUSED( parent )
    1343                 :            :   Q_UNUSED( context )
    1344                 :          0 :   return true;
    1345                 :            : }
    1346                 :            : 
    1347                 :            : 
    1348                 :          0 : QString QgsExpressionNodeLiteral::dump() const
    1349                 :            : {
    1350                 :          0 :   if ( mValue.isNull() )
    1351                 :          0 :     return QStringLiteral( "NULL" );
    1352                 :            : 
    1353                 :          0 :   switch ( mValue.type() )
    1354                 :            :   {
    1355                 :            :     case QVariant::Int:
    1356                 :          0 :       return QString::number( mValue.toInt() );
    1357                 :            :     case QVariant::Double:
    1358                 :          0 :       return QString::number( mValue.toDouble() );
    1359                 :            :     case QVariant::LongLong:
    1360                 :          0 :       return QString::number( mValue.toLongLong() );
    1361                 :            :     case QVariant::String:
    1362                 :          0 :       return QgsExpression::quotedString( mValue.toString() );
    1363                 :            :     case QVariant::Bool:
    1364                 :          0 :       return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
    1365                 :            :     default:
    1366                 :          0 :       return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
    1367                 :            :   }
    1368                 :          0 : }
    1369                 :            : 
    1370                 :          0 : QSet<QString> QgsExpressionNodeLiteral::referencedColumns() const
    1371                 :            : {
    1372                 :          0 :   return QSet<QString>();
    1373                 :            : }
    1374                 :            : 
    1375                 :          0 : QSet<QString> QgsExpressionNodeLiteral::referencedVariables() const
    1376                 :            : {
    1377                 :          0 :   return QSet<QString>();
    1378                 :            : }
    1379                 :            : 
    1380                 :          0 : QSet<QString> QgsExpressionNodeLiteral::referencedFunctions() const
    1381                 :            : {
    1382                 :          0 :   return QSet<QString>();
    1383                 :            : }
    1384                 :            : 
    1385                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
    1386                 :            : {
    1387                 :          0 :   QList<const QgsExpressionNode *> lst;
    1388                 :          0 :   lst << this;
    1389                 :          0 :   return lst;
    1390                 :          0 : }
    1391                 :            : 
    1392                 :          0 : bool QgsExpressionNodeLiteral::needsGeometry() const
    1393                 :            : {
    1394                 :          0 :   return false;
    1395                 :            : }
    1396                 :            : 
    1397                 :          0 : QgsExpressionNode *QgsExpressionNodeLiteral::clone() const
    1398                 :            : {
    1399                 :          0 :   QgsExpressionNodeLiteral *copy = new QgsExpressionNodeLiteral( mValue );
    1400                 :          0 :   cloneTo( copy );
    1401                 :          0 :   return copy;
    1402                 :          0 : }
    1403                 :            : 
    1404                 :          0 : bool QgsExpressionNodeLiteral::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1405                 :            : {
    1406                 :            :   Q_UNUSED( context )
    1407                 :            :   Q_UNUSED( parent )
    1408                 :          0 :   return true;
    1409                 :            : }
    1410                 :            : 
    1411                 :            : //
    1412                 :            : 
    1413                 :          0 : QVariant QgsExpressionNodeColumnRef::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
    1414                 :            : {
    1415                 :            :   Q_UNUSED( parent )
    1416                 :          0 :   int index = mIndex;
    1417                 :            : 
    1418                 :          0 :   if ( index < 0 )
    1419                 :            :   {
    1420                 :            :     // have not yet found field index - first check explicitly set fields collection
    1421                 :          0 :     if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
    1422                 :            :     {
    1423                 :          0 :       QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
    1424                 :          0 :       index = fields.lookupField( mName );
    1425                 :          0 :     }
    1426                 :          0 :   }
    1427                 :            : 
    1428                 :          0 :   if ( context )
    1429                 :            :   {
    1430                 :          0 :     QgsFeature feature = context->feature();
    1431                 :          0 :     if ( feature.isValid() )
    1432                 :            :     {
    1433                 :          0 :       if ( index >= 0 )
    1434                 :          0 :         return feature.attribute( index );
    1435                 :            :       else
    1436                 :          0 :         return feature.attribute( mName );
    1437                 :            :     }
    1438                 :            :     else
    1439                 :            :     {
    1440                 :          0 :       parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
    1441                 :            :     }
    1442                 :          0 :   }
    1443                 :          0 :   if ( index < 0 )
    1444                 :          0 :     parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
    1445                 :          0 :   return QVariant();
    1446                 :          0 : }
    1447                 :            : 
    1448                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeColumnRef::nodeType() const
    1449                 :            : {
    1450                 :          0 :   return ntColumnRef;
    1451                 :            : }
    1452                 :            : 
    1453                 :          0 : bool QgsExpressionNodeColumnRef::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1454                 :            : {
    1455                 :          0 :   if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
    1456                 :          0 :     return false;
    1457                 :            : 
    1458                 :          0 :   QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
    1459                 :            : 
    1460                 :          0 :   mIndex = fields.lookupField( mName );
    1461                 :            : 
    1462                 :          0 :   if ( mIndex == -1 && context->hasFeature() )
    1463                 :            :   {
    1464                 :          0 :     mIndex = context->feature().fieldNameIndex( mName );
    1465                 :          0 :   }
    1466                 :            : 
    1467                 :          0 :   if ( mIndex == -1 )
    1468                 :            :   {
    1469                 :          0 :     parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
    1470                 :          0 :     return false;
    1471                 :            :   }
    1472                 :          0 :   return true;
    1473                 :          0 : }
    1474                 :            : 
    1475                 :          0 : QString QgsExpressionNodeColumnRef::dump() const
    1476                 :            : {
    1477                 :          0 :   const thread_local QRegExp re( QStringLiteral( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ) );
    1478                 :          0 :   return re.exactMatch( mName ) ? mName : QgsExpression::quotedColumnRef( mName );
    1479                 :          0 : }
    1480                 :            : 
    1481                 :          0 : QSet<QString> QgsExpressionNodeColumnRef::referencedColumns() const
    1482                 :            : {
    1483                 :          0 :   return QSet<QString>() << mName;
    1484                 :          0 : }
    1485                 :            : 
    1486                 :          0 : QSet<QString> QgsExpressionNodeColumnRef::referencedVariables() const
    1487                 :            : {
    1488                 :          0 :   return QSet<QString>();
    1489                 :            : }
    1490                 :            : 
    1491                 :          0 : QSet<QString> QgsExpressionNodeColumnRef::referencedFunctions() const
    1492                 :            : {
    1493                 :          0 :   return QSet<QString>();
    1494                 :            : }
    1495                 :            : 
    1496                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
    1497                 :            : {
    1498                 :          0 :   QList<const QgsExpressionNode *> result;
    1499                 :          0 :   result << this;
    1500                 :          0 :   return result;
    1501                 :          0 : }
    1502                 :            : 
    1503                 :          0 : bool QgsExpressionNodeColumnRef::needsGeometry() const
    1504                 :            : {
    1505                 :          0 :   return false;
    1506                 :            : }
    1507                 :            : 
    1508                 :          0 : QgsExpressionNode *QgsExpressionNodeColumnRef::clone() const
    1509                 :            : {
    1510                 :          0 :   QgsExpressionNodeColumnRef *copy = new QgsExpressionNodeColumnRef( mName );
    1511                 :          0 :   cloneTo( copy );
    1512                 :          0 :   return copy;
    1513                 :          0 : }
    1514                 :            : 
    1515                 :          0 : bool QgsExpressionNodeColumnRef::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1516                 :            : {
    1517                 :            :   Q_UNUSED( context )
    1518                 :            :   Q_UNUSED( parent )
    1519                 :          0 :   return false;
    1520                 :            : }
    1521                 :            : 
    1522                 :            : //
    1523                 :            : 
    1524                 :          0 : QgsExpressionNodeCondition::QgsExpressionNodeCondition( QgsExpressionNodeCondition::WhenThenList *conditions, QgsExpressionNode *elseExp )
    1525                 :          0 :   : mConditions( *conditions )
    1526                 :          0 :   , mElseExp( elseExp )
    1527                 :          0 : {
    1528                 :          0 :   delete conditions;
    1529                 :          0 : }
    1530                 :            : 
    1531                 :          0 : QgsExpressionNodeCondition::~QgsExpressionNodeCondition()
    1532                 :          0 : {
    1533                 :          0 :   delete mElseExp;
    1534                 :          0 :   qDeleteAll( mConditions );
    1535                 :          0 : }
    1536                 :            : 
    1537                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeCondition::nodeType() const
    1538                 :            : {
    1539                 :          0 :   return ntCondition;
    1540                 :            : }
    1541                 :            : 
    1542                 :          0 : QVariant QgsExpressionNodeCondition::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
    1543                 :            : {
    1544                 :          0 :   for ( WhenThen *cond : std::as_const( mConditions ) )
    1545                 :            :   {
    1546                 :          0 :     QVariant vWhen = cond->mWhenExp->eval( parent, context );
    1547                 :          0 :     QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
    1548                 :          0 :     ENSURE_NO_EVAL_ERROR
    1549                 :          0 :     if ( tvl == QgsExpressionUtils::True )
    1550                 :            :     {
    1551                 :          0 :       QVariant vRes = cond->mThenExp->eval( parent, context );
    1552                 :          0 :       ENSURE_NO_EVAL_ERROR
    1553                 :          0 :       return vRes;
    1554                 :          0 :     }
    1555                 :          0 :   }
    1556                 :            : 
    1557                 :          0 :   if ( mElseExp )
    1558                 :            :   {
    1559                 :          0 :     QVariant vElse = mElseExp->eval( parent, context );
    1560                 :          0 :     ENSURE_NO_EVAL_ERROR
    1561                 :          0 :     return vElse;
    1562                 :          0 :   }
    1563                 :            : 
    1564                 :            :   // return NULL if no condition is matching
    1565                 :          0 :   return QVariant();
    1566                 :          0 : }
    1567                 :            : 
    1568                 :          0 : bool QgsExpressionNodeCondition::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1569                 :            : {
    1570                 :            :   bool res;
    1571                 :          0 :   for ( WhenThen *cond : std::as_const( mConditions ) )
    1572                 :            :   {
    1573                 :          0 :     res = cond->mWhenExp->prepare( parent, context )
    1574                 :          0 :           & cond->mThenExp->prepare( parent, context );
    1575                 :          0 :     if ( !res )
    1576                 :          0 :       return false;
    1577                 :            :   }
    1578                 :            : 
    1579                 :          0 :   if ( mElseExp )
    1580                 :          0 :     return mElseExp->prepare( parent, context );
    1581                 :            : 
    1582                 :          0 :   return true;
    1583                 :          0 : }
    1584                 :            : 
    1585                 :          0 : QString QgsExpressionNodeCondition::dump() const
    1586                 :            : {
    1587                 :          0 :   QString msg( QStringLiteral( "CASE" ) );
    1588                 :          0 :   for ( WhenThen *cond : mConditions )
    1589                 :            :   {
    1590                 :          0 :     msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
    1591                 :            :   }
    1592                 :          0 :   if ( mElseExp )
    1593                 :          0 :     msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
    1594                 :          0 :   msg += QLatin1String( " END" );
    1595                 :          0 :   return msg;
    1596                 :          0 : }
    1597                 :            : 
    1598                 :          0 : QSet<QString> QgsExpressionNodeCondition::referencedColumns() const
    1599                 :            : {
    1600                 :          0 :   if ( hasCachedStaticValue() )
    1601                 :          0 :     return QSet< QString >();
    1602                 :            : 
    1603                 :          0 :   QSet<QString> lst;
    1604                 :          0 :   for ( WhenThen *cond : mConditions )
    1605                 :            :   {
    1606                 :          0 :     lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
    1607                 :            :   }
    1608                 :            : 
    1609                 :          0 :   if ( mElseExp )
    1610                 :          0 :     lst += mElseExp->referencedColumns();
    1611                 :            : 
    1612                 :          0 :   return lst;
    1613                 :          0 : }
    1614                 :            : 
    1615                 :          0 : QSet<QString> QgsExpressionNodeCondition::referencedVariables() const
    1616                 :            : {
    1617                 :          0 :   QSet<QString> lst;
    1618                 :          0 :   for ( WhenThen *cond : mConditions )
    1619                 :            :   {
    1620                 :          0 :     lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
    1621                 :            :   }
    1622                 :            : 
    1623                 :          0 :   if ( mElseExp )
    1624                 :          0 :     lst += mElseExp->referencedVariables();
    1625                 :            : 
    1626                 :          0 :   return lst;
    1627                 :          0 : }
    1628                 :            : 
    1629                 :          0 : QSet<QString> QgsExpressionNodeCondition::referencedFunctions() const
    1630                 :            : {
    1631                 :          0 :   QSet<QString> lst;
    1632                 :          0 :   for ( WhenThen *cond : mConditions )
    1633                 :            :   {
    1634                 :          0 :     lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
    1635                 :            :   }
    1636                 :            : 
    1637                 :          0 :   if ( mElseExp )
    1638                 :          0 :     lst += mElseExp->referencedFunctions();
    1639                 :            : 
    1640                 :          0 :   return lst;
    1641                 :          0 : }
    1642                 :            : 
    1643                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
    1644                 :            : {
    1645                 :          0 :   QList<const QgsExpressionNode *> lst;
    1646                 :          0 :   lst << this;
    1647                 :          0 :   for ( WhenThen *cond : mConditions )
    1648                 :            :   {
    1649                 :          0 :     lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
    1650                 :            :   }
    1651                 :            : 
    1652                 :          0 :   if ( mElseExp )
    1653                 :          0 :     lst += mElseExp->nodes();
    1654                 :            : 
    1655                 :          0 :   return lst;
    1656                 :          0 : }
    1657                 :            : 
    1658                 :          0 : bool QgsExpressionNodeCondition::needsGeometry() const
    1659                 :            : {
    1660                 :          0 :   for ( WhenThen *cond : mConditions )
    1661                 :            :   {
    1662                 :          0 :     if ( cond->mWhenExp->needsGeometry() ||
    1663                 :          0 :          cond->mThenExp->needsGeometry() )
    1664                 :          0 :       return true;
    1665                 :            :   }
    1666                 :            : 
    1667                 :          0 :   return mElseExp && mElseExp->needsGeometry();
    1668                 :          0 : }
    1669                 :            : 
    1670                 :          0 : QgsExpressionNode *QgsExpressionNodeCondition::clone() const
    1671                 :            : {
    1672                 :          0 :   WhenThenList conditions;
    1673                 :          0 :   conditions.reserve( mConditions.size() );
    1674                 :          0 :   for ( WhenThen *wt : mConditions )
    1675                 :          0 :     conditions.append( wt->clone() );
    1676                 :            : 
    1677                 :          0 :   QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
    1678                 :          0 :   cloneTo( copy );
    1679                 :          0 :   return copy;
    1680                 :          0 : }
    1681                 :            : 
    1682                 :          0 : bool QgsExpressionNodeCondition::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1683                 :            : {
    1684                 :          0 :   for ( WhenThen *wt : mConditions )
    1685                 :            :   {
    1686                 :          0 :     if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
    1687                 :          0 :       return false;
    1688                 :            :   }
    1689                 :            : 
    1690                 :          0 :   if ( mElseExp )
    1691                 :          0 :     return mElseExp->isStatic( parent, context );
    1692                 :            : 
    1693                 :          0 :   return true;
    1694                 :          0 : }
    1695                 :            : 
    1696                 :          0 : QSet<QString> QgsExpressionNodeInOperator::referencedColumns() const
    1697                 :            : {
    1698                 :          0 :   if ( hasCachedStaticValue() )
    1699                 :          0 :     return QSet< QString >();
    1700                 :            : 
    1701                 :          0 :   QSet<QString> lst( mNode->referencedColumns() );
    1702                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1703                 :          0 :   for ( const QgsExpressionNode *n : nodeList )
    1704                 :          0 :     lst.unite( n->referencedColumns() );
    1705                 :          0 :   return lst;
    1706                 :          0 : }
    1707                 :            : 
    1708                 :          0 : QSet<QString> QgsExpressionNodeInOperator::referencedVariables() const
    1709                 :            : {
    1710                 :          0 :   QSet<QString> lst( mNode->referencedVariables() );
    1711                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1712                 :          0 :   for ( const QgsExpressionNode *n : nodeList )
    1713                 :          0 :     lst.unite( n->referencedVariables() );
    1714                 :          0 :   return lst;
    1715                 :          0 : }
    1716                 :            : 
    1717                 :          0 : QSet<QString> QgsExpressionNodeInOperator::referencedFunctions() const
    1718                 :            : {
    1719                 :          0 :   QSet<QString> lst( mNode->referencedFunctions() );
    1720                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1721                 :          0 :   for ( const QgsExpressionNode *n : nodeList )
    1722                 :          0 :     lst.unite( n->referencedFunctions() );
    1723                 :          0 :   return lst;
    1724                 :          0 : }
    1725                 :            : 
    1726                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
    1727                 :            : {
    1728                 :          0 :   QList<const QgsExpressionNode *> lst;
    1729                 :          0 :   lst << this;
    1730                 :          0 :   const QList< QgsExpressionNode * > nodeList = mList->list();
    1731                 :          0 :   for ( const QgsExpressionNode *n : nodeList )
    1732                 :          0 :     lst += n->nodes();
    1733                 :          0 :   return lst;
    1734                 :          0 : }
    1735                 :            : 
    1736                 :          0 : QgsExpressionNodeCondition::WhenThen::WhenThen( QgsExpressionNode *whenExp, QgsExpressionNode *thenExp )
    1737                 :          0 :   : mWhenExp( whenExp )
    1738                 :          0 :   , mThenExp( thenExp )
    1739                 :            : {
    1740                 :          0 : }
    1741                 :            : 
    1742                 :          0 : QgsExpressionNodeCondition::WhenThen::~WhenThen()
    1743                 :            : {
    1744                 :          0 :   delete mWhenExp;
    1745                 :          0 :   delete mThenExp;
    1746                 :          0 : }
    1747                 :            : 
    1748                 :          0 : QgsExpressionNodeCondition::WhenThen *QgsExpressionNodeCondition::WhenThen::clone() const
    1749                 :            : {
    1750                 :          0 :   return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
    1751                 :          0 : }
    1752                 :            : 
    1753                 :          0 : QString QgsExpressionNodeBinaryOperator::text() const
    1754                 :            : {
    1755                 :          0 :   return BINARY_OPERATOR_TEXT[mOp];
    1756                 :            : }
    1757                 :            : 
    1758                 :            : //
    1759                 :            : 
    1760                 :          0 : QVariant QgsExpressionNodeIndexOperator::evalNode( QgsExpression *parent, const QgsExpressionContext *context )
    1761                 :            : {
    1762                 :          0 :   const QVariant container = mContainer->eval( parent, context );
    1763                 :          0 :   ENSURE_NO_EVAL_ERROR
    1764                 :          0 :   const QVariant index = mIndex->eval( parent, context );
    1765                 :          0 :   ENSURE_NO_EVAL_ERROR
    1766                 :            : 
    1767                 :          0 :   switch ( container.type() )
    1768                 :            :   {
    1769                 :            :     case QVariant::Map:
    1770                 :          0 :       return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
    1771                 :            : 
    1772                 :            :     case QVariant::List:
    1773                 :            :     case QVariant::StringList:
    1774                 :            :     {
    1775                 :          0 :       const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
    1776                 :          0 :       qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
    1777                 :          0 :       if ( pos >= list.length() || pos < -list.length() )
    1778                 :            :       {
    1779                 :          0 :         return QVariant();
    1780                 :            :       }
    1781                 :          0 :       if ( pos < 0 )
    1782                 :            :       {
    1783                 :            :         // negative indices are from back of list
    1784                 :          0 :         pos += list.length();
    1785                 :          0 :       }
    1786                 :            : 
    1787                 :          0 :       return list.at( pos );
    1788                 :          0 :     }
    1789                 :            : 
    1790                 :            :     default:
    1791                 :          0 :       parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( container.type() ) ) );
    1792                 :          0 :       return QVariant();
    1793                 :            :   }
    1794                 :          0 : }
    1795                 :            : 
    1796                 :          0 : QgsExpressionNode::NodeType QgsExpressionNodeIndexOperator::nodeType() const
    1797                 :            : {
    1798                 :          0 :   return ntIndexOperator;
    1799                 :            : }
    1800                 :            : 
    1801                 :          0 : bool QgsExpressionNodeIndexOperator::prepareNode( QgsExpression *parent, const QgsExpressionContext *context )
    1802                 :            : {
    1803                 :          0 :   bool resC = mContainer->prepare( parent, context );
    1804                 :          0 :   bool resV = mIndex->prepare( parent, context );
    1805                 :          0 :   return resC && resV;
    1806                 :            : }
    1807                 :            : 
    1808                 :          0 : QString QgsExpressionNodeIndexOperator::dump() const
    1809                 :            : {
    1810                 :          0 :   return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
    1811                 :          0 : }
    1812                 :            : 
    1813                 :          0 : QSet<QString> QgsExpressionNodeIndexOperator::referencedColumns() const
    1814                 :            : {
    1815                 :          0 :   if ( hasCachedStaticValue() )
    1816                 :          0 :     return QSet< QString >();
    1817                 :            : 
    1818                 :          0 :   return mContainer->referencedColumns() + mIndex->referencedColumns();
    1819                 :          0 : }
    1820                 :            : 
    1821                 :          0 : QSet<QString> QgsExpressionNodeIndexOperator::referencedVariables() const
    1822                 :            : {
    1823                 :          0 :   return mContainer->referencedVariables() + mIndex->referencedVariables();
    1824                 :          0 : }
    1825                 :            : 
    1826                 :          0 : QSet<QString> QgsExpressionNodeIndexOperator::referencedFunctions() const
    1827                 :            : {
    1828                 :          0 :   return mContainer->referencedFunctions() + mIndex->referencedFunctions();
    1829                 :          0 : }
    1830                 :            : 
    1831                 :          0 : QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
    1832                 :            : {
    1833                 :          0 :   QList<const QgsExpressionNode *> lst;
    1834                 :          0 :   lst << this;
    1835                 :          0 :   lst += mContainer->nodes() + mIndex->nodes();
    1836                 :          0 :   return lst;
    1837                 :          0 : }
    1838                 :            : 
    1839                 :          0 : bool QgsExpressionNodeIndexOperator::needsGeometry() const
    1840                 :            : {
    1841                 :          0 :   return mContainer->needsGeometry() || mIndex->needsGeometry();
    1842                 :            : }
    1843                 :            : 
    1844                 :          0 : QgsExpressionNode *QgsExpressionNodeIndexOperator::clone() const
    1845                 :            : {
    1846                 :          0 :   QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
    1847                 :          0 :   cloneTo( copy );
    1848                 :          0 :   return copy;
    1849                 :          0 : }
    1850                 :            : 
    1851                 :          0 : bool QgsExpressionNodeIndexOperator::isStatic( QgsExpression *parent, const QgsExpressionContext *context ) const
    1852                 :            : {
    1853                 :          0 :   return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
    1854                 :            : }

Generated by: LCOV version 1.14