QGIS API Documentation 4.3.0-Master (6402a64e93b)
Loading...
Searching...
No Matches
qgsexpressionnodeimpl.cpp
Go to the documentation of this file.
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
17
18#include "qgsexpression.h"
19#include "qgsexpressionutils.h"
20#include "qgsstringutils.h"
21#include "qgsvariantutils.h"
22
23#include <QColor>
24#include <QDate>
25#include <QDateTime>
26#include <QRegularExpression>
27#include <QString>
28#include <QTime>
29
30using namespace Qt::StringLiterals;
31
32const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] = {
33 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
34 "OR", "AND", "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT", "+", "-", "*", "/", "//", "%", "^", "||"
35};
36
37const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] = {
38 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
39 "NOT",
40 "-"
41};
42
44{
45 bool needs = false;
46 const QList< QgsExpressionNode * > nodeList = mList->list();
47 for ( QgsExpressionNode *n : nodeList )
48 needs |= n->needsGeometry();
49 return needs;
50}
51
53{
54 qDeleteAll( mList );
55}
56
58{
59 mList.append( node->node );
60 mNameList.append( cleanNamedNodeName( node->name ) );
61 mHasNamedNodes = true;
62 delete node;
63}
64
66{
67 NodeList *nl = new NodeList;
68 for ( QgsExpressionNode *node : mList )
69 {
70 nl->mList.append( node->clone() );
71 }
72 nl->mNameList = mNameList;
73
74 return nl;
75}
76
78{
79 QString msg;
80 bool first = true;
81 for ( QgsExpressionNode *n : mList )
82 {
83 if ( !first )
84 msg += ", "_L1;
85 else
86 first = false;
87 msg += n->dump();
88 }
89 return msg;
90}
91
92QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
93{
94 QString cleaned = name.toLower();
95
96 // upgrade older argument names to standard versions
97 if ( cleaned == "geom"_L1 )
98 cleaned = u"geometry"_s;
99 else if ( cleaned == "val"_L1 )
100 cleaned = u"value"_s;
101 else if ( cleaned == "geometry a"_L1 )
102 cleaned = u"geometry1"_s;
103 else if ( cleaned == "geometry b"_L1 )
104 cleaned = u"geometry2"_s;
105 else if ( cleaned == "i"_L1 )
106 cleaned = u"vertex"_s;
107 else if ( cleaned == "array_a"_L1 )
108 cleaned = u"array1"_s;
109 else if ( cleaned == "array_b"_L1 )
110 cleaned = u"array2"_s;
111 else if ( cleaned == "point_a"_L1 )
112 cleaned = u"point1"_s;
113 else if ( cleaned == "point_b"_L1 )
114 cleaned = u"point2"_s;
115 else if ( cleaned == "array_prioritize"_L1 )
116 cleaned = u"priority"_s;
117
118 return cleaned;
119}
120
121
122//
123
125{
126 QVariant val = mOperand->eval( parent, context );
128
129 switch ( mOp )
130 {
131 case uoNot:
132 {
133 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
135 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
136 }
137
138 case uoMinus:
139 if ( QgsExpressionUtils::isIntSafe( val ) )
140 return QVariant( -QgsExpressionUtils::getIntValue( val, parent ) );
141 else if ( QgsExpressionUtils::isDoubleSafe( val ) )
142 return QVariant( -QgsExpressionUtils::getDoubleValue( val, parent ) );
143 else
144 SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
145 }
146 return QVariant();
147}
148
153
155{
156 return mOperand->prepare( parent, context );
157}
158
160{
161 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand.get() ) )
162 return u"%1 ( %2 )"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
163 else
164 return u"%1 %2"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
165}
166
168{
169 if ( hasCachedStaticValue() )
170 return QSet< QString >();
171
172 return mOperand->referencedColumns();
173}
174
176{
177 return mOperand->referencedVariables();
178}
179
181{
182 return mOperand->referencedFunctions();
183}
184
185QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
186{
187 QList<const QgsExpressionNode *> lst;
188 lst.append( this );
189 lst += mOperand->nodes();
190 return lst;
191}
192
194{
195 return mOperand->needsGeometry();
196}
197
199{
200 QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
201 cloneTo( copy );
202 return copy;
203}
204
206{
207 std::unique_ptr< QgsExpressionNode > simplifiedOperand( mOperand->simplifiedNode() );
208 if ( simplifiedOperand->nodeType() == ntLiteral )
209 {
210 QgsExpressionNodeUnaryOperator tempNode( mOp, simplifiedOperand->clone() );
211 QgsExpression parentExp;
212 QVariant result = tempNode.eval( &parentExp, nullptr );
213 if ( !parentExp.hasEvalError() )
214 {
215 return new QgsExpressionNodeLiteral( result );
216 }
217 }
218
219 return new QgsExpressionNodeUnaryOperator( mOp, simplifiedOperand.release() );
220}
221
223{
224 return mOperand->isStatic( parent, context );
225}
226
228{
229 return UNARY_OPERATOR_TEXT[mOp];
230}
231
232//
233
235{
236 switch ( op )
237 {
239 return diff == 0;
241 return diff != 0;
243 return diff < 0;
245 return diff > 0;
247 return diff <= 0;
249 return diff >= 0;
250 default:
251 Q_ASSERT( false );
252 return false;
253 }
254}
255
257{
258 switch ( op )
259 {
261 return qgsDoubleNear( diff, 0.0 );
263 return !qgsDoubleNear( diff, 0.0 );
265 return diff < 0;
267 return diff > 0;
269 return diff <= 0;
271 return diff >= 0;
272 default:
273 Q_ASSERT( false );
274 return false;
275 }
276}
277
278QVariant QgsExpressionNodeBinaryOperator::compareNonNullValues( QgsExpression *parent, const QgsExpressionContext *, const QVariant &vL, const QVariant &vR, BinaryOperator op )
279{
280 if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
281 {
282 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
284 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
286
287 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
288 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
289 // results (due to different hidden timezones), we force all datetime comparisons to treat
290 // all datetime values as having the same time zone
291 dL.setTimeSpec( Qt::UTC );
292 dR.setTimeSpec( Qt::UTC );
293
294 return compareOp<qint64>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
295 }
296 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
297 {
298 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
300 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
302 return compareOp<qint64>( dR.daysTo( dL ), op ) ? TVL_True : TVL_False;
303 }
304 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
305 {
306 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
308 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
310 return compareOp<int>( dR.msecsTo( dL ), op ) ? TVL_True : TVL_False;
311 }
312 else if ( ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
313 {
314 // do numeric comparison if both operators can be converted to numbers,
315 // and they aren't both string
316 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
318 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
320 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
321 }
322
323 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
324 {
325 // Documented behavior of QVariant::toBool() for each userType:
326 //
327 // For variant with userType():
328 //
329 // QMetaType::Bool:
330 // true if value is true
331 // false otherwise
332 //
333 // QMetaType::QChar, QMetaType::Double, QMetaType::Int,
334 // QMetaType::LongLong, QMetaType::UInt, and QMetaType::ULongLong:
335 // true if the value is non-zero
336 // false otherwise
337 //
338 // QMetaType::QString and QMetaType::QByteArray:
339 // false if its lower-case content is empty, "0" or "false"
340 // true otherwise
341 //
342 // All other variants always return false.
343
344 // Note: Boolean logical operators behave the same in C++ and SQL.
345 const bool vLBool = vL.toBool();
346 const bool vRBool = vR.toBool();
347 switch ( op )
348 {
349 case boEQ:
350 return vLBool == vRBool ? TVL_True : TVL_False;
351 case boNE:
352 return vLBool != vRBool ? TVL_True : TVL_False;
353 case boLT:
354 return vLBool < vRBool ? TVL_True : TVL_False;
355 case boLE:
356 return vLBool <= vRBool ? TVL_True : TVL_False;
357 case boGT:
358 return vLBool > vRBool ? TVL_True : TVL_False;
359 case boGE:
360 return vLBool >= vRBool ? TVL_True : TVL_False;
361 case boOr:
362 case boAnd:
363 case boRegexp:
364 case boLike:
365 case boNotLike:
366 case boILike:
367 case boNotILike:
368 case boIs:
369 case boIsNot:
370 case boPlus:
371 case boMinus:
372 case boMul:
373 case boDiv:
374 case boIntDiv:
375 case boMod:
376 case boPow:
377 case boConcat:
378 // should not happen
379 break;
380 }
381 return TVL_Unknown;
382 }
383
384 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
385 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
386 {
387 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
389 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
391 return compareOp< double >( fL - fR, op ) ? TVL_True : TVL_False;
392 }
393 else
394 {
395 // do string comparison otherwise
396 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
398 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
400 int diff = QString::compare( sL, sR );
401 return compareOp<int>( diff, op ) ? TVL_True : TVL_False;
402 }
403}
404
406{
407 QVariant vL = mOpLeft->eval( parent, context );
409
410 if ( mOp == boAnd || mOp == boOr )
411 {
412 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
414 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
415 return TVL_False; // shortcut -- no need to evaluate right-hand side
416 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
417 return TVL_True; // shortcut -- no need to evaluate right-hand side
418 }
419
420 QVariant vR = mOpRight->eval( parent, context );
422
423 switch ( mOp )
424 {
425 case boPlus:
426 if ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
427 {
428 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
430 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
432 return QVariant( sL + sR );
433 }
434 //intentional fall-through
435 [[fallthrough]];
436 case boMinus:
437 case boMul:
438 case boDiv:
439 case boMod:
440 {
441 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
442 return QVariant();
443 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
444 {
445 // both are integers - let's use integer arithmetic
446 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
448 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
450
451 if ( mOp == boMod && iR == 0 )
452 return QVariant();
453
454 return QVariant( computeInt( iL, iR ) );
455 }
456 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
457 {
458 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
460 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
462 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
463 {
464 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
465 return QVariant();
466 }
467 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
468 }
469 else if ( mOp == boPlus
470 && ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) || ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
471 {
472 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
474 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
476 QDateTime dt = QDateTime( date, time );
477 return QVariant( dt );
478 }
479 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
480 {
481 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
483 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
485 return date1 - date2;
486 }
487 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
488 {
489 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
491 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
493 return time1 - time2;
494 }
495 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
496 {
497 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
499 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
501 return QgsInterval( datetime1 - datetime2 );
502 }
503 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv ) && vL.userType() == QMetaType::Type::QColor && vR.userType() == QMetaType::Type::QColor )
504 {
505 bool isQColor = false;
506 const QColor colorL = QgsExpressionUtils::getColorValue( vL, parent, isQColor );
508 const QColor colorR = QgsExpressionUtils::getColorValue( vR, parent, isQColor );
510
511 if ( !colorL.isValid() || !colorR.isValid() )
512 {
513 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
514 return QVariant();
515 }
516
517 QColor::Spec colorLSpec = colorL.spec();
518 QColor::Spec colorRSpec = colorR.spec();
519
520 switch ( colorLSpec )
521 {
522 case QColor::Cmyk:
523 {
524 if ( colorRSpec != QColor::Cmyk )
525 {
526 parent->setEvalErrorString( tr( "Cannot combine a CMYK color with a non-CMYK color" ) );
527 return QVariant();
528 }
529
530 float lc, lm, ly, lk, la, rc, rm, ry, rk, ra;
531 colorL.getCmykF( &lc, &lm, &ly, &lk, &la );
532 colorR.getCmykF( &rc, &rm, &ry, &rk, &ra );
533 return QColor::fromCmykF(
534 static_cast<float>( std::clamp( computeDouble( lc, rc ), 0.0, 1.0 ) ),
535 static_cast<float>( std::clamp( computeDouble( lm, rm ), 0.0, 1.0 ) ),
536 static_cast<float>( std::clamp( computeDouble( ly, ry ), 0.0, 1.0 ) ),
537 static_cast<float>( std::clamp( computeDouble( lk, rk ), 0.0, 1.0 ) ),
538 la
539 );
540 }
541 case QColor::Hsl:
542 case QColor::Hsv:
543 case QColor::Rgb:
544 case QColor::ExtendedRgb:
545 {
546 if ( colorRSpec == QColor::Cmyk )
547 {
548 parent->setEvalErrorString( tr( "Cannot combine a non-CMYK color with a CMYK color" ) );
549 return QVariant();
550 }
551
552 float lr, lg, lb, la, rr, rg, rb, ra;
553 colorL.getRgbF( &lr, &lg, &lb, &la );
554 colorR.getRgbF( &rr, &rg, &rb, &ra );
555 QColor result = QColor::
556 fromRgbF( static_cast<float>( std::clamp( computeDouble( lr, rr ), 0.0, 1.0 ) ), static_cast<float>( std::clamp( computeDouble( lg, rg ), 0.0, 1.0 ) ), static_cast<float>( std::clamp( computeDouble( lb, rb ), 0.0, 1.0 ) ), la );
557 return result;
558 }
559 default:
560 return QVariant();
561 }
562 }
563 else if ( ( mOp == boPlus || mOp == boMinus || mOp == boMul || mOp == boDiv )
564 && ( ( ( vL.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vR ) ) || ( ( vR.userType() == QMetaType::Type::QColor ) && QgsExpressionUtils::isDoubleSafe( vL ) ) ) )
565 {
566 const bool colorLeft = vL.userType() == QMetaType::Type::QColor;
567 bool isQColor = false;
568 const QColor color = QgsExpressionUtils::getColorValue( colorLeft ? vL : vR, parent, isQColor );
570
571 if ( !color.isValid() )
572 {
573 parent->setEvalErrorString( tr( "Cannot perform operation on invalid color" ) );
574 return QVariant();
575 }
576
577 const double value = QgsExpressionUtils::getDoubleValue( colorLeft ? vR : vL, parent );
579
580 if ( mOp == boDiv && value == 0.0 )
581 {
582 return QVariant();
583 }
584
585 // let's not divide with color
586 if ( !colorLeft && mOp == boDiv )
587 {
588 parent->setEvalErrorString( tr( "Can't perform / with a color value on the right" ) );
589 return QVariant();
590 }
591
592 switch ( color.spec() )
593 {
594 case QColor::Cmyk:
595 {
596 float c, m, y, k, a;
597 color.getCmykF( &c, &m, &y, &k, &a );
598 const double dc = static_cast<double>( c );
599 const double dm = static_cast<double>( m );
600 const double dy = static_cast<double>( y );
601 const double dk = static_cast<double>( k );
602
603 return QColor::fromCmykF(
604 static_cast<float>( std::clamp( computeDouble( colorLeft ? dc : value, colorLeft ? value : dc ), 0.0, 1.0 ) ),
605 static_cast<float>( std::clamp( computeDouble( colorLeft ? dm : value, colorLeft ? value : dm ), 0.0, 1.0 ) ),
606 static_cast<float>( std::clamp( computeDouble( colorLeft ? dy : value, colorLeft ? value : dy ), 0.0, 1.0 ) ),
607 static_cast<float>( std::clamp( computeDouble( colorLeft ? dk : value, colorLeft ? value : dk ), 0.0, 1.0 ) ),
608 a
609 );
610 }
611 case QColor::Hsl:
612 case QColor::Hsv:
613 case QColor::Rgb:
614 case QColor::ExtendedRgb: // color_rgbf constructor clamps it to 0-1, so we do the same here
615 {
616 float r, g, b, a;
617 color.getRgbF( &r, &g, &b, &a );
618 const double dr = static_cast<double>( r );
619 const double dg = static_cast<double>( g );
620 const double db = static_cast<double>( b );
621
622 return QColor::fromRgbF(
623 static_cast<float>( std::clamp( computeDouble( colorLeft ? dr : value, colorLeft ? value : dr ), 0.0, 1.0 ) ),
624 static_cast<float>( std::clamp( computeDouble( colorLeft ? dg : value, colorLeft ? value : dg ), 0.0, 1.0 ) ),
625 static_cast<float>( std::clamp( computeDouble( colorLeft ? db : value, colorLeft ? value : db ), 0.0, 1.0 ) ),
626 a
627 );
628 }
629 default:
630 return QVariant();
631 }
632 }
633 else
634 {
635 // general floating point arithmetic
636 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
638 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
640 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
641 return QVariant(); // silently handle division by zero and return NULL
642 return QVariant( computeDouble( fL, fR ) );
643 }
644 }
645 case boIntDiv:
646 {
647 //integer division
648 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
650 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
652 if ( fR == 0. )
653 return QVariant(); // silently handle division by zero and return NULL
654 return QVariant( qlonglong( std::floor( fL / fR ) ) );
655 }
656 case boPow:
657 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
658 return QVariant();
659 else
660 {
661 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
663 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
665 return QVariant( std::pow( fL, fR ) );
666 }
667
668 case boAnd:
669 {
670 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
672 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
673 }
674
675 case boOr:
676 {
677 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
679 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
680 }
681
682 case boEQ:
683 case boNE:
684 case boLT:
685 case boGT:
686 case boLE:
687 case boGE:
688 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
689 {
690 return TVL_Unknown;
691 }
692 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
693 {
694 // verify that we have two lists
695 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
696 return TVL_Unknown;
697
698 // and search for not equal respective items
699 QVariantList lL = vL.toList();
700 QVariantList lR = vR.toList();
701 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
702 {
703 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
704 continue; // same behavior as PostgreSQL
705
706 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
707 {
708 switch ( mOp )
709 {
710 case boEQ:
711 return false;
712 case boNE:
713 return true;
714 case boLT:
715 case boLE:
716 return QgsExpressionUtils::isNull( lR.at( i ) );
717 case boGT:
718 case boGE:
719 return QgsExpressionUtils::isNull( lL.at( i ) );
720 default:
721 Q_ASSERT( false );
722 return TVL_Unknown;
723 }
724 }
725
726 QgsExpressionNodeLiteral nL( lL.at( i ) );
727 QgsExpressionNodeLiteral nR( lR.at( i ) );
728 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
729 QVariant eq = eqNode.eval( parent, context );
731 if ( eq == TVL_False )
732 {
733 // return the two items comparison
734 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
735 QVariant v = node.eval( parent, context );
737 return v;
738 }
739 }
740
741 // default to length comparison
742 switch ( mOp )
743 {
744 case boEQ:
745 return lL.length() == lR.length();
746 case boNE:
747 return lL.length() != lR.length();
748 case boLT:
749 return lL.length() < lR.length();
750 case boGT:
751 return lL.length() > lR.length();
752 case boLE:
753 return lL.length() <= lR.length();
754 case boGE:
755 return lL.length() >= lR.length();
756 default:
757 Q_ASSERT( false );
758 return TVL_Unknown;
759 }
760 }
761 else
762 {
763 return compareNonNullValues( parent, context, vL, vR, mOp );
764 }
765
766 case boIs:
767 case boIsNot:
768 {
769 const bool vLNull = QgsExpressionUtils::isNull( vL );
770 const bool vRNull = QgsExpressionUtils::isNull( vR );
771 if ( vLNull && vRNull ) // both operators null
772 return ( mOp == boIs ? TVL_True : TVL_False );
773 else if ( vLNull || vRNull ) // one operator null
774 return ( mOp == boIs ? TVL_False : TVL_True );
775 else // both operators non-null
776 {
777 return compareNonNullValues( parent, context, vL, vR, mOp == boIs ? boEQ : boNE );
778 }
779 }
780
781 case boRegexp:
782 case boLike:
783 case boNotLike:
784 case boILike:
785 case boNotILike:
786 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
787 return TVL_Unknown;
788 else
789 {
790 QString str = QgsExpressionUtils::getStringValue( vL, parent );
792 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
794 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
795 bool matches;
796 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
797 {
798 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
799 // manage escape % and _
800 if ( esc_regexp.startsWith( '%' ) )
801 {
802 esc_regexp.replace( 0, 1, u".*"_s );
803 }
804 const thread_local QRegularExpression rx1( u"[^\\\\](%)"_s );
805 int pos = 0;
806 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
807 {
808 esc_regexp.replace( pos + 1, 1, u".*"_s );
809 pos += 1;
810 }
811 const thread_local QRegularExpression rx2( u"\\\\%"_s );
812 esc_regexp.replace( rx2, u"%"_s );
813 if ( esc_regexp.startsWith( '_' ) )
814 {
815 esc_regexp.replace( 0, 1, u"."_s );
816 }
817 const thread_local QRegularExpression rx3( u"[^\\\\](_)"_s );
818 pos = 0;
819 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
820 {
821 esc_regexp.replace( pos + 1, 1, '.' );
822 pos += 1;
823 }
824 esc_regexp.replace( "\\\\_"_L1, "_"_L1 );
825
826 matches
827 = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption )
828 .match( str )
829 .hasMatch();
830 }
831 else
832 {
833 matches = QRegularExpression( regexp ).match( str ).hasMatch();
834 }
835
836 if ( mOp == boNotLike || mOp == boNotILike )
837 {
838 matches = !matches;
839 }
840
841 return matches ? TVL_True : TVL_False;
842 }
843
844 case boConcat:
845 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
846 return QVariant();
847 else
848 {
849 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
851 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
853 return QVariant( sL + sR );
854 }
855 }
856 Q_ASSERT( false );
857 return QVariant();
858}
859
860qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
861{
862 switch ( mOp )
863 {
864 case boPlus:
865 return x + y;
866 case boMinus:
867 return x - y;
868 case boMul:
869 return x * y;
870 case boDiv:
871 return x / y;
872 case boMod:
873 return x % y;
874 default:
875 Q_ASSERT( false );
876 return 0;
877 }
878}
879
880QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
881{
882 switch ( mOp )
883 {
884 case boPlus:
885 return d.addSecs( i->seconds() );
886 case boMinus:
887 return d.addSecs( -i->seconds() );
888 default:
889 Q_ASSERT( false );
890 return QDateTime();
891 }
892}
893
894double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
895{
896 switch ( mOp )
897 {
898 case boPlus:
899 return x + y;
900 case boMinus:
901 return x - y;
902 case boMul:
903 return x * y;
904 case boDiv:
905 return x / y;
906 case boMod:
907 return std::fmod( x, y );
908 default:
909 Q_ASSERT( false );
910 return 0;
911 }
912}
913
918
920{
921 // if this is an OR, try to collapse the OR expression into an IN node
922 if ( mOp == boOr )
923 {
924 // First step: flatten OR chain and collect values
925 QMap<QString, QgsExpressionNode::NodeList> orValuesMap;
926 QList<QString> orFieldNames;
927
928 // Get a list of all the OR and IN nodes chained together
929 std::function<bool( QgsExpressionNode * )> visitOrNodes = [&visitOrNodes, &orValuesMap, &orFieldNames]( QgsExpressionNode *node ) -> bool {
931 {
932 if ( op->op() != boOr && op->op() != boEQ )
933 {
934 return false;
935 }
936
937 if ( op->op() == boEQ )
938 {
939 // If left is a column ref and right is a literal, collect
940 if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opLeft() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opRight() ) ) )
941 {
942 const QString fieldName = op->opLeft()->dump();
943 if ( !orValuesMap.contains( fieldName ) )
944 {
945 orFieldNames.append( fieldName );
946 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
947 }
948 orValuesMap[fieldName].append( op->opRight()->clone() );
949 return true;
950 }
951 else if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opRight() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opLeft() ) ) )
952 {
953 const QString fieldName = op->opRight()->dump();
954 if ( !orValuesMap.contains( fieldName ) )
955 {
956 orFieldNames.append( fieldName );
957 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
958 }
959 orValuesMap[fieldName].append( op->opLeft()->clone() );
960 return true;
961 }
962 return false;
963 }
964
965 if ( visitOrNodes( op->opLeft() ) && visitOrNodes( op->opRight() ) )
966 {
967 return true;
968 }
969 }
970 else if ( QgsExpressionNodeInOperator *inOp = dynamic_cast<QgsExpressionNodeInOperator *>( node ) )
971 {
972 if ( inOp->isNotIn() || inOp->node()->nodeType() != QgsExpressionNode::ntColumnRef )
973 {
974 return false;
975 }
976
977 const QString fieldName = inOp->node()->dump();
978
979 // Check if all nodes are literals
980 const auto nodes = inOp->list()->list();
981 for ( const auto &valueNode : std::as_const( nodes ) )
982 {
983 if ( valueNode->nodeType() != QgsExpressionNode::ntLiteral )
984 {
985 return false;
986 }
987 }
988
989 if ( !orValuesMap.contains( fieldName ) )
990 {
991 orFieldNames.append( fieldName );
992 orValuesMap.insert( fieldName, *inOp->list()->clone() );
993 }
994 else
995 {
996 for ( const auto &valueNode : std::as_const( nodes ) )
997 {
998 orValuesMap[fieldName].append( valueNode->clone() );
999 }
1000 }
1001
1002 return true;
1003 }
1004 return false;
1005 };
1006
1007
1008 // Second step: build the OR chain of IN operators
1009 if ( visitOrNodes( this ) && !orValuesMap.empty() )
1010 {
1011 std::unique_ptr<QgsExpressionNode> currentNode;
1012 for ( const auto &fieldName : std::as_const( orFieldNames ) )
1013 {
1014 auto orValuesIt = orValuesMap.find( fieldName );
1015 if ( orValuesIt.value().count() == 1 )
1016 {
1017 auto eqNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boEQ, new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().at( 0 )->clone() );
1018 if ( currentNode )
1019 {
1020 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), eqNode.release() );
1021 }
1022 else
1023 {
1024 currentNode = std::move( eqNode );
1025 }
1026 }
1027 else
1028 {
1029 auto inNode = std::make_unique<QgsExpressionNodeInOperator>( new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().clone() );
1030 if ( currentNode )
1031 {
1032 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), inNode.release() );
1033 }
1034 else
1035 {
1036 currentNode = std::move( inNode );
1037 }
1038 }
1039 }
1040
1041
1042 if ( currentNode )
1043 {
1044 mCompiledSimplifiedNode = std::move( currentNode );
1045 }
1046 }
1047 }
1048
1049 bool resL = mOpLeft->prepare( parent, context );
1050 bool resR = mOpRight->prepare( parent, context );
1051 return resL && resR;
1052}
1053
1055{
1056 // see left/right in qgsexpressionparser.yy
1057 switch ( mOp )
1058 {
1059 case boOr:
1060 return 1;
1061
1062 case boAnd:
1063 return 2;
1064
1065 case boEQ:
1066 case boNE:
1067 case boLE:
1068 case boGE:
1069 case boLT:
1070 case boGT:
1071 case boRegexp:
1072 case boLike:
1073 case boILike:
1074 case boNotLike:
1075 case boNotILike:
1076 case boIs:
1077 case boIsNot:
1078 return 3;
1079
1080 case boPlus:
1081 case boMinus:
1082 return 4;
1083
1084 case boMul:
1085 case boDiv:
1086 case boIntDiv:
1087 case boMod:
1088 return 5;
1089
1090 case boPow:
1091 return 6;
1092
1093 case boConcat:
1094 return 7;
1095 }
1096 Q_ASSERT( false && "unexpected binary operator" );
1097 return -1;
1098}
1099
1101{
1102 // see left/right in qgsexpressionparser.yy
1103 switch ( mOp )
1104 {
1105 case boOr:
1106 case boAnd:
1107 case boEQ:
1108 case boNE:
1109 case boLE:
1110 case boGE:
1111 case boLT:
1112 case boGT:
1113 case boRegexp:
1114 case boLike:
1115 case boILike:
1116 case boNotLike:
1117 case boNotILike:
1118 case boIs:
1119 case boIsNot:
1120 case boPlus:
1121 case boMinus:
1122 case boMul:
1123 case boDiv:
1124 case boIntDiv:
1125 case boMod:
1126 case boConcat:
1127 return true;
1128
1129 case boPow:
1130 return false;
1131 }
1132 Q_ASSERT( false && "unexpected binary operator" );
1133 return false;
1134}
1135
1137{
1138 QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft.get() );
1139 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight.get() );
1140 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight.get() );
1141
1142 QString rdump( mOpRight->dump() );
1143
1144 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
1145 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
1146 {
1147 rdump.prepend( '(' ).append( ')' );
1148 }
1149
1150 QString fmt;
1151 if ( leftAssociative() )
1152 {
1153 fmt += lOp && ( lOp->precedence() < precedence() ) ? u"(%1)"_s : u"%1"_s;
1154 fmt += " %2 "_L1;
1155 fmt += rOp && ( rOp->precedence() <= precedence() ) ? u"(%3)"_s : u"%3"_s;
1156 }
1157 else
1158 {
1159 fmt += lOp && ( lOp->precedence() <= precedence() ) ? u"(%1)"_s : u"%1"_s;
1160 fmt += " %2 "_L1;
1161 fmt += rOp && ( rOp->precedence() < precedence() ) ? u"(%3)"_s : u"%3"_s;
1162 }
1163
1164 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
1165}
1166
1168{
1169 if ( hasCachedStaticValue() )
1170 return QSet< QString >();
1171
1172 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
1173}
1174
1176{
1177 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
1178}
1179
1181{
1182 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
1183}
1184
1185QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
1186{
1187 QList<const QgsExpressionNode *> lst;
1188 lst << this;
1189 lst += mOpLeft->nodes() + mOpRight->nodes();
1190 return lst;
1191}
1192
1194{
1195 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
1196}
1197
1199{
1200 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
1201 cloneTo( copy );
1202 return copy;
1203}
1204
1206{
1207 const bool leftStatic = mOpLeft->isStatic( parent, context );
1208 const bool rightStatic = mOpRight->isStatic( parent, context );
1209
1210 if ( leftStatic && rightStatic )
1211 return true;
1212
1213 // special logic for certain ops...
1214 switch ( mOp )
1215 {
1217 {
1218 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
1219 // of the value of the other node!
1220 if ( leftStatic )
1221 {
1222 mOpLeft->prepare( parent, context );
1223 if ( mOpLeft->hasCachedStaticValue() )
1224 {
1225 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1226 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1227 {
1228 mCachedStaticValue = true;
1229 mHasCachedValue = true;
1230 return true;
1231 }
1232 }
1233 }
1234 else if ( rightStatic )
1235 {
1236 mOpRight->prepare( parent, context );
1237 if ( mOpRight->hasCachedStaticValue() )
1238 {
1239 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1240 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1241 {
1242 mCachedStaticValue = true;
1243 mHasCachedValue = true;
1244 return true;
1245 }
1246 }
1247 }
1248
1249 break;
1250 }
1252 {
1253 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
1254 // of the value of the other node!
1255
1256 if ( leftStatic )
1257 {
1258 mOpLeft->prepare( parent, context );
1259 if ( mOpLeft->hasCachedStaticValue() )
1260 {
1261 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1262 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1263 {
1264 mCachedStaticValue = false;
1265 mHasCachedValue = true;
1266 return true;
1267 }
1268 }
1269 }
1270 else if ( rightStatic )
1271 {
1272 mOpRight->prepare( parent, context );
1273 if ( mOpRight->hasCachedStaticValue() )
1274 {
1275 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1276 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1277 {
1278 mCachedStaticValue = false;
1279 mHasCachedValue = true;
1280 return true;
1281 }
1282 }
1283 }
1284
1285 break;
1286 }
1287
1309 break;
1310 }
1311
1312 return false;
1313}
1314
1316{
1317 std::unique_ptr< QgsExpressionNode > opLeft( mOpLeft->simplifiedNode() );
1318 std::unique_ptr< QgsExpressionNode > opRight( mOpRight->simplifiedNode() );
1319
1320 // if both operands are literals, evaluate the operation
1321 if ( opLeft->nodeType() == ntLiteral && opRight->nodeType() == ntLiteral )
1322 {
1323 QgsExpressionNodeBinaryOperator tempNode( mOp, opLeft->clone(), opRight->clone() );
1324 QgsExpression parentExp;
1325 QVariant result = tempNode.eval( &parentExp, nullptr );
1326 if ( !parentExp.hasEvalError() )
1327 {
1328 return new QgsExpressionNodeLiteral( result );
1329 }
1330 }
1331
1332 return new QgsExpressionNodeBinaryOperator( mOp, opLeft.release(), opRight.release() );
1333}
1334
1335//
1336
1338{
1339 if ( mList->count() == 0 )
1340 return mNotIn ? TVL_True : TVL_False;
1341 QVariant v1 = mNode->eval( parent, context );
1343 if ( QgsExpressionUtils::isNull( v1 ) )
1344 return TVL_Unknown;
1345
1346 bool listHasNull = false;
1347
1348 const QList< QgsExpressionNode * > nodeList = mList->list();
1349 for ( QgsExpressionNode *n : nodeList )
1350 {
1351 QVariant v2 = n->eval( parent, context );
1353 if ( QgsExpressionUtils::isNull( v2 ) )
1354 listHasNull = true;
1355 else
1356 {
1357 bool equal = false;
1358 // check whether they are equal
1359 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) && QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
1360 {
1361 // do numeric comparison if both operators can be converted to numbers,
1362 // and they aren't both string
1363 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
1365 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
1367 equal = qgsDoubleNear( f1, f2 );
1368 }
1369 else
1370 {
1371 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1373 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1375 equal = QString::compare( s1, s2 ) == 0;
1376 }
1377
1378 if ( equal ) // we know the result
1379 return mNotIn ? TVL_False : TVL_True;
1380 }
1381 }
1382
1383 // item not found
1384 if ( listHasNull )
1385 return TVL_Unknown;
1386 else
1387 return mNotIn ? TVL_True : TVL_False;
1388}
1389
1392
1397
1399{
1400 bool res = mNode->prepare( parent, context );
1401 const QList< QgsExpressionNode * > nodeList = mList->list();
1402 for ( QgsExpressionNode *n : nodeList )
1403 {
1404 res = res && n->prepare( parent, context );
1405 }
1406 return res;
1407}
1408
1410{
1411 return u"%1 %2 IN (%3)"_s.arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1412}
1413
1415{
1416 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1417 cloneTo( copy );
1418 return copy;
1419}
1420
1422{
1423 if ( !mNode->isStatic( parent, context ) )
1424 return false;
1425
1426 const QList< QgsExpressionNode * > nodeList = mList->list();
1427 for ( QgsExpressionNode *n : nodeList )
1428 {
1429 if ( !n->isStatic( parent, context ) )
1430 return false;
1431 }
1432
1433 return true;
1434}
1435
1437{
1438 std::unique_ptr< QgsExpressionNode > simplifiedTargetNode( mNode->simplifiedNode() );
1439 bool allLiterals = simplifiedTargetNode->nodeType() == ntLiteral;
1440
1441 auto simplifiedList = std::make_unique< QgsExpressionNode::NodeList >();
1442 simplifiedList->reserve( mList->count() );
1443 for ( QgsExpressionNode *node : mList->list() )
1444 {
1445 std::unique_ptr< QgsExpressionNode > simplifiedItem( node->simplifiedNode() );
1446 if ( simplifiedItem->nodeType() != ntLiteral )
1447 {
1448 allLiterals = false;
1449 }
1450
1451 if ( simplifiedTargetNode->nodeType() == ntLiteral
1452 && simplifiedItem->nodeType() == ntLiteral
1453 && qgis::down_cast< QgsExpressionNodeLiteral *>( simplifiedTargetNode.get() )->value() == qgis::down_cast< QgsExpressionNodeLiteral * >( simplifiedItem.get() )->value() )
1454 {
1455 return new QgsExpressionNodeLiteral( !mNotIn );
1456 }
1457
1458 simplifiedList->append( simplifiedItem.release() );
1459 }
1460
1461 // if target node and all items in the list are literals, we can just directly evaluate and replace with a literal
1462 if ( allLiterals )
1463 {
1464 QgsExpressionNodeInOperator tempNode( simplifiedTargetNode->clone(), simplifiedList->clone(), mNotIn );
1465 QgsExpression parentExp;
1466 QVariant result = tempNode.eval( &parentExp, nullptr );
1467 if ( !parentExp.hasEvalError() )
1468 {
1469 return new QgsExpressionNodeLiteral( result );
1470 }
1471 }
1472
1473 return new QgsExpressionNodeInOperator( simplifiedTargetNode.release(), simplifiedList.release(), mNotIn );
1474}
1475
1476//
1477
1479{
1480 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1481 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1482
1483 QVariant res = fd->run( mArgs.get(), context, parent, this );
1485
1486 // everything went fine
1487 return res;
1488}
1489
1491 : mFnIndex( fnIndex )
1492{
1493 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1494 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1495 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1496 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1497
1498 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1499 const int functionParamsSize = functionParams.size();
1500 if ( functionParams.isEmpty() )
1501 {
1502 // function does not support parameters
1503 mArgs.reset( args );
1504 }
1505 else if ( !args )
1506 {
1507 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1508 mArgs = std::make_unique<NodeList>();
1509 mArgs->reserve( functionParamsSize );
1510 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1511 {
1512 // insert default value for QgsExpressionFunction::Parameter
1513 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1514 }
1515 }
1516 else
1517 {
1518 mArgs = std::make_unique<NodeList>();
1519 mArgs->reserve( functionParamsSize );
1520
1521 int idx = 0;
1522 const QStringList argNames = args->names();
1523 const QList<QgsExpressionNode *> argList = args->list();
1524 //first loop through unnamed arguments
1525 {
1526 const int argNamesSize = argNames.size();
1527 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1528 {
1529 mArgs->append( argList.at( idx )->clone() );
1530 idx++;
1531 }
1532 }
1533
1534 //next copy named QgsExpressionFunction::Parameters in order expected by function
1535 for ( ; idx < functionParamsSize; ++idx )
1536 {
1537 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1538 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1539 if ( nodeIdx < 0 )
1540 {
1541 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1542 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1543 }
1544 else
1545 {
1546 mArgs->append( argList.at( nodeIdx )->clone() );
1547 }
1548 }
1549
1550 delete args;
1551 }
1552}
1553
1556
1561
1563{
1564 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1565
1566 bool res = fd->prepare( this, parent, context );
1567 if ( mArgs && !fd->lazyEval() )
1568 {
1569 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1570 for ( QgsExpressionNode *n : nodeList )
1571 {
1572 res = res && n->prepare( parent, context );
1573 }
1574 }
1575 return res;
1576}
1577
1579{
1580 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1581 if ( fd->params() == 0 )
1582 return u"%1%2"_s.arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : u"()"_s ); // special column
1583 else
1584 return u"%1(%2)"_s.arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1585}
1586
1588{
1589 if ( hasCachedStaticValue() )
1590 return QSet< QString >();
1591
1592 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1593 QSet<QString> functionColumns = fd->referencedColumns( this );
1594
1595 if ( !mArgs )
1596 {
1597 //no referenced columns in arguments, just return function's referenced columns
1598 return functionColumns;
1599 }
1600
1601 int paramIndex = 0;
1602 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1603 for ( QgsExpressionNode *n : nodeList )
1604 {
1605 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1606 functionColumns.unite( n->referencedColumns() );
1607 paramIndex++;
1608 }
1609
1610 return functionColumns;
1611}
1612
1614{
1615 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1616 if ( fd->name() == "var"_L1 )
1617 {
1618 if ( !mArgs->list().isEmpty() )
1619 {
1620 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1621 if ( var )
1622 return QSet<QString>() << var->value().toString();
1623 }
1624 return QSet<QString>() << QString();
1625 }
1626 else
1627 {
1628 QSet<QString> functionVariables = QSet<QString>();
1629
1630 if ( !mArgs )
1631 return functionVariables;
1632
1633 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1634 for ( QgsExpressionNode *n : nodeList )
1635 {
1636 functionVariables.unite( n->referencedVariables() );
1637 }
1638
1639 return functionVariables;
1640 }
1641}
1642
1644{
1645 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1646 QSet<QString> functions = QSet<QString>();
1647 functions.insert( fd->name() );
1648
1649 if ( !mArgs )
1650 return functions;
1651
1652 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1653 for ( QgsExpressionNode *n : nodeList )
1654 {
1655 functions.unite( n->referencedFunctions() );
1656 }
1657 return functions;
1658}
1659
1660QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1661{
1662 QList<const QgsExpressionNode *> lst;
1663 lst << this;
1664 if ( !mArgs )
1665 return lst;
1666
1667 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1668 for ( QgsExpressionNode *n : nodeList )
1669 {
1670 lst += n->nodes();
1671 }
1672 return lst;
1673}
1674
1676{
1677 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1678 if ( mArgs )
1679 {
1680 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1681 for ( QgsExpressionNode *n : nodeList )
1682 needs |= n->needsGeometry();
1683 }
1684 return needs;
1685}
1686
1688{
1689 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1690 cloneTo( copy );
1691 return copy;
1692}
1693
1695{
1696 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1697}
1698
1700{
1701 auto simplifiedArgs = std::make_unique< QgsExpressionNode::NodeList >();
1702 if ( mArgs )
1703 {
1704 simplifiedArgs->reserve( mArgs->count() );
1705 for ( QgsExpressionNode *arg : mArgs->list() )
1706 {
1707 std::unique_ptr< QgsExpressionNode > simplifiedArg( arg->simplifiedNode() );
1708 simplifiedArgs->append( simplifiedArg.release() );
1709 }
1710
1711 return new QgsExpressionNodeFunction( mFnIndex, simplifiedArgs.release() );
1712 }
1713 return clone();
1714}
1715
1717{
1718 if ( !args || !args->hasNamedNodes() )
1719 return true;
1720
1721 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1722 if ( functionParams.isEmpty() )
1723 {
1724 error = u"%1 does not support named QgsExpressionFunction::Parameters"_s.arg( QgsExpression::Functions()[fnIndex]->name() );
1725 return false;
1726 }
1727 else
1728 {
1729 QSet< int > providedArgs;
1730 QSet< int > handledArgs;
1731 int idx = 0;
1732 //first loop through unnamed arguments
1733 while ( args->names().at( idx ).isEmpty() )
1734 {
1735 providedArgs << idx;
1736 handledArgs << idx;
1737 idx++;
1738 }
1739
1740 //next check named QgsExpressionFunction::Parameters
1741 for ( ; idx < functionParams.count(); ++idx )
1742 {
1743 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1744 if ( nodeIdx < 0 )
1745 {
1746 if ( !functionParams.at( idx ).optional() )
1747 {
1748 error = u"No value specified for QgsExpressionFunction::Parameter '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1749 return false;
1750 }
1751 }
1752 else
1753 {
1754 if ( providedArgs.contains( idx ) )
1755 {
1756 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1757 return false;
1758 }
1759 }
1760 providedArgs << idx;
1761 handledArgs << nodeIdx;
1762 }
1763
1764 //last check for bad names
1765 idx = 0;
1766 const QStringList nameList = args->names();
1767 for ( const QString &name : nameList )
1768 {
1769 if ( !name.isEmpty() && !functionParams.contains( name ) )
1770 {
1771 error = u"Invalid QgsExpressionFunction::Parameter name '%1' for %2"_s.arg( name, QgsExpression::Functions()[fnIndex]->name() );
1772 return false;
1773 }
1774 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1775 {
1776 int functionIdx = functionParams.indexOf( name );
1777 if ( providedArgs.contains( functionIdx ) )
1778 {
1779 error = u"Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2"_s.arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1780 return false;
1781 }
1782 }
1783 idx++;
1784 }
1785 }
1786 return true;
1787}
1788
1789//
1790
1792{
1793 Q_UNUSED( context )
1794 Q_UNUSED( parent )
1795 return mValue;
1796}
1797
1802
1804{
1805 Q_UNUSED( parent )
1806 Q_UNUSED( context )
1807 return true;
1808}
1809
1810
1812{
1813 if ( QgsVariantUtils::isNull( mValue ) )
1814 return u"NULL"_s;
1815
1816 switch ( mValue.userType() )
1817 {
1818 case QMetaType::Type::Int:
1819 return QString::number( mValue.toInt() );
1820 case QMetaType::Type::Double:
1821 return qgsDoubleToString( mValue.toDouble() );
1822 case QMetaType::Type::LongLong:
1823 return QString::number( mValue.toLongLong() );
1824 case QMetaType::Type::QString:
1825 return QgsExpression::quotedString( mValue.toString() );
1826 case QMetaType::Type::QTime:
1827 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1828 case QMetaType::Type::QDate:
1829 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1830 case QMetaType::Type::QDateTime:
1831 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1832 case QMetaType::Type::Bool:
1833 return mValue.toBool() ? u"TRUE"_s : u"FALSE"_s;
1834 default:
1835 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1836 }
1837}
1838
1840{
1841 return valueAsString();
1842}
1843
1845{
1846 return QSet<QString>();
1847}
1848
1850{
1851 return QSet<QString>();
1852}
1853
1855{
1856 return QSet<QString>();
1857}
1858
1859QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1860{
1861 QList<const QgsExpressionNode *> lst;
1862 lst << this;
1863 return lst;
1864}
1865
1867{
1868 return false;
1869}
1870
1872{
1874 cloneTo( copy );
1875 return copy;
1876}
1877
1879{
1880 Q_UNUSED( context )
1881 Q_UNUSED( parent )
1882 return true;
1883}
1884
1885//
1886
1888{
1889 Q_UNUSED( parent )
1890 int index = mIndex;
1891
1892 if ( index < 0 )
1893 {
1894 // have not yet found field index - first check explicitly set fields collection
1895 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1896 {
1897 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1898 index = fields.lookupField( mName );
1899 }
1900 }
1901
1902 if ( context )
1903 {
1904 QgsFeature feature = context->feature();
1905 if ( feature.isValid() )
1906 {
1907 if ( index >= 0 )
1908 return feature.attribute( index );
1909 else
1910 return feature.attribute( mName );
1911 }
1912 else
1913 {
1914 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1915 }
1916 }
1917 if ( index < 0 )
1918 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1919 return QVariant();
1920}
1921
1926
1928{
1929 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1930 return false;
1931
1932 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1933
1934 mIndex = fields.lookupField( mName );
1935
1936 if ( mIndex == -1 && context->hasFeature() )
1937 {
1938 mIndex = context->feature().fieldNameIndex( mName );
1939 }
1940
1941 if ( mIndex == -1 )
1942 {
1943 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1944 return false;
1945 }
1946 return true;
1947}
1948
1950{
1951 const thread_local QRegularExpression re( u"^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$"_s );
1952 const QRegularExpressionMatch match = re.match( mName );
1953 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1954}
1955
1957{
1958 return QSet<QString>() << mName;
1959}
1960
1962{
1963 return QSet<QString>();
1964}
1965
1967{
1968 return QSet<QString>();
1969}
1970
1971QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1972{
1973 QList<const QgsExpressionNode *> result;
1974 result << this;
1975 return result;
1976}
1977
1979{
1980 return false;
1981}
1982
1984{
1986 cloneTo( copy );
1987 return copy;
1988}
1989
1991{
1992 Q_UNUSED( context )
1993 Q_UNUSED( parent )
1994 return false;
1995}
1996
1997//
1998
2005
2007{
2008 qDeleteAll( mConditions );
2009}
2010
2015
2017{
2018 for ( WhenThen *cond : std::as_const( mConditions ) )
2019 {
2020 QVariant vWhen = cond->mWhenExp->eval( parent, context );
2021 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
2023 if ( tvl == QgsExpressionUtils::True )
2024 {
2025 QVariant vRes = cond->mThenExp->eval( parent, context );
2027 return vRes;
2028 }
2029 }
2030
2031 if ( mElseExp )
2032 {
2033 QVariant vElse = mElseExp->eval( parent, context );
2035 return vElse;
2036 }
2037
2038 // return NULL if no condition is matching
2039 return QVariant();
2040}
2041
2043{
2044 bool foundAnyNonStaticConditions = false;
2045 for ( WhenThen *cond : std::as_const( mConditions ) )
2046 {
2047 const bool res = cond->mWhenExp->prepare( parent, context ) && cond->mThenExp->prepare( parent, context );
2048 if ( !res )
2049 return false;
2050
2051 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
2052 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
2053 {
2054 // ok, we now that we'll ALWAYS be picking the same condition, as the "WHEN" clause for this condition (and all previous conditions) is a static
2055 // value, and the static value for this WHEN clause is True.
2056 if ( cond->mThenExp->hasCachedStaticValue() )
2057 {
2058 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
2059 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
2060 mHasCachedValue = true;
2061 return true;
2062 }
2063 else
2064 {
2065 // we know at least that we'll ALWAYS be picking the same condition, so even though the THEN node is non-static we can effectively replace
2066 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
2067 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
2068 return true;
2069 }
2070 }
2071 }
2072
2073 if ( mElseExp )
2074 {
2075 const bool res = mElseExp->prepare( parent, context );
2076 if ( !res )
2077 return false;
2078
2079 if ( !foundAnyNonStaticConditions )
2080 {
2081 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
2082 if ( mElseExp->hasCachedStaticValue() )
2083 {
2084 mCachedStaticValue = mElseExp->cachedStaticValue();
2085 mHasCachedValue = true;
2086 return true;
2087 }
2088 else
2089 {
2090 // so even though the ELSE node is non-static we can effectively replace
2091 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
2092 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
2093 return true;
2094 }
2095 }
2096 }
2097
2098 return true;
2099}
2100
2102{
2103 QString msg( u"CASE"_s );
2104 for ( WhenThen *cond : mConditions )
2105 {
2106 msg += u" WHEN %1 THEN %2"_s.arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
2107 }
2108 if ( mElseExp )
2109 msg += u" ELSE %1"_s.arg( mElseExp->dump() );
2110 msg += " END"_L1;
2111 return msg;
2112}
2113
2115{
2116 if ( hasCachedStaticValue() )
2117 return QSet< QString >();
2118
2119 QSet<QString> lst;
2120 for ( WhenThen *cond : mConditions )
2121 {
2122 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
2123 }
2124
2125 if ( mElseExp )
2126 lst += mElseExp->referencedColumns();
2127
2128 return lst;
2129}
2130
2132{
2133 QSet<QString> lst;
2134 for ( WhenThen *cond : mConditions )
2135 {
2136 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
2137 }
2138
2139 if ( mElseExp )
2140 lst += mElseExp->referencedVariables();
2141
2142 return lst;
2143}
2144
2146{
2147 QSet<QString> lst;
2148 for ( WhenThen *cond : mConditions )
2149 {
2150 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
2151 }
2152
2153 if ( mElseExp )
2154 lst += mElseExp->referencedFunctions();
2155
2156 return lst;
2157}
2158
2159QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
2160{
2161 QList<const QgsExpressionNode *> lst;
2162 lst << this;
2163 for ( WhenThen *cond : mConditions )
2164 {
2165 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
2166 }
2167
2168 if ( mElseExp )
2169 lst += mElseExp->nodes();
2170
2171 return lst;
2172}
2173
2175{
2176 for ( WhenThen *cond : mConditions )
2177 {
2178 if ( cond->mWhenExp->needsGeometry() || cond->mThenExp->needsGeometry() )
2179 return true;
2180 }
2181
2182 return mElseExp && mElseExp->needsGeometry();
2183}
2184
2186{
2188 conditions.reserve( mConditions.size() );
2189 for ( WhenThen *wt : mConditions )
2190 conditions.append( wt->clone() );
2191
2192 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
2193 cloneTo( copy );
2194 return copy;
2195}
2196
2198{
2199 for ( WhenThen *wt : mConditions )
2200 {
2201 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
2202 return false;
2203 }
2204
2205 if ( mElseExp )
2206 return mElseExp->isStatic( parent, context );
2207
2208 return true;
2209}
2210
2212{
2213 auto simplifiedWhenThenList = std::make_unique< QgsExpressionNodeCondition::WhenThenList >();
2214 for ( QgsExpressionNodeCondition::WhenThen *clause : mConditions )
2215 {
2216 std::unique_ptr< QgsExpressionNode > simplifiedWhen( clause->whenExp()->simplifiedNode() );
2217 std::unique_ptr< QgsExpressionNode > simplifiedThen( clause->thenExp()->simplifiedNode() );
2218
2219 // if when condition is literal and TRUE we can just return the simplified THEN node
2220 if ( simplifiedWhenThenList->isEmpty() && simplifiedWhen->nodeType() == ntLiteral && simplifiedWhen->eval( nullptr, nullptr ).toBool() )
2221 {
2222 return simplifiedThen.release();
2223 }
2224 // if when simplifies to literal and FALSE, skip this condition as it can never be reached
2225 else if ( simplifiedWhen->nodeType() == ntLiteral && !simplifiedWhen->eval( nullptr, nullptr ).toBool() )
2226 {
2227 continue;
2228 }
2229
2230 simplifiedWhenThenList->append( new QgsExpressionNodeCondition::WhenThen( simplifiedWhen.release(), simplifiedThen.release() ) );
2231 }
2232
2233 std::unique_ptr< QgsExpressionNode > simplifiedElse( mElseExp ? mElseExp->simplifiedNode() : nullptr );
2234 if ( simplifiedWhenThenList->isEmpty() )
2235 {
2236 return simplifiedElse ? simplifiedElse.release() : new QgsExpressionNodeLiteral( QVariant() );
2237 }
2238
2239 return new QgsExpressionNodeCondition( simplifiedWhenThenList.release(), simplifiedElse.release() );
2240}
2241
2243{
2244 if ( hasCachedStaticValue() )
2245 return QSet< QString >();
2246
2247 QSet<QString> lst( mNode->referencedColumns() );
2248 const QList< QgsExpressionNode * > nodeList = mList->list();
2249 for ( const QgsExpressionNode *n : nodeList )
2250 lst.unite( n->referencedColumns() );
2251 return lst;
2252}
2253
2255{
2256 QSet<QString> lst( mNode->referencedVariables() );
2257 const QList< QgsExpressionNode * > nodeList = mList->list();
2258 for ( const QgsExpressionNode *n : nodeList )
2259 lst.unite( n->referencedVariables() );
2260 return lst;
2261}
2262
2264{
2265 QSet<QString> lst( mNode->referencedFunctions() );
2266 const QList< QgsExpressionNode * > nodeList = mList->list();
2267 for ( const QgsExpressionNode *n : nodeList )
2268 lst.unite( n->referencedFunctions() );
2269 return lst;
2270}
2271
2272QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
2273{
2274 QList<const QgsExpressionNode *> lst;
2275 lst << this;
2276 lst << mNode.get();
2277 const QList< QgsExpressionNode * > nodeList = mList->list();
2278 for ( const QgsExpressionNode *n : nodeList )
2279 lst += n->nodes();
2280 return lst;
2281}
2282
2283
2286
2291
2293{
2294 bool res = mNode->prepare( parent, context );
2295 res = res && mLowerBound->prepare( parent, context );
2296 res = res && mHigherBound->prepare( parent, context );
2297 return res;
2298}
2299
2301{
2302 const QVariant nodeVal = mNode->eval( parent, context );
2303 if ( QgsVariantUtils::isNull( nodeVal ) )
2304 {
2305 return QVariant();
2306 }
2307
2308 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
2309
2311 const QVariant lowBoundValue = lowBound.eval( parent, context );
2312 const bool lowBoundBool { lowBoundValue.toBool() };
2313
2314 if ( !QgsVariantUtils::isNull( lowBoundValue ) && !lowBoundBool )
2315 {
2316 return QVariant( mNegate );
2317 }
2318
2320 const QVariant highBoundValue = highBound.eval( parent, context );
2321
2322 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2323 {
2324 return QVariant();
2325 }
2326
2327 const bool highBoundBool { highBoundValue.toBool() };
2328
2329 // We already checked if both are nulls
2330 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2331 {
2332 // In this case we can return a boolean
2333 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && !highBoundBool ) || ( QgsVariantUtils::isNull( highBoundValue ) && !lowBoundBool ) )
2334 {
2335 return QVariant( mNegate );
2336 }
2337
2338 // Indetermined
2339 return QVariant();
2340 }
2341
2342 if ( !QgsVariantUtils::isNull( highBoundValue ) && !highBoundBool )
2343 {
2344 return QVariant( mNegate );
2345 }
2346
2347 const bool res { lowBoundBool && highBoundBool };
2348 return mNegate ? QVariant( !res ) : QVariant( res );
2349}
2350
2352{
2353 return u"%1 %2 %3 AND %4"_s.arg( mNode->dump(), mNegate ? u"NOT BETWEEN"_s : u"BETWEEN"_s, mLowerBound->dump(), mHigherBound->dump() );
2354}
2355
2357{
2358 QSet<QString> lst( mNode->referencedVariables() );
2359 lst.unite( mLowerBound->referencedVariables() );
2360 lst.unite( mHigherBound->referencedVariables() );
2361 return lst;
2362}
2363
2365{
2366 QSet<QString> lst( mNode->referencedFunctions() );
2367 lst.unite( mLowerBound->referencedFunctions() );
2368 lst.unite( mHigherBound->referencedFunctions() );
2369 return lst;
2370}
2371
2372QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2373{
2374 return { this, mLowerBound.get(), mHigherBound.get() };
2375}
2376
2378{
2379 QSet<QString> lst( mNode->referencedColumns() );
2380 lst.unite( mLowerBound->referencedColumns() );
2381 lst.unite( mHigherBound->referencedColumns() );
2382 return lst;
2383}
2384
2386{
2387 if ( mNode->needsGeometry() )
2388 return true;
2389
2390 if ( mLowerBound->needsGeometry() )
2391 return true;
2392
2393 if ( mHigherBound->needsGeometry() )
2394 return true;
2395
2396 return false;
2397}
2398
2400{
2401 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2402 cloneTo( copy );
2403 return copy;
2404}
2405
2407{
2408 if ( !mNode->isStatic( parent, context ) )
2409 return false;
2410
2411 if ( !mLowerBound->isStatic( parent, context ) )
2412 return false;
2413
2414 if ( !mHigherBound->isStatic( parent, context ) )
2415 return false;
2416
2417 return true;
2418}
2419
2421{
2422 return mLowerBound.get();
2423}
2424
2426{
2427 return mHigherBound.get();
2428}
2429
2431{
2432 return mNegate;
2433}
2434
2439
2442
2444{
2445 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2446}
2447
2449{
2450 return BINARY_OPERATOR_TEXT[mOp];
2451}
2452
2453//
2454
2456{
2457 const QVariant container = mContainer->eval( parent, context );
2459 const QVariant index = mIndex->eval( parent, context );
2461
2462 switch ( container.userType() )
2463 {
2464 case QMetaType::Type::QVariantMap:
2465 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2466
2467 case QMetaType::Type::QVariantList:
2468 case QMetaType::Type::QStringList:
2469 {
2470 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2471 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2472 if ( pos >= list.length() || pos < -list.length() )
2473 {
2474 return QVariant();
2475 }
2476 if ( pos < 0 )
2477 {
2478 // negative indices are from back of list
2479 pos += list.length();
2480 }
2481
2482 return list.at( pos );
2483 }
2484
2485 default:
2487 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2488 return QVariant();
2489 }
2490}
2491
2496
2498{
2499 bool resC = mContainer->prepare( parent, context );
2500 bool resV = mIndex->prepare( parent, context );
2501 return resC && resV;
2502}
2503
2505{
2506 return u"%1[%2]"_s.arg( mContainer->dump(), mIndex->dump() );
2507}
2508
2510{
2511 if ( hasCachedStaticValue() )
2512 return QSet< QString >();
2513
2514 return mContainer->referencedColumns() + mIndex->referencedColumns();
2515}
2516
2518{
2519 return mContainer->referencedVariables() + mIndex->referencedVariables();
2520}
2521
2523{
2524 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2525}
2526
2527QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2528{
2529 QList<const QgsExpressionNode *> lst;
2530 lst << this;
2531 lst += mContainer->nodes() + mIndex->nodes();
2532 return lst;
2533}
2534
2536{
2537 return mContainer->needsGeometry() || mIndex->needsGeometry();
2538}
2539
2541{
2542 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2543 cloneTo( copy );
2544 return copy;
2545}
2546
2548{
2549 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2550}
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
bool hasFeature() const
Returns true if the context has a feature associated with it.
Represents a single parameter passed to a function.
QVariant defaultValue() const
Returns the default value for the parameter.
QString name() const
Returns the name of the parameter.
An abstract base class for defining QgsExpression functions.
QList< QgsExpressionFunction::Parameter > ParameterList
List of parameters, used for function definition.
int params() const
The number of parameters this function takes.
bool lazyEval() const
true if this function should use lazy evaluation.
QString name() const
The name of the function.
virtual QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)
Evaluates the function, first evaluating all required arguments before passing them to the function's...
const QgsExpressionFunction::ParameterList & parameters() const
Returns the list of named parameters for the function, if set.
virtual QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const
Returns a set of field names which are required for this function.
virtual bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
This will be called during the prepare step() of an expression if it is not static.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
bool negate() const
Returns true if the predicate is an exclusion test (NOT BETWEEN).
QgsExpressionNode * lowerBound() const
Returns the lower bound expression node of the range.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * higherBound() const
Returns the higher bound expression node of the range.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeBetweenOperator(QgsExpressionNode *node, QgsExpressionNode *nodeLowerBound, QgsExpressionNode *nodeHigherBound, bool negate=false)
This node tests if the result of node is between the result of nodeLowerBound and nodeHigherBound nod...
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
A binary expression operator, which operates on two values.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
bool leftAssociative() const
Returns true if the operator is left-associative.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
int precedence() const
Returns the precedence index for the operator.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
QgsExpressionNodeBinaryOperator(QgsExpressionNodeBinaryOperator::BinaryOperator op, QgsExpressionNode *opLeft, QgsExpressionNode *opRight)
Binary combination of the left and the right with op.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
An expression node which takes its value from a feature's field.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNodeColumnRef(const QString &name)
Constructor for QgsExpressionNodeColumnRef, referencing the column with the specified name.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
Represents a "WHEN... THEN..." portation of a CASE WHEN clause in an expression.
WhenThen(QgsExpressionNode *whenExp, QgsExpressionNode *thenExp)
A combination of when and then.
QgsExpressionNode * thenExp() const
The expression node that makes the THEN result part of the condition.
QgsExpressionNode * whenExp() const
The expression that makes the WHEN part of the condition.
QgsExpressionNodeCondition::WhenThen * clone() const
Gets a deep copy of this WhenThen combination.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QList< QgsExpressionNodeCondition::WhenThen * > WhenThenList
QgsExpressionNodeCondition(QgsExpressionNodeCondition::WhenThenList *conditions, QgsExpressionNode *elseExp=nullptr)
Create a new node with the given list of conditions and an optional elseExp expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
WhenThenList conditions() const
The list of WHEN THEN expression parts of the expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
int fnIndex() const
Returns the index of the node's function.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNodeFunction(int fnIndex, QgsExpressionNode::NodeList *args)
A function node consists of an index of the function in the global function array and a list of argum...
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
static bool validateParams(int fnIndex, QgsExpressionNode::NodeList *args, QString &error)
Tests whether the provided argument list is valid for the matching function.
An expression node for value IN or NOT IN clauses.
QgsExpressionNode * node() const
Returns the expression node.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
QgsExpressionNodeInOperator(QgsExpressionNode *node, QgsExpressionNode::NodeList *list, bool notin=false)
This node tests if the result of node is in the result of list.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsExpressionNodeIndexOperator(QgsExpressionNode *container, QgsExpressionNode *index)
Constructor for QgsExpressionNodeIndexOperator.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QgsExpressionNode * index() const
Returns the index node, representing an array element index or map key.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QgsExpressionNode * container() const
Returns the container node, representing an array or map value.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
An expression node for literal values.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QString valueAsString() const
Returns a string representation of the node's literal value.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode * clone() const override
Generate a clone of this node.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QVariant value() const
The value of the literal.
QgsExpressionNodeLiteral(const QVariant &value)
Constructor for QgsExpressionNodeLiteral, with the specified literal value.
A unary node is either negative as in boolean (not) or as in numbers (minus).
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QSet< QString > referencedFunctions() const override
Returns a set of all functions which are used in this expression.
QgsExpressionNodeUnaryOperator::UnaryOperator op() const
Returns the unary operator.
QSet< QString > referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node.
QList< const QgsExpressionNode * > nodes() const override
Returns a list of all nodes which are used in this expression.
QgsExpressionNodeUnaryOperator(QgsExpressionNodeUnaryOperator::UnaryOperator op, QgsExpressionNode *operand)
A node unary operator is modifying the value of operand by negating it with op.
QString text() const
Returns a the name of this operator without the operands.
bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const override
Returns true if this node can be evaluated for a static value.
QVariant evalNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsExpressionNode * simplifiedNode() const override
Returns a new node, which is the simplest node which represents this node before any compilation opti...
bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString dump() const override
Dump this node into a serialized (part) of an expression.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
A list of expression nodes.
virtual QString dump() const
Returns a string dump of the expression node.
QgsExpressionNode::NodeList * clone() const
Creates a deep copy of this list. Ownership is transferred to the caller.
void append(QgsExpressionNode *node)
Takes ownership of the provided node.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
QVariant eval(QgsExpression *parent, const QgsExpressionContext *context)
Evaluate this node with the given context and parent.
virtual QgsExpressionNode * clone() const =0
Generate a clone of this node.
bool mHasCachedValue
true if the node has a static, precalculated value.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
QgsExpressionNode()=default
std::unique_ptr< QgsExpressionNode > mCompiledSimplifiedNode
Contains a compiled node which represents a simplified version of this node as a result of compilatio...
NodeType
Known node types.
@ ntBetweenOperator
Between operator.
@ ntIndexOperator
Index operator.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
Handles parsing and evaluation of expressions (formerly called "search strings").
static const QList< QgsExpressionFunction * > & Functions()
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes).
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions).
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:60
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
bool isValid() const
Returns the validity of this feature.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Container of fields for a vector layer.
Definition qgsfields.h:45
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A representation of the interval between two datetime values.
Definition qgsinterval.h:52
double seconds() const
Returns the interval duration in seconds.
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:7395
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7488
bool compareOp(T diff, QgsExpressionNodeBinaryOperator::BinaryOperator op)
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.