QGIS API Documentation 3.43.0-Master (56aa1fd18d7)
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#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.get() ) )
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->isNotIn() || 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 auto 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 auto 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{
920 QgsExpressionNodeBinaryOperator *lOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpLeft.get() );
921 QgsExpressionNodeBinaryOperator *rOp = dynamic_cast<QgsExpressionNodeBinaryOperator *>( mOpRight.get() );
922 QgsExpressionNodeUnaryOperator *ruOp = dynamic_cast<QgsExpressionNodeUnaryOperator *>( mOpRight.get() );
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
1156
1161
1163{
1164 bool res = mNode->prepare( parent, context );
1165 const QList< QgsExpressionNode * > nodeList = mList->list();
1166 for ( QgsExpressionNode *n : nodeList )
1167 {
1168 res = res && n->prepare( parent, context );
1169 }
1170 return res;
1171}
1172
1174{
1175 return QStringLiteral( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
1176}
1177
1179{
1180 QgsExpressionNodeInOperator *copy = new QgsExpressionNodeInOperator( mNode->clone(), mList->clone(), mNotIn );
1181 cloneTo( copy );
1182 return copy;
1183}
1184
1186{
1187 if ( !mNode->isStatic( parent, context ) )
1188 return false;
1189
1190 const QList< QgsExpressionNode * > nodeList = mList->list();
1191 for ( QgsExpressionNode *n : nodeList )
1192 {
1193 if ( !n->isStatic( parent, context ) )
1194 return false;
1195 }
1196
1197 return true;
1198}
1199
1200//
1201
1203{
1204 QString name = QgsExpression::QgsExpression::Functions()[mFnIndex]->name();
1205 QgsExpressionFunction *fd = context && context->hasFunction( name ) ? context->function( name ) : QgsExpression::QgsExpression::Functions()[mFnIndex];
1206
1207 QVariant res = fd->run( mArgs.get(), context, parent, this );
1209
1210 // everything went fine
1211 return res;
1212}
1213
1215 : mFnIndex( fnIndex )
1216{
1217 // lock the function mutex once upfront -- we'll be doing this when calling QgsExpression::Functions() anyway,
1218 // and it's cheaper to hold the recursive lock once upfront like while we handle ALL the function's arguments,
1219 // since those might be QgsExpressionNodeFunction nodes and would need to re-obtain the lock otherwise.
1220 QMutexLocker locker( &QgsExpression::QgsExpression::sFunctionsMutex );
1221
1222 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::QgsExpression::Functions()[mFnIndex]->parameters();
1223 const int functionParamsSize = functionParams.size();
1224 if ( functionParams.isEmpty() )
1225 {
1226 // function does not support parameters
1227 mArgs.reset( args );
1228 }
1229 else if ( !args )
1230 {
1231 // no arguments specified, but function has parameters. Build a list of default parameter values for the arguments list.
1232 mArgs = std::make_unique<NodeList>();
1233 mArgs->reserve( functionParamsSize );
1234 for ( const QgsExpressionFunction::Parameter &param : functionParams )
1235 {
1236 // insert default value for QgsExpressionFunction::Parameter
1237 mArgs->append( new QgsExpressionNodeLiteral( param.defaultValue() ) );
1238 }
1239 }
1240 else
1241 {
1242 mArgs = std::make_unique<NodeList>();
1243 mArgs->reserve( functionParamsSize );
1244
1245 int idx = 0;
1246 const QStringList argNames = args->names();
1247 const QList<QgsExpressionNode *> argList = args->list();
1248 //first loop through unnamed arguments
1249 {
1250 const int argNamesSize = argNames.size();
1251 while ( idx < argNamesSize && argNames.at( idx ).isEmpty() )
1252 {
1253 mArgs->append( argList.at( idx )->clone() );
1254 idx++;
1255 }
1256 }
1257
1258 //next copy named QgsExpressionFunction::Parameters in order expected by function
1259 for ( ; idx < functionParamsSize; ++idx )
1260 {
1261 const QgsExpressionFunction::Parameter &parameter = functionParams.at( idx );
1262 int nodeIdx = argNames.indexOf( parameter.name().toLower() );
1263 if ( nodeIdx < 0 )
1264 {
1265 //QgsExpressionFunction::Parameter not found - insert default value for QgsExpressionFunction::Parameter
1266 mArgs->append( new QgsExpressionNodeLiteral( parameter.defaultValue() ) );
1267 }
1268 else
1269 {
1270 mArgs->append( argList.at( nodeIdx )->clone() );
1271 }
1272 }
1273
1274 delete args;
1275 }
1276}
1277
1282
1287
1289{
1290 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1291
1292 bool res = fd->prepare( this, parent, context );
1293 if ( mArgs && !fd->lazyEval() )
1294 {
1295 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1296 for ( QgsExpressionNode *n : nodeList )
1297 {
1298 res = res && n->prepare( parent, context );
1299 }
1300 }
1301 return res;
1302}
1303
1305{
1306 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1307 if ( fd->params() == 0 )
1308 return QStringLiteral( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? QString() : QStringLiteral( "()" ) ); // special column
1309 else
1310 return QStringLiteral( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
1311}
1312
1314{
1315 if ( hasCachedStaticValue() )
1316 return QSet< QString >();
1317
1318 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1319 QSet<QString> functionColumns = fd->referencedColumns( this );
1320
1321 if ( !mArgs )
1322 {
1323 //no referenced columns in arguments, just return function's referenced columns
1324 return functionColumns;
1325 }
1326
1327 int paramIndex = 0;
1328 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1329 for ( QgsExpressionNode *n : nodeList )
1330 {
1331 if ( fd->parameters().count() <= paramIndex || !fd->parameters().at( paramIndex ).isSubExpression() )
1332 functionColumns.unite( n->referencedColumns() );
1333 paramIndex++;
1334 }
1335
1336 return functionColumns;
1337}
1338
1340{
1341 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1342 if ( fd->name() == QLatin1String( "var" ) )
1343 {
1344 if ( !mArgs->list().isEmpty() )
1345 {
1346 QgsExpressionNodeLiteral *var = dynamic_cast<QgsExpressionNodeLiteral *>( mArgs->list().at( 0 ) );
1347 if ( var )
1348 return QSet<QString>() << var->value().toString();
1349 }
1350 return QSet<QString>() << QString();
1351 }
1352 else
1353 {
1354 QSet<QString> functionVariables = QSet<QString>();
1355
1356 if ( !mArgs )
1357 return functionVariables;
1358
1359 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1360 for ( QgsExpressionNode *n : nodeList )
1361 {
1362 functionVariables.unite( n->referencedVariables() );
1363 }
1364
1365 return functionVariables;
1366 }
1367}
1368
1370{
1371 QgsExpressionFunction *fd = QgsExpression::QgsExpression::Functions()[mFnIndex];
1372 QSet<QString> functions = QSet<QString>();
1373 functions.insert( fd->name() );
1374
1375 if ( !mArgs )
1376 return functions;
1377
1378 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1379 for ( QgsExpressionNode *n : nodeList )
1380 {
1381 functions.unite( n->referencedFunctions() );
1382 }
1383 return functions;
1384}
1385
1386QList<const QgsExpressionNode *> QgsExpressionNodeFunction::nodes() const
1387{
1388 QList<const QgsExpressionNode *> lst;
1389 lst << this;
1390 if ( !mArgs )
1391 return lst;
1392
1393 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1394 for ( QgsExpressionNode *n : nodeList )
1395 {
1396 lst += n->nodes();
1397 }
1398 return lst;
1399}
1400
1402{
1403 bool needs = QgsExpression::QgsExpression::Functions()[mFnIndex]->usesGeometry( this );
1404 if ( mArgs )
1405 {
1406 const QList< QgsExpressionNode * > nodeList = mArgs->list();
1407 for ( QgsExpressionNode *n : nodeList )
1408 needs |= n->needsGeometry();
1409 }
1410 return needs;
1411}
1412
1414{
1415 QgsExpressionNodeFunction *copy = new QgsExpressionNodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
1416 cloneTo( copy );
1417 return copy;
1418}
1419
1421{
1422 return QgsExpression::Functions()[mFnIndex]->isStatic( this, parent, context );
1423}
1424
1426{
1427 if ( !args || !args->hasNamedNodes() )
1428 return true;
1429
1430 const QgsExpressionFunction::ParameterList &functionParams = QgsExpression::Functions()[fnIndex]->parameters();
1431 if ( functionParams.isEmpty() )
1432 {
1433 error = QStringLiteral( "%1 does not support named QgsExpressionFunction::Parameters" ).arg( QgsExpression::Functions()[fnIndex]->name() );
1434 return false;
1435 }
1436 else
1437 {
1438 QSet< int > providedArgs;
1439 QSet< int > handledArgs;
1440 int idx = 0;
1441 //first loop through unnamed arguments
1442 while ( args->names().at( idx ).isEmpty() )
1443 {
1444 providedArgs << idx;
1445 handledArgs << idx;
1446 idx++;
1447 }
1448
1449 //next check named QgsExpressionFunction::Parameters
1450 for ( ; idx < functionParams.count(); ++idx )
1451 {
1452 int nodeIdx = args->names().indexOf( functionParams.at( idx ).name().toLower() );
1453 if ( nodeIdx < 0 )
1454 {
1455 if ( !functionParams.at( idx ).optional() )
1456 {
1457 error = QStringLiteral( "No value specified for QgsExpressionFunction::Parameter '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1458 return false;
1459 }
1460 }
1461 else
1462 {
1463 if ( providedArgs.contains( idx ) )
1464 {
1465 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( idx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1466 return false;
1467 }
1468 }
1469 providedArgs << idx;
1470 handledArgs << nodeIdx;
1471 }
1472
1473 //last check for bad names
1474 idx = 0;
1475 const QStringList nameList = args->names();
1476 for ( const QString &name : nameList )
1477 {
1478 if ( !name.isEmpty() && !functionParams.contains( name ) )
1479 {
1480 error = QStringLiteral( "Invalid QgsExpressionFunction::Parameter name '%1' for %2" ).arg( name, QgsExpression::Functions()[fnIndex]->name() );
1481 return false;
1482 }
1483 if ( !name.isEmpty() && !handledArgs.contains( idx ) )
1484 {
1485 int functionIdx = functionParams.indexOf( name );
1486 if ( providedArgs.contains( functionIdx ) )
1487 {
1488 error = QStringLiteral( "Duplicate QgsExpressionFunction::Parameter specified for '%1' for %2" ).arg( functionParams.at( functionIdx ).name(), QgsExpression::Functions()[fnIndex]->name() );
1489 return false;
1490 }
1491 }
1492 idx++;
1493 }
1494
1495 }
1496 return true;
1497}
1498
1499//
1500
1502{
1503 Q_UNUSED( context )
1504 Q_UNUSED( parent )
1505 return mValue;
1506}
1507
1512
1514{
1515 Q_UNUSED( parent )
1516 Q_UNUSED( context )
1517 return true;
1518}
1519
1520
1522{
1523 if ( QgsVariantUtils::isNull( mValue ) )
1524 return QStringLiteral( "NULL" );
1525
1526 switch ( mValue.userType() )
1527 {
1528 case QMetaType::Type::Int:
1529 return QString::number( mValue.toInt() );
1530 case QMetaType::Type::Double:
1531 return qgsDoubleToString( mValue.toDouble() );
1532 case QMetaType::Type::LongLong:
1533 return QString::number( mValue.toLongLong() );
1534 case QMetaType::Type::QString:
1535 return QgsExpression::quotedString( mValue.toString() );
1536 case QMetaType::Type::QTime:
1537 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
1538 case QMetaType::Type::QDate:
1539 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
1540 case QMetaType::Type::QDateTime:
1541 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
1542 case QMetaType::Type::Bool:
1543 return mValue.toBool() ? QStringLiteral( "TRUE" ) : QStringLiteral( "FALSE" );
1544 default:
1545 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
1546 }
1547}
1548
1550{
1551 return valueAsString();
1552}
1553
1555{
1556 return QSet<QString>();
1557}
1558
1560{
1561 return QSet<QString>();
1562}
1563
1565{
1566 return QSet<QString>();
1567}
1568
1569QList<const QgsExpressionNode *> QgsExpressionNodeLiteral::nodes() const
1570{
1571 QList<const QgsExpressionNode *> lst;
1572 lst << this;
1573 return lst;
1574}
1575
1577{
1578 return false;
1579}
1580
1582{
1584 cloneTo( copy );
1585 return copy;
1586}
1587
1589{
1590 Q_UNUSED( context )
1591 Q_UNUSED( parent )
1592 return true;
1593}
1594
1595//
1596
1598{
1599 Q_UNUSED( parent )
1600 int index = mIndex;
1601
1602 if ( index < 0 )
1603 {
1604 // have not yet found field index - first check explicitly set fields collection
1605 if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1606 {
1607 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1608 index = fields.lookupField( mName );
1609 }
1610 }
1611
1612 if ( context )
1613 {
1614 QgsFeature feature = context->feature();
1615 if ( feature.isValid() )
1616 {
1617 if ( index >= 0 )
1618 return feature.attribute( index );
1619 else
1620 return feature.attribute( mName );
1621 }
1622 else
1623 {
1624 parent->setEvalErrorString( tr( "No feature available for field '%1' evaluation" ).arg( mName ) );
1625 }
1626 }
1627 if ( index < 0 )
1628 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1629 return QVariant();
1630}
1631
1636
1638{
1639 if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
1640 return false;
1641
1642 QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
1643
1644 mIndex = fields.lookupField( mName );
1645
1646 if ( mIndex == -1 && context->hasFeature() )
1647 {
1648 mIndex = context->feature().fieldNameIndex( mName );
1649 }
1650
1651 if ( mIndex == -1 )
1652 {
1653 parent->setEvalErrorString( tr( "Field '%1' not found" ).arg( mName ) );
1654 return false;
1655 }
1656 return true;
1657}
1658
1660{
1661 const thread_local QRegularExpression re( QStringLiteral( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" ) );
1662 const QRegularExpressionMatch match = re.match( mName );
1663 return match.hasMatch() ? mName : QgsExpression::quotedColumnRef( mName );
1664}
1665
1667{
1668 return QSet<QString>() << mName;
1669}
1670
1672{
1673 return QSet<QString>();
1674}
1675
1677{
1678 return QSet<QString>();
1679}
1680
1681QList<const QgsExpressionNode *> QgsExpressionNodeColumnRef::nodes() const
1682{
1683 QList<const QgsExpressionNode *> result;
1684 result << this;
1685 return result;
1686}
1687
1689{
1690 return false;
1691}
1692
1694{
1696 cloneTo( copy );
1697 return copy;
1698}
1699
1701{
1702 Q_UNUSED( context )
1703 Q_UNUSED( parent )
1704 return false;
1705}
1706
1707//
1708
1710 : mConditions( *conditions )
1711 , mElseExp( elseExp )
1712{
1713 delete conditions;
1714}
1715
1717{
1718
1719 qDeleteAll( mConditions );
1720}
1721
1726
1728{
1729 for ( WhenThen *cond : std::as_const( mConditions ) )
1730 {
1731 QVariant vWhen = cond->mWhenExp->eval( parent, context );
1732 QgsExpressionUtils::TVL tvl = QgsExpressionUtils::getTVLValue( vWhen, parent );
1734 if ( tvl == QgsExpressionUtils::True )
1735 {
1736 QVariant vRes = cond->mThenExp->eval( parent, context );
1738 return vRes;
1739 }
1740 }
1741
1742 if ( mElseExp )
1743 {
1744 QVariant vElse = mElseExp->eval( parent, context );
1746 return vElse;
1747 }
1748
1749 // return NULL if no condition is matching
1750 return QVariant();
1751}
1752
1754{
1755 bool foundAnyNonStaticConditions = false;
1756 for ( WhenThen *cond : std::as_const( mConditions ) )
1757 {
1758 const bool res = cond->mWhenExp->prepare( parent, context )
1759 && cond->mThenExp->prepare( parent, context );
1760 if ( !res )
1761 return false;
1762
1763 foundAnyNonStaticConditions |= !cond->mWhenExp->hasCachedStaticValue();
1764 if ( !foundAnyNonStaticConditions && QgsExpressionUtils::getTVLValue( cond->mWhenExp->cachedStaticValue(), parent ) == QgsExpressionUtils::True )
1765 {
1766 // 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
1767 // value, and the static value for this WHEN clause is True.
1768 if ( cond->mThenExp->hasCachedStaticValue() )
1769 {
1770 // then "THEN" clause ALSO has a static value, so we can replace the whole node with a static value
1771 mCachedStaticValue = cond->mThenExp->cachedStaticValue();
1772 mHasCachedValue = true;
1773 return true;
1774 }
1775 else
1776 {
1777 // 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
1778 // this whole QgsExpressionNodeCondition node with just the THEN node for this condition.
1779 mCompiledSimplifiedNode.reset( cond->mThenExp->effectiveNode()->clone() );
1780 return true;
1781 }
1782 }
1783 }
1784
1785 if ( mElseExp )
1786 {
1787 const bool res = mElseExp->prepare( parent, context );
1788 if ( !res )
1789 return false;
1790
1791 if ( !foundAnyNonStaticConditions )
1792 {
1793 // all condition nodes are static conditions and not TRUE, so we know we'll ALWAYS be picking the ELSE node
1794 if ( mElseExp->hasCachedStaticValue() )
1795 {
1796 mCachedStaticValue = mElseExp->cachedStaticValue();
1797 mHasCachedValue = true;
1798 return true;
1799 }
1800 else
1801 {
1802 // so even though the ELSE node is non-static we can effectively replace
1803 // this whole QgsExpressionNodeCondition node with just the ELSE node for this condition.
1804 mCompiledSimplifiedNode.reset( mElseExp->effectiveNode()->clone() );
1805 return true;
1806 }
1807 }
1808 }
1809
1810 return true;
1811}
1812
1814{
1815 QString msg( QStringLiteral( "CASE" ) );
1816 for ( WhenThen *cond : mConditions )
1817 {
1818 msg += QStringLiteral( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
1819 }
1820 if ( mElseExp )
1821 msg += QStringLiteral( " ELSE %1" ).arg( mElseExp->dump() );
1822 msg += QLatin1String( " END" );
1823 return msg;
1824}
1825
1827{
1828 if ( hasCachedStaticValue() )
1829 return QSet< QString >();
1830
1831 QSet<QString> lst;
1832 for ( WhenThen *cond : mConditions )
1833 {
1834 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
1835 }
1836
1837 if ( mElseExp )
1838 lst += mElseExp->referencedColumns();
1839
1840 return lst;
1841}
1842
1844{
1845 QSet<QString> lst;
1846 for ( WhenThen *cond : mConditions )
1847 {
1848 lst += cond->mWhenExp->referencedVariables() + cond->mThenExp->referencedVariables();
1849 }
1850
1851 if ( mElseExp )
1852 lst += mElseExp->referencedVariables();
1853
1854 return lst;
1855}
1856
1858{
1859 QSet<QString> lst;
1860 for ( WhenThen *cond : mConditions )
1861 {
1862 lst += cond->mWhenExp->referencedFunctions() + cond->mThenExp->referencedFunctions();
1863 }
1864
1865 if ( mElseExp )
1866 lst += mElseExp->referencedFunctions();
1867
1868 return lst;
1869}
1870
1871QList<const QgsExpressionNode *> QgsExpressionNodeCondition::nodes() const
1872{
1873 QList<const QgsExpressionNode *> lst;
1874 lst << this;
1875 for ( WhenThen *cond : mConditions )
1876 {
1877 lst += cond->mWhenExp->nodes() + cond->mThenExp->nodes();
1878 }
1879
1880 if ( mElseExp )
1881 lst += mElseExp->nodes();
1882
1883 return lst;
1884}
1885
1887{
1888 for ( WhenThen *cond : mConditions )
1889 {
1890 if ( cond->mWhenExp->needsGeometry() ||
1891 cond->mThenExp->needsGeometry() )
1892 return true;
1893 }
1894
1895 return mElseExp && mElseExp->needsGeometry();
1896}
1897
1899{
1901 conditions.reserve( mConditions.size() );
1902 for ( WhenThen *wt : mConditions )
1903 conditions.append( wt->clone() );
1904
1905 QgsExpressionNodeCondition *copy = new QgsExpressionNodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
1906 cloneTo( copy );
1907 return copy;
1908}
1909
1911{
1912 for ( WhenThen *wt : mConditions )
1913 {
1914 if ( !wt->mWhenExp->isStatic( parent, context ) || !wt->mThenExp->isStatic( parent, context ) )
1915 return false;
1916 }
1917
1918 if ( mElseExp )
1919 return mElseExp->isStatic( parent, context );
1920
1921 return true;
1922}
1923
1925{
1926 if ( hasCachedStaticValue() )
1927 return QSet< QString >();
1928
1929 QSet<QString> lst( mNode->referencedColumns() );
1930 const QList< QgsExpressionNode * > nodeList = mList->list();
1931 for ( const QgsExpressionNode *n : nodeList )
1932 lst.unite( n->referencedColumns() );
1933 return lst;
1934}
1935
1937{
1938 QSet<QString> lst( mNode->referencedVariables() );
1939 const QList< QgsExpressionNode * > nodeList = mList->list();
1940 for ( const QgsExpressionNode *n : nodeList )
1941 lst.unite( n->referencedVariables() );
1942 return lst;
1943}
1944
1946{
1947 QSet<QString> lst( mNode->referencedFunctions() );
1948 const QList< QgsExpressionNode * > nodeList = mList->list();
1949 for ( const QgsExpressionNode *n : nodeList )
1950 lst.unite( n->referencedFunctions() );
1951 return lst;
1952}
1953
1954QList<const QgsExpressionNode *> QgsExpressionNodeInOperator::nodes() const
1955{
1956 QList<const QgsExpressionNode *> lst;
1957 lst << this;
1958 const QList< QgsExpressionNode * > nodeList = mList->list();
1959 for ( const QgsExpressionNode *n : nodeList )
1960 lst += n->nodes();
1961 return lst;
1962}
1963
1964
1968
1973
1975{
1976 bool res = mNode->prepare( parent, context );
1977 res = res && mLowerBound->prepare( parent, context );
1978 res = res && mHigherBound->prepare( parent, context );
1979 return res;
1980}
1981
1983{
1984 const QVariant nodeVal = mNode->eval( parent, context );
1985 if ( QgsVariantUtils::isNull( nodeVal ) )
1986 {
1987 return QVariant();
1988 }
1989
1990 const QgsExpressionNodeLiteral nodeValNode { nodeVal };
1991
1993 const QVariant lowBoundValue = lowBound.eval( parent, context );
1994 const bool lowBoundBool { lowBoundValue.toBool() };
1995
1996 if ( ! QgsVariantUtils::isNull( lowBoundValue ) && ! lowBoundBool )
1997 {
1998 return QVariant( mNegate );
1999 }
2000
2001 QgsExpressionNodeBinaryOperator highBound { QgsExpressionNodeBinaryOperator::BinaryOperator::boLE, nodeValNode.clone(), mHigherBound->clone() };
2002 const QVariant highBoundValue = highBound.eval( parent, context );
2003
2004 if ( QgsVariantUtils::isNull( lowBoundValue ) && QgsVariantUtils::isNull( highBoundValue ) )
2005 {
2006 return QVariant();
2007 }
2008
2009 const bool highBoundBool { highBoundValue.toBool() };
2010
2011 // We already checked if both are nulls
2012 if ( QgsVariantUtils::isNull( lowBoundValue ) || QgsVariantUtils::isNull( highBoundValue ) )
2013 {
2014
2015 // In this case we can return a boolean
2016 if ( ( QgsVariantUtils::isNull( lowBoundValue ) && ! highBoundBool ) ||
2017 ( QgsVariantUtils::isNull( highBoundValue ) && ! lowBoundBool ) )
2018 {
2019 return QVariant( mNegate );
2020 }
2021
2022 // Indetermined
2023 return QVariant();
2024
2025 }
2026
2027 if ( ! QgsVariantUtils::isNull( highBoundValue ) && ! highBoundBool )
2028 {
2029 return QVariant( mNegate );
2030 }
2031
2032 const bool res { lowBoundBool &&highBoundBool };
2033 return mNegate ? QVariant( ! res ) : QVariant( res );
2034
2035}
2036
2038{
2039 return QStringLiteral( "%1 %2 %3 AND %4" ).arg( mNode->dump(), mNegate ? QStringLiteral( "NOT BETWEEN" ) : QStringLiteral( "BETWEEN" ), mLowerBound->dump(), mHigherBound->dump() );
2040}
2041
2043{
2044 QSet<QString> lst( mNode->referencedVariables() );
2045 lst.unite( mLowerBound->referencedVariables() );
2046 lst.unite( mHigherBound->referencedVariables() );
2047 return lst;
2048}
2049
2051{
2052 QSet<QString> lst( mNode->referencedFunctions() );
2053 lst.unite( mLowerBound->referencedFunctions() );
2054 lst.unite( mHigherBound->referencedFunctions() );
2055 return lst;
2056}
2057
2058QList<const QgsExpressionNode *> QgsExpressionNodeBetweenOperator::nodes() const
2059{
2060 return { this, mLowerBound.get(), mHigherBound.get() };
2061}
2062
2064{
2065 QSet<QString> lst( mNode->referencedColumns() );
2066 lst.unite( mLowerBound->referencedColumns() );
2067 lst.unite( mHigherBound->referencedColumns() );
2068 return lst;
2069}
2070
2072{
2073 if ( mNode->needsGeometry() )
2074 return true;
2075
2076 if ( mLowerBound->needsGeometry() )
2077 return true;
2078
2079 if ( mHigherBound->needsGeometry() )
2080 return true;
2081
2082 return false;
2083}
2084
2086{
2087 QgsExpressionNodeBetweenOperator *copy = new QgsExpressionNodeBetweenOperator( mNode->clone(), mLowerBound->clone(), mHigherBound->clone(), mNegate );
2088 cloneTo( copy );
2089 return copy;
2090}
2091
2093{
2094 if ( !mNode->isStatic( parent, context ) )
2095 return false;
2096
2097 if ( !mLowerBound->isStatic( parent, context ) )
2098 return false;
2099
2100 if ( !mHigherBound->isStatic( parent, context ) )
2101 return false;
2102
2103 return true;
2104}
2105
2107{
2108 return mLowerBound.get();
2109}
2110
2112{
2113 return mHigherBound.get();
2114}
2115
2117{
2118 return mNegate;
2119}
2120
2122 : mWhenExp( whenExp )
2123 , mThenExp( thenExp )
2124{
2125}
2126
2132
2134{
2135 return new WhenThen( mWhenExp->clone(), mThenExp->clone() );
2136}
2137
2139{
2140 return BINARY_OPERATOR_TEXT[mOp];
2141}
2142
2143//
2144
2146{
2147 const QVariant container = mContainer->eval( parent, context );
2149 const QVariant index = mIndex->eval( parent, context );
2151
2152 switch ( container.userType() )
2153 {
2154 case QMetaType::Type::QVariantMap:
2155 return QgsExpressionUtils::getMapValue( container, parent ).value( index.toString() );
2156
2157 case QMetaType::Type::QVariantList:
2158 case QMetaType::Type::QStringList:
2159 {
2160 const QVariantList list = QgsExpressionUtils::getListValue( container, parent );
2161 qlonglong pos = QgsExpressionUtils::getIntValue( index, parent );
2162 if ( pos >= list.length() || pos < -list.length() )
2163 {
2164 return QVariant();
2165 }
2166 if ( pos < 0 )
2167 {
2168 // negative indices are from back of list
2169 pos += list.length();
2170 }
2171
2172 return list.at( pos );
2173 }
2174
2175 default:
2176 if ( !QgsVariantUtils::isNull( container ) )
2177 parent->setEvalErrorString( tr( "[] can only be used with map or array values, not %1" ).arg( QMetaType::typeName( static_cast<QMetaType::Type>( container.userType() ) ) ) );
2178 return QVariant();
2179 }
2180}
2181
2186
2188{
2189 bool resC = mContainer->prepare( parent, context );
2190 bool resV = mIndex->prepare( parent, context );
2191 return resC && resV;
2192}
2193
2195{
2196 return QStringLiteral( "%1[%2]" ).arg( mContainer->dump(), mIndex->dump() );
2197}
2198
2200{
2201 if ( hasCachedStaticValue() )
2202 return QSet< QString >();
2203
2204 return mContainer->referencedColumns() + mIndex->referencedColumns();
2205}
2206
2208{
2209 return mContainer->referencedVariables() + mIndex->referencedVariables();
2210}
2211
2213{
2214 return mContainer->referencedFunctions() + mIndex->referencedFunctions();
2215}
2216
2217QList<const QgsExpressionNode *> QgsExpressionNodeIndexOperator::nodes() const
2218{
2219 QList<const QgsExpressionNode *> lst;
2220 lst << this;
2221 lst += mContainer->nodes() + mIndex->nodes();
2222 return lst;
2223}
2224
2226{
2227 return mContainer->needsGeometry() || mIndex->needsGeometry();
2228}
2229
2231{
2232 QgsExpressionNodeIndexOperator *copy = new QgsExpressionNodeIndexOperator( mContainer->clone(), mIndex->clone() );
2233 cloneTo( copy );
2234 return copy;
2235}
2236
2238{
2239 return mContainer->isStatic( parent, context ) && mIndex->isStatic( parent, context );
2240}
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.
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 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.
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.
An indexing expression operator, which allows use of square brackets [] to reference map and array it...
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.
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.
QVariant eval(QgsExpression *parent, const QgsExpressionContext *context)
Evaluate this node with the given context and parent.
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.
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 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.
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: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.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6219
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6302
#define ENSURE_NO_EVAL_ERROR
#define SET_EVAL_ERROR(x)
QgsExpressionNode * node
Node.