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