QGIS API Documentation 3.41.0-Master (3440c17df1d)
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
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#include "qgsexpressionutils.h"
18#include "qgsexpression.h"
19
20#include "qgsstringutils.h"
21#include "qgsvariantutils.h"
22
23#include <QDate>
24#include <QDateTime>
25#include <QTime>
26#include <QRegularExpression>
27
28const char *QgsExpressionNodeBinaryOperator::BINARY_OPERATOR_TEXT[] =
29{
30 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
31 "OR", "AND",
32 "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
33 "+", "-", "*", "/", "//", "%", "^",
34 "||"
35};
36
37const char *QgsExpressionNodeUnaryOperator::UNARY_OPERATOR_TEXT[] =
38{
39 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
40 "NOT", "-"
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 ) msg += QLatin1String( ", " );
84 else first = false;
85 msg += n->dump();
86 }
87 return msg;
88}
89
90QString QgsExpressionNode::NodeList::cleanNamedNodeName( const QString &name )
91{
92 QString cleaned = name.toLower();
93
94 // upgrade older argument names to standard versions
95 if ( cleaned == QLatin1String( "geom" ) )
96 cleaned = QStringLiteral( "geometry" );
97 else if ( cleaned == QLatin1String( "val" ) )
98 cleaned = QStringLiteral( "value" );
99 else if ( cleaned == QLatin1String( "geometry a" ) )
100 cleaned = QStringLiteral( "geometry1" );
101 else if ( cleaned == QLatin1String( "geometry b" ) )
102 cleaned = QStringLiteral( "geometry2" );
103 else if ( cleaned == QLatin1String( "i" ) )
104 cleaned = QStringLiteral( "vertex" );
105
106 return cleaned;
107}
108
109
110//
111
113{
114 QVariant val = mOperand->eval( parent, context );
116
117 switch ( mOp )
118 {
119 case uoNot:
120 {
121 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( val, parent );
123 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::NOT[tvl] );
124 }
125
126 case uoMinus:
127 if ( QgsExpressionUtils::isIntSafe( val ) )
128 return QVariant( - QgsExpressionUtils::getIntValue( val, parent ) );
129 else if ( QgsExpressionUtils::isDoubleSafe( val ) )
130 return QVariant( - QgsExpressionUtils::getDoubleValue( val, parent ) );
131 else
132 SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) )
133 }
134 return QVariant();
135}
136
141
143{
144 return mOperand->prepare( parent, context );
145}
146
148{
149 if ( dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOperand ) )
150 return QStringLiteral( "%1 ( %2 )" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
151 else
152 return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
153}
154
156{
157 if ( hasCachedStaticValue() )
158 return QSet< QString >();
159
160 return mOperand->referencedColumns();
161}
162
164{
165 return mOperand->referencedVariables();
166}
167
169{
170 return mOperand->referencedFunctions();
171}
172
173QList<const QgsExpressionNode *> QgsExpressionNodeUnaryOperator::nodes() const
174{
175 QList<const QgsExpressionNode *> lst;
176 lst.append( this );
177 lst += mOperand->nodes();
178 return lst;
179}
180
182{
183 return mOperand->needsGeometry();
184}
185
187{
188 QgsExpressionNodeUnaryOperator *copy = new QgsExpressionNodeUnaryOperator( mOp, mOperand->clone() );
189 cloneTo( copy );
190 return copy;
191}
192
194{
195 return mOperand->isStatic( parent, context );
196}
197
199{
200 return UNARY_OPERATOR_TEXT[mOp];
201}
202
203//
204
206{
207 QVariant vL = mOpLeft->eval( parent, context );
209
210 if ( mOp == boAnd || mOp == boOr )
211 {
212 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent );
214 if ( mOp == boAnd && tvlL == QgsExpressionUtils::False )
215 return TVL_False; // shortcut -- no need to evaluate right-hand side
216 if ( mOp == boOr && tvlL == QgsExpressionUtils::True )
217 return TVL_True; // shortcut -- no need to evaluate right-hand side
218 }
219
220 QVariant vR = mOpRight->eval( parent, context );
222
223 switch ( mOp )
224 {
225 case boPlus:
226 if ( vL.userType() == QMetaType::Type::QString && vR.userType() == QMetaType::Type::QString )
227 {
228 QString sL = QgsExpressionUtils::isNull( vL ) ? QString() : QgsExpressionUtils::getStringValue( vL, parent );
230 QString sR = QgsExpressionUtils::isNull( vR ) ? QString() : QgsExpressionUtils::getStringValue( vR, parent );
232 return QVariant( sL + sR );
233 }
234 //intentional fall-through
235 [[fallthrough]];
236 case boMinus:
237 case boMul:
238 case boDiv:
239 case boMod:
240 {
241 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
242 return QVariant();
243 else if ( mOp != boDiv && QgsExpressionUtils::isIntSafe( vL ) && QgsExpressionUtils::isIntSafe( vR ) )
244 {
245 // both are integers - let's use integer arithmetic
246 qlonglong iL = QgsExpressionUtils::getIntValue( vL, parent );
248 qlonglong iR = QgsExpressionUtils::getIntValue( vR, parent );
250
251 if ( mOp == boMod && iR == 0 )
252 return QVariant();
253
254 return QVariant( computeInt( iL, iR ) );
255 }
256 else if ( QgsExpressionUtils::isDateTimeSafe( vL ) && QgsExpressionUtils::isIntervalSafe( vR ) )
257 {
258 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
260 QgsInterval iL = QgsExpressionUtils::getInterval( vR, parent );
262 if ( mOp == boDiv || mOp == boMul || mOp == boMod )
263 {
264 parent->setEvalErrorString( tr( "Can't perform /, *, or % on DateTime and Interval" ) );
265 return QVariant();
266 }
267 return QVariant( computeDateTimeFromInterval( dL, &iL ) );
268 }
269 else if ( mOp == boPlus && ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QTime ) ||
270 ( vR.userType() == QMetaType::Type::QDate && vL.userType() == QMetaType::Type::QTime ) ) )
271 {
272 QDate date = QgsExpressionUtils::getDateValue( vL.userType() == QMetaType::Type::QDate ? vL : vR, parent );
274 QTime time = QgsExpressionUtils::getTimeValue( vR.userType() == QMetaType::Type::QTime ? vR : vL, parent );
276 QDateTime dt = QDateTime( date, time );
277 return QVariant( dt );
278 }
279 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate )
280 {
281 QDate date1 = QgsExpressionUtils::getDateValue( vL, parent );
283 QDate date2 = QgsExpressionUtils::getDateValue( vR, parent );
285 return date1 - date2;
286 }
287 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime )
288 {
289 QTime time1 = QgsExpressionUtils::getTimeValue( vL, parent );
291 QTime time2 = QgsExpressionUtils::getTimeValue( vR, parent );
293 return time1 - time2;
294 }
295 else if ( mOp == boMinus && vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime )
296 {
297 QDateTime datetime1 = QgsExpressionUtils::getDateTimeValue( vL, parent );
299 QDateTime datetime2 = QgsExpressionUtils::getDateTimeValue( vR, parent );
301 return QgsInterval( datetime1 - datetime2 );
302 }
303 else
304 {
305 // general floating point arithmetic
306 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
308 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
310 if ( ( mOp == boDiv || mOp == boMod ) && fR == 0. )
311 return QVariant(); // silently handle division by zero and return NULL
312 return QVariant( computeDouble( fL, fR ) );
313 }
314 }
315 case boIntDiv:
316 {
317 //integer division
318 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
320 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
322 if ( fR == 0. )
323 return QVariant(); // silently handle division by zero and return NULL
324 return QVariant( qlonglong( std::floor( fL / fR ) ) );
325 }
326 case boPow:
327 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
328 return QVariant();
329 else
330 {
331 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
333 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
335 return QVariant( std::pow( fL, fR ) );
336 }
337
338 case boAnd:
339 {
340 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
342 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::AND[tvlL][tvlR] );
343 }
344
345 case boOr:
346 {
347 QgsExpressionUtils::TVL tvlL = QgsExpressionUtils::getTVLValue( vL, parent ), tvlR = QgsExpressionUtils::getTVLValue( vR, parent );
349 return QgsExpressionUtils::tvl2variant( QgsExpressionUtils::OR[tvlL][tvlR] );
350 }
351
352 case boEQ:
353 case boNE:
354 case boLT:
355 case boGT:
356 case boLE:
357 case boGE:
358 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
359 {
360 return TVL_Unknown;
361 }
362 else if ( QgsExpressionUtils::isList( vL ) || QgsExpressionUtils::isList( vR ) )
363 {
364 // verify that we have two lists
365 if ( !QgsExpressionUtils::isList( vL ) || !QgsExpressionUtils::isList( vR ) )
366 return TVL_Unknown;
367
368 // and search for not equal respective items
369 QVariantList lL = vL.toList();
370 QVariantList lR = vR.toList();
371 for ( int i = 0; i < lL.length() && i < lR.length(); i++ )
372 {
373 if ( QgsExpressionUtils::isNull( lL.at( i ) ) && QgsExpressionUtils::isNull( lR.at( i ) ) )
374 continue; // same behavior as PostgreSQL
375
376 if ( QgsExpressionUtils::isNull( lL.at( i ) ) || QgsExpressionUtils::isNull( lR.at( i ) ) )
377 {
378 switch ( mOp )
379 {
380 case boEQ:
381 return false;
382 case boNE:
383 return true;
384 case boLT:
385 case boLE:
386 return QgsExpressionUtils::isNull( lR.at( i ) );
387 case boGT:
388 case boGE:
389 return QgsExpressionUtils::isNull( lL.at( i ) );
390 default:
391 Q_ASSERT( false );
392 return TVL_Unknown;
393 }
394 }
395
396 QgsExpressionNodeLiteral nL( lL.at( i ) );
397 QgsExpressionNodeLiteral nR( lR.at( i ) );
398 QgsExpressionNodeBinaryOperator eqNode( boEQ, nL.clone(), nR.clone() );
399 QVariant eq = eqNode.eval( parent, context );
401 if ( eq == TVL_False )
402 {
403 // return the two items comparison
404 QgsExpressionNodeBinaryOperator node( mOp, nL.clone(), nR.clone() );
405 QVariant v = node.eval( parent, context );
407 return v;
408 }
409 }
410
411 // default to length comparison
412 switch ( mOp )
413 {
414 case boEQ:
415 return lL.length() == lR.length();
416 case boNE:
417 return lL.length() != lR.length();
418 case boLT:
419 return lL.length() < lR.length();
420 case boGT:
421 return lL.length() > lR.length();
422 case boLE:
423 return lL.length() <= lR.length();
424 case boGE:
425 return lL.length() >= lR.length();
426 default:
427 Q_ASSERT( false );
428 return TVL_Unknown;
429 }
430 }
431 else if ( ( vL.userType() == QMetaType::Type::QDateTime && vR.userType() == QMetaType::Type::QDateTime ) )
432 {
433 QDateTime dL = QgsExpressionUtils::getDateTimeValue( vL, parent );
435 QDateTime dR = QgsExpressionUtils::getDateTimeValue( vR, parent );
437
438 // while QDateTime has innate handling of timezones, we don't expose these ANYWHERE
439 // in QGIS. So to avoid confusion where seemingly equal datetime values give unexpected
440 // results (due to different hidden timezones), we force all datetime comparisons to treat
441 // all datetime values as having the same time zone
442 dL.setTimeSpec( Qt::UTC );
443 dR.setTimeSpec( Qt::UTC );
444
445 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
446 }
447 else if ( ( vL.userType() == QMetaType::Type::QDate && vR.userType() == QMetaType::Type::QDate ) )
448 {
449 const QDate dL = QgsExpressionUtils::getDateValue( vL, parent );
451 const QDate dR = QgsExpressionUtils::getDateValue( vR, parent );
453 return compare( dR.daysTo( dL ) ) ? TVL_True : TVL_False;
454 }
455 else if ( ( vL.userType() == QMetaType::Type::QTime && vR.userType() == QMetaType::Type::QTime ) )
456 {
457 const QTime dL = QgsExpressionUtils::getTimeValue( vL, parent );
459 const QTime dR = QgsExpressionUtils::getTimeValue( vR, parent );
461 return compare( dR.msecsTo( dL ) ) ? TVL_True : TVL_False;
462 }
463 else if ( ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) &&
464 QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) )
465 {
466 // do numeric comparison if both operators can be converted to numbers,
467 // and they aren't both string
468 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
470 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
472 return compare( fL - fR ) ? TVL_True : TVL_False;
473 }
474
475 else if ( vL.userType() == QMetaType::Type::Bool || vR.userType() == QMetaType::Type::Bool )
476 {
477 // if one of value is boolean, then the other must also be boolean,
478 // in order to avoid confusion between different expression evaluations
479 // amongst providers and QVariant, that can consider or not the string
480 // 'false' as boolean or text
481 if ( vL.userType() == QMetaType::Type::Bool && vR.userType() == QMetaType::Type::Bool )
482 return vL.toBool() == vR.toBool() ? TVL_True : TVL_False;
483 return TVL_False;
484 }
485
486 // warning - QgsExpression::isIntervalSafe is VERY expensive and should not be used here
487 else if ( vL.userType() == qMetaTypeId< QgsInterval>() && vR.userType() == qMetaTypeId< QgsInterval>() )
488 {
489 double fL = QgsExpressionUtils::getInterval( vL, parent ).seconds();
491 double fR = QgsExpressionUtils::getInterval( vR, parent ).seconds();
493 return compare( fL - fR ) ? TVL_True : TVL_False;
494 }
495 else
496 {
497 // do string comparison otherwise
498 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
500 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
502 int diff = QString::compare( sL, sR );
503 return compare( diff ) ? TVL_True : TVL_False;
504 }
505
506 case boIs:
507 case boIsNot:
508 if ( QgsExpressionUtils::isNull( vL ) && QgsExpressionUtils::isNull( vR ) ) // both operators null
509 return ( mOp == boIs ? TVL_True : TVL_False );
510 else if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) ) // one operator null
511 return ( mOp == boIs ? TVL_False : TVL_True );
512 else // both operators non-null
513 {
514 bool equal = false;
515 if ( QgsExpressionUtils::isDoubleSafe( vL ) && QgsExpressionUtils::isDoubleSafe( vR ) &&
516 ( vL.userType() != QMetaType::Type::QString || vR.userType() != QMetaType::Type::QString ) )
517 {
518 double fL = QgsExpressionUtils::getDoubleValue( vL, parent );
520 double fR = QgsExpressionUtils::getDoubleValue( vR, parent );
522 equal = qgsDoubleNear( fL, fR );
523 }
524 else
525 {
526 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
528 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
530 equal = QString::compare( sL, sR ) == 0;
531 }
532 if ( equal )
533 return mOp == boIs ? TVL_True : TVL_False;
534 else
535 return mOp == boIs ? TVL_False : TVL_True;
536 }
537
538 case boRegexp:
539 case boLike:
540 case boNotLike:
541 case boILike:
542 case boNotILike:
543 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
544 return TVL_Unknown;
545 else
546 {
547 QString str = QgsExpressionUtils::getStringValue( vL, parent );
549 QString regexp = QgsExpressionUtils::getStringValue( vR, parent );
551 // TODO: cache QRegularExpression in case that regexp is a literal string (i.e. it will stay constant)
552 bool matches;
553 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
554 {
555 QString esc_regexp = QgsStringUtils::qRegExpEscape( regexp );
556 // manage escape % and _
557 if ( esc_regexp.startsWith( '%' ) )
558 {
559 esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
560 }
561 const thread_local QRegularExpression rx1( QStringLiteral( "[^\\\\](%)" ) );
562 int pos = 0;
563 while ( ( pos = esc_regexp.indexOf( rx1, pos ) ) != -1 )
564 {
565 esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
566 pos += 1;
567 }
568 const thread_local QRegularExpression rx2( QStringLiteral( "\\\\%" ) );
569 esc_regexp.replace( rx2, QStringLiteral( "%" ) );
570 if ( esc_regexp.startsWith( '_' ) )
571 {
572 esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
573 }
574 const thread_local QRegularExpression rx3( QStringLiteral( "[^\\\\](_)" ) );
575 pos = 0;
576 while ( ( pos = esc_regexp.indexOf( rx3, pos ) ) != -1 )
577 {
578 esc_regexp.replace( pos + 1, 1, '.' );
579 pos += 1;
580 }
581 esc_regexp.replace( QLatin1String( "\\\\_" ), QLatin1String( "_" ) );
582
583 matches = QRegularExpression( QRegularExpression::anchoredPattern( esc_regexp ), mOp == boLike || mOp == boNotLike ? QRegularExpression::DotMatchesEverythingOption : QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption ).match( str ).hasMatch();
584 }
585 else
586 {
587 matches = QRegularExpression( regexp ).match( str ).hasMatch();
588 }
589
590 if ( mOp == boNotLike || mOp == boNotILike )
591 {
592 matches = !matches;
593 }
594
595 return matches ? TVL_True : TVL_False;
596 }
597
598 case boConcat:
599 if ( QgsExpressionUtils::isNull( vL ) || QgsExpressionUtils::isNull( vR ) )
600 return QVariant();
601 else
602 {
603 QString sL = QgsExpressionUtils::getStringValue( vL, parent );
605 QString sR = QgsExpressionUtils::getStringValue( vR, parent );
607 return QVariant( sL + sR );
608 }
609 }
610 Q_ASSERT( false );
611 return QVariant();
612}
613
614bool QgsExpressionNodeBinaryOperator::compare( double diff )
615{
616 switch ( mOp )
617 {
618 case boEQ:
619 return qgsDoubleNear( diff, 0.0 );
620 case boNE:
621 return !qgsDoubleNear( diff, 0.0 );
622 case boLT:
623 return diff < 0;
624 case boGT:
625 return diff > 0;
626 case boLE:
627 return diff <= 0;
628 case boGE:
629 return diff >= 0;
630 default:
631 Q_ASSERT( false );
632 return false;
633 }
634}
635
636qlonglong QgsExpressionNodeBinaryOperator::computeInt( qlonglong x, qlonglong y )
637{
638 switch ( mOp )
639 {
640 case boPlus:
641 return x + y;
642 case boMinus:
643 return x - y;
644 case boMul:
645 return x * y;
646 case boDiv:
647 return x / y;
648 case boMod:
649 return x % y;
650 default:
651 Q_ASSERT( false );
652 return 0;
653 }
654}
655
656QDateTime QgsExpressionNodeBinaryOperator::computeDateTimeFromInterval( const QDateTime &d, QgsInterval *i )
657{
658 switch ( mOp )
659 {
660 case boPlus:
661 return d.addSecs( i->seconds() );
662 case boMinus:
663 return d.addSecs( -i->seconds() );
664 default:
665 Q_ASSERT( false );
666 return QDateTime();
667 }
668}
669
670double QgsExpressionNodeBinaryOperator::computeDouble( double x, double y )
671{
672 switch ( mOp )
673 {
674 case boPlus:
675 return x + y;
676 case boMinus:
677 return x - y;
678 case boMul:
679 return x * y;
680 case boDiv:
681 return x / y;
682 case boMod:
683 return std::fmod( x, y );
684 default:
685 Q_ASSERT( false );
686 return 0;
687 }
688}
689
694
696{
697
698 // if this is an OR, try to collapse the OR expression into an IN node
699 if ( mOp == boOr )
700 {
701
702 // First step: flatten OR chain and collect values
703 QMap<QString, QgsExpressionNode::NodeList> orValuesMap;
704 QList<QString> orFieldNames;
705
706 // Get a list of all the OR and IN nodes chained together
707 std::function<bool ( QgsExpressionNode * )> visitOrNodes = [&visitOrNodes, &orValuesMap, &orFieldNames]( QgsExpressionNode * node ) -> bool
708 {
709 if ( QgsExpressionNodeBinaryOperator *op = dynamic_cast<QgsExpressionNodeBinaryOperator *>( node ) )
710 {
711 if ( op->op() != boOr && op->op() != boEQ )
712 {
713 return false;
714 }
715
716 if ( op->op() == boEQ )
717 {
718 // If left is a column ref and right is a literal, collect
719 if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opLeft() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opRight() ) ) )
720 {
721 const QString fieldName = op->opLeft()->dump();
722 if ( !orValuesMap.contains( fieldName ) )
723 {
724 orFieldNames.append( fieldName );
725 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
726 }
727 orValuesMap[fieldName].append( op->opRight()->clone() );
728 return true;
729 }
730 else if ( ( dynamic_cast<QgsExpressionNodeColumnRef *>( op->opRight() ) && dynamic_cast<QgsExpressionNodeLiteral *>( op->opLeft() ) ) )
731 {
732 const QString fieldName = op->opRight()->dump();
733 if ( !orValuesMap.contains( fieldName ) )
734 {
735 orFieldNames.append( fieldName );
736 orValuesMap.insert( fieldName, QgsExpressionNode::NodeList() );
737 }
738 orValuesMap[fieldName].append( op->opLeft()->clone() );
739 return true;
740 }
741 return false;
742 }
743
744 if ( visitOrNodes( op->opLeft() ) && visitOrNodes( op->opRight() ) )
745 {
746 return true;
747 }
748
749 }
750 else if ( QgsExpressionNodeInOperator *inOp = dynamic_cast<QgsExpressionNodeInOperator *>( node ) )
751 {
752 if ( inOp->node()->nodeType() != QgsExpressionNode::ntColumnRef )
753 {
754 return false;
755 }
756
757 const QString fieldName = inOp->node()->dump();
758
759 // Check if all nodes are literals
760 const auto nodes = inOp->list()->list();
761 for ( const auto &valueNode : std::as_const( nodes ) )
762 {
763 if ( valueNode->nodeType() != QgsExpressionNode::ntLiteral )
764 {
765 return false;
766 }
767 }
768
769 if ( !orValuesMap.contains( fieldName ) )
770 {
771 orFieldNames.append( fieldName );
772 orValuesMap.insert( fieldName, *inOp->list()->clone() );
773 }
774 else
775 {
776 for ( const auto &valueNode : std::as_const( nodes ) )
777 {
778 orValuesMap[fieldName].append( valueNode->clone() );
779 }
780 }
781
782 return true;
783 }
784 return false;
785 };
786
787
788 // Second step: build the OR chain of IN operators
789 if ( visitOrNodes( this ) && ! orValuesMap.empty() )
790 {
791
792 std::unique_ptr<QgsExpressionNode> currentNode;
793 for ( const auto &fieldName : std::as_const( orFieldNames ) )
794 {
795 auto orValuesIt = orValuesMap.find( fieldName );
796 if ( orValuesIt.value().count() == 1 )
797 {
798 std::unique_ptr<QgsExpressionNodeBinaryOperator> eqNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boEQ, new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().at( 0 )->clone() );
799 if ( currentNode )
800 {
801 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), eqNode.release() );
802 }
803 else
804 {
805 currentNode = std::move( eqNode );
806 }
807 }
808 else
809 {
810 std::unique_ptr<QgsExpressionNodeInOperator> inNode = std::make_unique<QgsExpressionNodeInOperator>( new QgsExpressionNodeColumnRef( fieldName ), orValuesIt.value().clone() );
811 if ( currentNode )
812 {
813 currentNode = std::make_unique<QgsExpressionNodeBinaryOperator>( boOr, currentNode.release(), inNode.release() );
814 }
815 else
816 {
817 currentNode = std::move( inNode );
818 }
819 }
820 }
821
822
823 if ( currentNode )
824 {
825 mCompiledSimplifiedNode = std::move( currentNode );
826 }
827 }
828
829 }
830
831 bool resL = mOpLeft->prepare( parent, context );
832 bool resR = mOpRight->prepare( parent, context );
833 return resL && resR;
834}
835
837{
838 // see left/right in qgsexpressionparser.yy
839 switch ( mOp )
840 {
841 case boOr:
842 return 1;
843
844 case boAnd:
845 return 2;
846
847 case boEQ:
848 case boNE:
849 case boLE:
850 case boGE:
851 case boLT:
852 case boGT:
853 case boRegexp:
854 case boLike:
855 case boILike:
856 case boNotLike:
857 case boNotILike:
858 case boIs:
859 case boIsNot:
860 return 3;
861
862 case boPlus:
863 case boMinus:
864 return 4;
865
866 case boMul:
867 case boDiv:
868 case boIntDiv:
869 case boMod:
870 return 5;
871
872 case boPow:
873 return 6;
874
875 case boConcat:
876 return 7;
877 }
878 Q_ASSERT( false && "unexpected binary operator" );
879 return -1;
880}
881
883{
884 // see left/right in qgsexpressionparser.yy
885 switch ( mOp )
886 {
887 case boOr:
888 case boAnd:
889 case boEQ:
890 case boNE:
891 case boLE:
892 case boGE:
893 case boLT:
894 case boGT:
895 case boRegexp:
896 case boLike:
897 case boILike:
898 case boNotLike:
899 case boNotILike:
900 case boIs:
901 case boIsNot:
902 case boPlus:
903 case boMinus:
904 case boMul:
905 case boDiv:
906 case boIntDiv:
907 case boMod:
908 case boConcat:
909 return true;
910
911 case boPow:
912 return false;
913 }
914 Q_ASSERT( false && "unexpected binary operator" );
915 return false;
916}
917
919{
921 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight );
922 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight );
923
924 QString rdump( mOpRight->dump() );
925
926 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
927 if ( mOp == boIs && ruOp && ruOp->op() == QgsExpressionNodeUnaryOperator::uoNot )
928 {
929 rdump.prepend( '(' ).append( ')' );
930 }
931
932 QString fmt;
933 if ( leftAssociative() )
934 {
935 fmt += lOp && ( lOp->precedence() < precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
936 fmt += QLatin1String( " %2 " );
937 fmt += rOp && ( rOp->precedence() <= precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
938 }
939 else
940 {
941 fmt += lOp && ( lOp->precedence() <= precedence() ) ? QStringLiteral( "(%1)" ) : QStringLiteral( "%1" );
942 fmt += QLatin1String( " %2 " );
943 fmt += rOp && ( rOp->precedence() < precedence() ) ? QStringLiteral( "(%3)" ) : QStringLiteral( "%3" );
944 }
945
946 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
947}
948
950{
951 if ( hasCachedStaticValue() )
952 return QSet< QString >();
953
954 return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
955}
956
958{
959 return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
960}
961
963{
964 return mOpLeft->referencedFunctions() + mOpRight->referencedFunctions();
965}
966
967QList<const QgsExpressionNode *> QgsExpressionNodeBinaryOperator::nodes() const
968{
969 QList<const QgsExpressionNode *> lst;
970 lst << this;
971 lst += mOpLeft->nodes() + mOpRight->nodes();
972 return lst;
973}
974
976{
977 return mOpLeft->needsGeometry() || mOpRight->needsGeometry();
978}
979
981{
982 QgsExpressionNodeBinaryOperator *copy = new QgsExpressionNodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
983 cloneTo( copy );
984 return copy;
985}
986
988{
989 const bool leftStatic = mOpLeft->isStatic( parent, context );
990 const bool rightStatic = mOpRight->isStatic( parent, context );
991
992 if ( leftStatic && rightStatic )
993 return true;
994
995 // special logic for certain ops...
996 switch ( mOp )
997 {
999 {
1000 // if either node is static AND evaluates to TRUE, then the result will ALWAYS be true regardless
1001 // of the value of the other node!
1002 if ( leftStatic )
1003 {
1004 mOpLeft->prepare( parent, context );
1005 if ( mOpLeft->hasCachedStaticValue() )
1006 {
1007 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1008 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1009 {
1010 mCachedStaticValue = true;
1011 mHasCachedValue = true;
1012 return true;
1013 }
1014 }
1015 }
1016 else if ( rightStatic )
1017 {
1018 mOpRight->prepare( parent, context );
1019 if ( mOpRight->hasCachedStaticValue() )
1020 {
1021 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1022 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::True )
1023 {
1024 mCachedStaticValue = true;
1025 mHasCachedValue = true;
1026 return true;
1027 }
1028 }
1029 }
1030
1031 break;
1032 }
1034 {
1035 // if either node is static AND evaluates to FALSE, then the result will ALWAYS be false regardless
1036 // of the value of the other node!
1037
1038 if ( leftStatic )
1039 {
1040 mOpLeft->prepare( parent, context );
1041 if ( mOpLeft->hasCachedStaticValue() )
1042 {
1043 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpLeft->cachedStaticValue(), parent );
1044 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1045 {
1046 mCachedStaticValue = false;
1047 mHasCachedValue = true;
1048 return true;
1049 }
1050 }
1051 }
1052 else if ( rightStatic )
1053 {
1054 mOpRight->prepare( parent, context );
1055 if ( mOpRight->hasCachedStaticValue() )
1056 {
1057 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( mOpRight->cachedStaticValue(), parent );
1058 if ( !parent->hasEvalError() && tvl == QgsExpressionUtils::False )
1059 {
1060 mCachedStaticValue = false;
1061 mHasCachedValue = true;
1062 return true;
1063 }
1064 }
1065 }
1066
1067 break;
1068 }
1069
1091 break;
1092 }
1093
1094 return false;
1095}
1096
1097//
1098
1100{
1101 if ( mList->count() == 0 )
1102 return mNotIn ? TVL_True : TVL_False;
1103 QVariant v1 = mNode->eval( parent, context );
1105 if ( QgsExpressionUtils::isNull( v1 ) )
1106 return TVL_Unknown;
1107
1108 bool listHasNull = false;
1109
1110 const QList< QgsExpressionNode * > nodeList = mList->list();
1111 for ( QgsExpressionNode *n : nodeList )
1112 {
1113 QVariant v2 = n->eval( parent, context );
1115 if ( QgsExpressionUtils::isNull( v2 ) )
1116 listHasNull = true;
1117 else
1118 {
1119 bool equal = false;
1120 // check whether they are equal
1121 if ( ( v1.userType() != QMetaType::Type::QString || v2.userType() != QMetaType::Type::QString ) &&
1122 QgsExpressionUtils::isDoubleSafe( v1 ) && QgsExpressionUtils::isDoubleSafe( v2 ) )
1123 {
1124 // do numeric comparison if both operators can be converted to numbers,
1125 // and they aren't both string
1126 double f1 = QgsExpressionUtils::getDoubleValue( v1, parent );
1128 double f2 = QgsExpressionUtils::getDoubleValue( v2, parent );
1130 equal = qgsDoubleNear( f1, f2 );
1131 }
1132 else
1133 {
1134 QString s1 = QgsExpressionUtils::getStringValue( v1, parent );
1136 QString s2 = QgsExpressionUtils::getStringValue( v2, parent );
1138 equal = QString::compare( s1, s2 ) == 0;
1139 }
1140
1141 if ( equal ) // we know the result
1142 return mNotIn ? TVL_False : TVL_True;
1143 }
1144 }
1145
1146 // item not found
1147 if ( listHasNull )
1148 return TVL_Unknown;
1149 else
1150 return mNotIn ? TVL_True : TVL_False;
1151}
1152
1154{
1155 delete mNode;
1156 delete mList;
1157}
1158
1163
1165{
1166 bool res = mNode->prepare( parent, context );
1167 const QList< QgsExpressionNode * > nodeList = mList->list();
1168 for ( QgsExpressionNode *n : nodeList )
1169 {
1170 res = res && n->prepare( parent, context );
1171 }
1172 return res;
1173}
1174
1176{
1177 return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1178}
1179
1181{
1182 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1183 cloneTo( copy );
1184 return copy;
1185}
1186
1188{
1189 if ( !mNode->isStatic( parent, context ) )
1190 return false;
1191
1192 const QList< QgsExpressionNode * > nodeList = mList->list();
1193 for ( QgsExpressionNode *n : nodeList )
1194 {
1195 if ( !n->isStatic( parent, context ) )
1196 return false;
1197 }
1198
1199 return true;
1200}
1201
1202//
1203
1205{
1206 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1207 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1208
1209 QVariant res = fd->run( mArgs, context, parent, this );
1211
1212 // everything went fine
1213 return res;
1214}
1215
1217 : mFnIndex( fnIndex )
1218{
1219 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1220 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1221 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1222 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1223
1224 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1225 const int functionParamsSize = functionParams.size();
1226 if ( functionParams.isEmpty() )
1227 {
1228 // function does not support parameters
1229 mArgs = args;
1230 }
1231 else if ( !args )
1232 {
1233 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1234 mArgs = new NodeList();
1235 mArgs->reserve( functionParamsSize );
1236 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1237 {
1238 // insert default value for QgsExpressionFunction::Parameter
1239 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1240 }
1241 }
1242 else
1243 {
1244 mArgs = new NodeList();
1245 mArgs->reserve( functionParamsSize );
1246
1247 int idx = 0;
1248 const QStringList argNames = args->names();
1249 const QList<QgsExpressionNode *> argList = args->list();
1250 //first loop through unnamed arguments
1251 {
1252 const int argNamesSize = argNames.size();
1253 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1254 {
1255 mArgs->append( argList.at( idx )->clone() );
1256 idx++;
1257 }
1258 }
1259
1260 //next copy named QgsExpressionFunction::Parameters in order expected by function
1261 for ( ; idx < functionParamsSize; ++idx )
1262 {
1263 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1264 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1265 if ( nodeIdx < 0 )
1266 {
1267 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1268 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1269 }
1270 else
1271 {
1272 mArgs->append( argList.at( nodeIdx )->clone() );
1273 }
1274 }
1275
1276 delete args;
1277 }
1278}
1279
1284
1289
1291{
1292 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1293
1294 bool res = fd->prepare( this, parent, context );
1295 if ( mArgs && !fd->lazyEval() )
1296 {
1297 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1298 for ( QgsExpressionNode *n : nodeList )
1299 {
1300 res = res && n->prepare( parent, context );
1301 }
1302 }
1303 return res;
1304}
1305
1307{
1308 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1309 if ( fd->params() == 0 )
1310 return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1311 else
1312 return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1313}
1314
1316{
1317 if ( hasCachedStaticValue() )
1318 return QSet< QString >();
1319
1320 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1321 QSet<QString> functionColumns = fd->referencedColumns( this );
1322
1323 if ( !mArgs )
1324 {
1325 //no referenced columns in arguments, just return function's referenced columns
1326 return functionColumns;
1327 }
1328
1329 int paramIndex = 0;
1330 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1331 for ( QgsExpressionNode *n : nodeList )
1332 {
1333 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1334 functionColumns.unite( n->referencedColumns() );
1335 paramIndex++;
1336 }
1337
1338 return functionColumns;
1339}
1340
1342{
1343 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1344 if ( fd->name() == QLatin1String( "var" ) )
1345 {
1346 if ( !mArgs->list().isEmpty() )
1347 {
1348 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1349 if ( var )
1350 return QSet<QString>() << var->value().toString();
1351 }
1352 return QSet<QString>() << QString();
1353 }
1354 else
1355 {
1356 QSet<QString> functionVariables = QSet<QString>();
1357
1358 if ( !mArgs )
1359 return functionVariables;
1360
1361 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1362 for ( QgsExpressionNode *n : nodeList )
1363 {
1364 functionVariables.unite( n->referencedVariables() );
1365 }
1366
1367 return functionVariables;
1368 }
1369}
1370
1372{
1373 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1374 QSet<QString> functions = QSet<QString>();
1375 functions.insert( fd->name() );
1376
1377 if ( !mArgs )
1378 return functions;
1379
1380 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1381 for ( QgsExpressionNode *n : nodeList )
1382 {
1383 functions.unite( n->referencedFunctions() );
1384 }
1385 return functions;
1386}
1387
1388QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1389{
1390 QList<const QgsExpressionNode *> lst;
1391 lst << this;
1392 if ( !mArgs )
1393 return lst;
1394
1395 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1396 for ( QgsExpressionNode *n : nodeList )
1397 {
1398 lst += n->nodes();
1399 }
1400 return lst;
1401}
1402
1404{
1405 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1406 if ( mArgs )
1407 {
1408 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1409 for ( QgsExpressionNode *n : nodeList )
1410 needs |= n->needsGeometry();
1411 }
1412 return needs;
1413}
1414
1416{
1417 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1418 cloneTo( copy );
1419 return copy;
1420}
1421
1423{
1424 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1425}
1426
1428{
1429 if ( !args || !args->hasNamedNodes() )
1430 return true;
1431
1432 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1433 if ( functionParams.isEmpty() )
1434 {
1435 error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1436 return false;
1437 }
1438 else
1439 {
1440 QSet< int > providedArgs;
1441 QSet< int > handledArgs;
1442 int idx = 0;
1443 //first loop through unnamed arguments
1444 while ( args->names().at( idx ).isEmpty() )
1445 {
1446 providedArgs << idx;
1447 handledArgs << idx;
1448 idx++;
1449 }
1450
1451 //next check named QgsExpressionFunction::Parameters
1452 for ( ; idx < functionParams.count(); ++idx )
1453 {
1454 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1455 if ( nodeIdx < 0 )
1456 {
1457 if ( !functionParams.at( idx ).optional() )
1458 {
1459 error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1460 return false;
1461 }
1462 }
1463 else
1464 {
1465 if ( providedArgs.contains( idx ) )
1466 {
1467 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1468 return false;
1469 }
1470 }
1471 providedArgs << idx;
1472 handledArgs << nodeIdx;
1473 }
1474
1475 //last check for bad names
1476 idx = 0;
1477 const QStringList nameList = args->names();
1478 for ( const QString &name : nameList )
1479 {
1480 if ( !name.isEmpty() && !functionParams.contains( name ) )
1481 {
1482 error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1483 return false;
1484 }
1485 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1486 {
1487 int functionIdx = functionParams.indexOf( name );
1488 if ( providedArgs.contains( functionIdx ) )
1489 {
1490 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1491 return false;
1492 }
1493 }
1494 idx++;
1495 }
1496
1497 }
1498 return true;
1499}
1500
1501//
1502
1504{
1505 Q_UNUSED( context )
1506 Q_UNUSED( parent )
1507 return mValue;
1508}
1509
1514
1516{
1517 Q_UNUSED( parent )
1518 Q_UNUSED( context )
1519 return true;
1520}
1521
1522
1524{
1525 if ( QgsVariantUtils::isNull( mValue ) )
1526 return QStringLiteral( "NULL" );
1527
1528 switch ( mValue.userType() )
1529 {
1530 case QMetaType::Type::Int:
1531 return QString::number( mValue.toInt() );
1532 case QMetaType::Type::Double:
1533 return QString::number( mValue.toDouble() );
1534 case QMetaType::Type::LongLong:
1535 return QString::number( mValue.toLongLong() );
1536 case QMetaType::Type::QString:
1537 return QgsExpression::quotedString( mValue.toString() );
1538 case QMetaType::Type::QTime:
1539 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1540 case QMetaType::Type::QDate:
1541 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1542 case QMetaType::Type::QDateTime:
1543 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1544 case QMetaType::Type::Bool:
1545 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1546 default:
1547 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1548 }
1549}
1550
1552{
1553 return valueAsString();
1554}
1555
1557{
1558 return QSet<QString>();
1559}
1560
1562{
1563 return QSet<QString>();
1564}
1565
1567{
1568 return QSet<QString>();
1569}
1570
1571QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1572{
1573 QList<const QgsExpressionNode *> lst;
1574 lst << this;
1575 return lst;
1576}
1577
1579{
1580 return false;
1581}
1582
1584{
1586 cloneTo( copy );
1587 return copy;
1588}
1589
1591{
1592 Q_UNUSED( context )
1593 Q_UNUSED( parent )
1594 return true;
1595}
1596
1597//
1598
1600{
1601 Q_UNUSED( parent )
1602 int index = mIndex;
1603
1604 if ( index < 0 )
1605 {
1606 // have not yet found field index - first check explicitly set fields collection
1607 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1608 {
1609 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1610 index = fields.lookupField( mName );
1611 }
1612 }
1613
1614 if ( context )
1615 {
1616 QgsFeature feature = context->feature();
1617 if ( feature.isValid() )
1618 {
1619 if ( index >= 0 )
1620 return feature.attribute( index );
1621 else
1622 return feature.attribute( mName );
1623 }
1624 else
1625 {
1626 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1627 }
1628 }
1629 if ( index < 0 )
1630 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1631 return QVariant();
1632}
1633
1638
1640{
1641 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1642 return false;
1643
1644 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1645
1646 mIndex = fields.lookupField( mName );
1647
1648 if ( mIndex == -1 && context->hasFeature() )
1649 {
1650 mIndex = context->feature().fieldNameIndex( mName );
1651 }
1652
1653 if ( mIndex == -1 )
1654 {
1655 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1656 return false;
1657 }
1658 return true;
1659}
1660
1662{
1663 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" ) );
1664 const QRegularExpressionMatch match = re.match( mName );
1665 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1666}
1667
1669{
1670 return QSet<QString>() << mName;
1671}
1672
1674{
1675 return QSet<QString>();
1676}
1677
1679{
1680 return QSet<QString>();
1681}
1682
1683QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1684{
1685 QList<const QgsExpressionNode *> result;
1686 result << this;
1687 return result;
1688}
1689
1691{
1692 return false;
1693}
1694
1696{
1698 cloneTo( copy );
1699 return copy;
1700}
1701
1703{
1704 Q_UNUSED( context )
1705 Q_UNUSED( parent )
1706 return false;
1707}
1708
1709//
1710
1712 : mConditions( *conditions )
1713 , mElseExp( elseExp )
1714{
1715 delete conditions;
1716}
1717
1719{
1720 delete mElseExp;
1721 qDeleteAll( mConditions );
1722}
1723
1728
1730{
1731 for ( WhenThen *cond : std::as_const( mConditions ) )
1732 {
1733 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1734 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1736 if ( tvl == QgsExpressionUtils::True )
1737 {
1738 QVariant vRes = cond->mThenExp->eval( parent, context );
1740 return vRes;
1741 }
1742 }
1743
1744 if ( mElseExp )
1745 {
1746 QVariant vElse = mElseExp->eval( parent, context );
1748 return vElse;
1749 }
1750
1751 // return NULL if no condition is matching
1752 return QVariant();
1753}
1754
1756{
1757 bool foundAnyNonStaticConditions = false;
1758 for ( WhenThen *cond : std::as_const( mConditions ) )
1759 {
1760 const bool res = cond->mWhenExp->prepare( parent, context )
1761 && cond->mThenExp->prepare( parent, context );
1762 if ( !res )
1763 return false;
1764
1765 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1766 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1767 {
1768 // 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
1769 // value, and the static value for this WHEN clause is True.
1770 if ( cond->mThenExp->hasCachedStaticValue() )
1771 {
1772 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1773 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1774 mHasCachedValue = true;
1775 return true;
1776 }
1777 else
1778 {
1779 // 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
1780 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1781 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1782 return true;
1783 }
1784 }
1785 }
1786
1787 if ( mElseExp )
1788 {
1789 const bool res = mElseExp->prepare( parent, context );
1790 if ( !res )
1791 return false;
1792
1793 if ( !foundAnyNonStaticConditions )
1794 {
1795 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1796 if ( mElseExp->hasCachedStaticValue() )
1797 {
1799 mHasCachedValue = true;
1800 return true;
1801 }
1802 else
1803 {
1804 // so even though the ELSE node is non-static we can effectively replace
1805 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1806 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1807 return true;
1808 }
1809 }
1810 }
1811
1812 return true;
1813}
1814
1816{
1817 QString msg( QStringLiteral( "CASE" ) );
1818 for ( WhenThen *cond : mConditions )
1819 {
1820 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1821 }
1822 if ( mElseExp )
1823 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1824 msg += QLatin1String( " END" );
1825 return msg;
1826}
1827
1829{
1830 if ( hasCachedStaticValue() )
1831 return QSet< QString >();
1832
1833 QSet<QString> lst;
1834 for ( WhenThen *cond : mConditions )
1835 {
1836 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1837 }
1838
1839 if ( mElseExp )
1840 lst += mElseExp->referencedColumns();
1841
1842 return lst;
1843}
1844
1846{
1847 QSet<QString> lst;
1848 for ( WhenThen *cond : mConditions )
1849 {
1850 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1851 }
1852
1853 if ( mElseExp )
1854 lst += mElseExp->referencedVariables();
1855
1856 return lst;
1857}
1858
1860{
1861 QSet<QString> lst;
1862 for ( WhenThen *cond : mConditions )
1863 {
1864 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1865 }
1866
1867 if ( mElseExp )
1868 lst += mElseExp->referencedFunctions();
1869
1870 return lst;
1871}
1872
1873QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1874{
1875 QList<const QgsExpressionNode *> lst;
1876 lst << this;
1877 for ( WhenThen *cond : mConditions )
1878 {
1879 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1880 }
1881
1882 if ( mElseExp )
1883 lst += mElseExp->nodes();
1884
1885 return lst;
1886}
1887
1889{
1890 for ( WhenThen *cond : mConditions )
1891 {
1892 if ( cond->mWhenExp->needsGeometry() ||
1893 cond->mThenExp->needsGeometry() )
1894 return true;
1895 }
1896
1897 return mElseExp && mElseExp->needsGeometry();
1898}
1899
1901{
1903 conditions.reserve( mConditions.size() );
1904 for ( WhenThen *wt : mConditions )
1905 conditions.append( wt->clone() );
1906
1907 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1908 cloneTo( copy );
1909 return copy;
1910}
1911
1913{
1914 for ( WhenThen *wt : mConditions )
1915 {
1916 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1917 return false;
1918 }
1919
1920 if ( mElseExp )
1921 return mElseExp->isStatic( parent, context );
1922
1923 return true;
1924}
1925
1927{
1928 if ( hasCachedStaticValue() )
1929 return QSet< QString >();
1930
1931 QSet<QString> lst( mNode->referencedColumns() );
1932 const QList< QgsExpressionNode * > nodeList = mList->list();
1933 for ( const QgsExpressionNode *n : nodeList )
1934 lst.unite( n->referencedColumns() );
1935 return lst;
1936}
1937
1939{
1940 QSet<QString> lst( mNode->referencedVariables() );
1941 const QList< QgsExpressionNode * > nodeList = mList->list();
1942 for ( const QgsExpressionNode *n : nodeList )
1943 lst.unite( n->referencedVariables() );
1944 return lst;
1945}
1946
1948{
1949 QSet<QString> lst( mNode->referencedFunctions() );
1950 const QList< QgsExpressionNode * > nodeList = mList->list();
1951 for ( const QgsExpressionNode *n : nodeList )
1952 lst.unite( n->referencedFunctions() );
1953 return lst;
1954}
1955
1956QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1957{
1958 QList<const QgsExpressionNode *> lst;
1959 lst << this;
1960 const QList< QgsExpressionNode * > nodeList = mList->list();
1961 for ( const QgsExpressionNode *n : nodeList )
1962 lst += n->nodes();
1963 return lst;
1964}
1965
1966
1968{
1969 delete mNode;
1970 delete mLowerBound;
1971 delete mHigherBound;
1972}
1973
1978
1980{
1981 bool res = mNode->prepare( parent, context );
1982 res = res && mLowerBound->prepare( parent, context );
1983 res = res && mHigherBound->prepare( parent, context );
1984 return res;
1985}
1986
1988{
1989 const QVariant nodeVal = mNode->eval( parent, context );
1990 if ( QgsVariantUtils::isNull( nodeVal ) )
1991 {
1992 return QVariant();
1993 }
1994
1995 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1996
1998 const QVariant lowBoundValue = lowBound.eval( parent, context );
1999 const bool lowBoundBool { lowBoundValue.toBool() };
2000
2001 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
2002 {
2003 return QVariant( mNegate );
2004 }
2005
2007 const QVariant highBoundValue = highBound.eval( parent, context );
2008
2009 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2010 {
2011 return QVariant();
2012 }
2013
2014 const bool highBoundBool { highBoundValue.toBool() };
2015
2016 // We already checked if both are nulls
2017 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2018 {
2019
2020 // In this case we can return a boolean
2021 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
2022 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
2023 {
2024 return QVariant( mNegate );
2025 }
2026
2027 // Indetermined
2028 return QVariant();
2029
2030 }
2031
2032 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
2033 {
2034 return QVariant( mNegate );
2035 }
2036
2037 const bool res { lowBoundBool &&highBoundBool };
2038 return mNegate ? QVariant( ! res ) : QVariant( res );
2039
2040}
2041
2043{
2044 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
2045}
2046
2048{
2049 QSet<QString> lst( mNode->referencedVariables() );
2050 lst.unite( mLowerBound->referencedVariables() );
2051 lst.unite( mHigherBound->referencedVariables() );
2052 return lst;
2053}
2054
2056{
2057 QSet<QString> lst( mNode->referencedFunctions() );
2058 lst.unite( mLowerBound->referencedFunctions() );
2059 lst.unite( mHigherBound->referencedFunctions() );
2060 return lst;
2061}
2062
2063QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2064{
2065 return { this, mLowerBound, mHigherBound };
2066}
2067
2069{
2070 QSet<QString> lst( mNode->referencedColumns() );
2071 lst.unite( mLowerBound->referencedColumns() );
2072 lst.unite( mHigherBound->referencedColumns() );
2073 return lst;
2074}
2075
2077{
2078 if ( mNode->needsGeometry() )
2079 return true;
2080
2081 if ( mLowerBound->needsGeometry() )
2082 return true;
2083
2084 if ( mHigherBound->needsGeometry() )
2085 return true;
2086
2087 return false;
2088}
2089
2091{
2092 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2093 cloneTo( copy );
2094 return copy;
2095}
2096
2098{
2099 if ( !mNode->isStatic( parent, context ) )
2100 return false;
2101
2102 if ( !mLowerBound->isStatic( parent, context ) )
2103 return false;
2104
2105 if ( !mHigherBound->isStatic( parent, context ) )
2106 return false;
2107
2108 return true;
2109}
2110
2112{
2113 return mLowerBound;
2114}
2115
2117{
2118 return mHigherBound;
2119}
2120
2122{
2123 return mNegate;
2124}
2125
2127 : mWhenExp( whenExp )
2128 , mThenExp( thenExp )
2129{
2130}
2131
2133{
2134 delete mWhenExp;
2135 delete mThenExp;
2136}
2137
2139{
2140 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2141}
2142
2144{
2145 return BINARY_OPERATOR_TEXT[mOp];
2146}
2147
2148//
2149
2151{
2152 const QVariant container = mContainer->eval( parent, context );
2154 const QVariant index = mIndex->eval( parent, context );
2156
2157 switch ( container.userType() )
2158 {
2159 case QMetaType::Type::QVariantMap:
2160 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2161
2162 case QMetaType::Type::QVariantList:
2163 case QMetaType::Type::QStringList:
2164 {
2165 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2166 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2167 if ( pos >= list.length() || pos < -list.length() )
2168 {
2169 return QVariant();
2170 }
2171 if ( pos < 0 )
2172 {
2173 // negative indices are from back of list
2174 pos += list.length();
2175 }
2176
2177 return list.at( pos );
2178 }
2179
2180 default:
2181 if ( !QgsVariantUtils::isNull( container ) )
2182 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2183 return QVariant();
2184 }
2185}
2186
2191
2193{
2194 bool resC = mContainer->prepare( parent, context );
2195 bool resV = mIndex->prepare( parent, context );
2196 return resC && resV;
2197}
2198
2200{
2201 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2202}
2203
2205{
2206 if ( hasCachedStaticValue() )
2207 return QSet< QString >();
2208
2209 return mContainer->referencedColumns() + mIndex->referencedColumns();
2210}
2211
2213{
2214 return mContainer->referencedVariables() + mIndex->referencedVariables();
2215}
2216
2218{
2219 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2220}
2221
2222QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2223{
2224 QList<const QgsExpressionNode *> lst;
2225 lst << this;
2226 lst += mContainer->nodes() + mIndex->nodes();
2227 return lst;
2228}
2229
2231{
2232 return mContainer->needsGeometry() || mIndex->needsGeometry();
2233}
2234
2236{
2237 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2238 cloneTo( copy );
2239 return copy;
2240}
2241
2243{
2244 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2245}
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.
A 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.
SQL-like BETWEEN and NOT BETWEEN predicates.
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.
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.
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.
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.
QgsExpressionNode * clone() const override
Generate a clone of this node.
QString text() const
Returns a the name of this operator without the operands.
bool prepareNode(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsExpressionNode::NodeType nodeType() const override
Gets the type of this node.
An expression node which takes it 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.
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.
QgsExpressionNodeCondition::WhenThen * clone() const
Gets a deep copy of this WhenThen combination.
An expression node for CASE WHEN clauses.
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.
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.
An expression node for expression functions.
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.
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.
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.
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.
A indexing expression operator, which allows use of square brackets [] to reference map and array ite...
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.
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.
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.
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.
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.
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.
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.
bool hasNamedNodes() const
Returns true if list contains any named nodes.
virtual QString dump() const
Returns a string dump of the expression node.
QStringList names() const
Returns a list of names for nodes.
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.
void reserve(int size)
Reserves size for the node list.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Abstract base class for all nodes that can appear in an expression.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
virtual QString dump() const =0
Dump this node into a serialized (part) of an expression.
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.
virtual bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const =0
Returns true if this node can be evaluated for a static value.
bool prepare(QgsExpression *parent, const QgsExpressionContext *context)
Prepare this node for evaluation.
virtual QSet< QString > referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node.
bool mHasCachedValue
true if the node has a static, precalculated value.
const QgsExpressionNode * effectiveNode() const
Returns a reference to the simplest node which represents this node, after any compilation optimizati...
QVariant cachedStaticValue() const
Returns the node's static cached value.
virtual QSet< QString > referencedVariables() const =0
Returns a set of all variables which are used in this expression.
QVariant mCachedStaticValue
Contains the static, precalculated value for the node if mHasCachedValue is true.
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.
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression.
virtual QList< const QgsExpressionNode * > nodes() const =0
Returns a list of all nodes which are used in this expression.
void cloneTo(QgsExpressionNode *target) const
Copies the members of this node to the node provided in target.
virtual QSet< QString > referencedFunctions() const =0
Returns a set of all functions which are used in this expression.
Class for 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:58
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:46
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:46
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.
#define str(x)
Definition qgis.cpp:39
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5958
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.