Skip to content

Commit 6e3a1fa

Browse files
committedJun 25, 2015
Merge pull request #2118 from jef-n/postgres-like-concat
expressions: let concat handle NULL like empty string (like in postgres; fixes #1927)
2 parents e6556a2 + 3387d6f commit 6e3a1fa

File tree

4 files changed

+50
-11
lines changed

4 files changed

+50
-11
lines changed
 

‎python/core/qgsexpression.sip

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,14 @@ class QgsExpression
194194
class Function
195195
{
196196
public:
197-
Function( const QString& fnname, int params, const QString& group, const QString& helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false );
197+
Function( const QString& fnname,
198+
int params,
199+
QString group,
200+
QString helpText = QString(),
201+
bool usesGeometry = false,
202+
QStringList referencedColumns = QStringList(),
203+
bool lazyEval = false,
204+
bool handlesNull = false );
198205

199206
virtual ~Function();
200207

@@ -225,11 +232,11 @@ class QgsExpression
225232
const QString helptext();
226233

227234
virtual QVariant func( const QVariantList& values, const QgsFeature* f, QgsExpression* parent ) = 0;
228-
};
229235

236+
virtual bool handlesNull() const;
237+
};
230238

231239
static const QList<QgsExpression::Function *>& Functions();
232-
233240
static const QStringList& BuiltinFunctions();
234241

235242
static bool registerFunction( Function* function );
@@ -310,6 +317,7 @@ class QgsExpression
310317
public:
311318
NodeList();
312319
~NodeList();
320+
/** Takes ownership of the provided node */
313321
void append( QgsExpression::Node* node /Transfer/ );
314322
int count();
315323
const QList<QgsExpression::Node*>& list();

‎src/core/qgsexpression.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
17411741
<< new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
17421742
<< new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
17431743
<< new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
1744-
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals" )
1744+
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
17451745
<< new StaticFunction( "if", 3, fcnIf, "Conditionals", "", False, QStringList(), true )
17461746
<< new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
17471747
<< new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
@@ -1763,7 +1763,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
17631763
<< new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
17641764
<< new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
17651765
<< new StaticFunction( "substr", 3, fcnSubstr, "String" )
1766-
<< new StaticFunction( "concat", -1, fcnConcat, "String" )
1766+
<< new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
17671767
<< new StaticFunction( "strpos", 2, fcnStrpos, "String" )
17681768
<< new StaticFunction( "left", 2, fcnLeft, "String" )
17691769
<< new StaticFunction( "right", 2, fcnRight, "String" )
@@ -2683,7 +2683,7 @@ QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, const QgsFeat
26832683
{
26842684
v = n->eval( parent, f );
26852685
ENSURE_NO_EVAL_ERROR;
2686-
if ( isNull( v ) && fd->name() != "coalesce" )
2686+
if ( isNull( v ) && !fd->handlesNull() )
26872687
return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
26882688
}
26892689
argValues.append( v );

‎src/core/qgsexpression.h

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,23 @@ class CORE_EXPORT QgsExpression
286286
class CORE_EXPORT Function
287287
{
288288
public:
289-
Function( const QString& fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
290-
: mName( fnname ), mParams( params ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ), mReferencedColumns( referencedColumns ), mLazyEval( lazyEval ) {}
289+
Function( const QString& fnname,
290+
int params,
291+
QString group,
292+
QString helpText = QString(),
293+
bool usesGeometry = false,
294+
QStringList referencedColumns = QStringList(),
295+
bool lazyEval = false,
296+
bool handlesNull = false )
297+
: mName( fnname )
298+
, mParams( params )
299+
, mUsesGeometry( usesGeometry )
300+
, mGroup( group )
301+
, mHelpText( helpText )
302+
, mReferencedColumns( referencedColumns )
303+
, mLazyEval( lazyEval )
304+
, mHandlesNull( handlesNull )
305+
{}
291306

292307
virtual ~Function() {}
293308

@@ -327,6 +342,8 @@ class CORE_EXPORT QgsExpression
327342
return false;
328343
}
329344

345+
virtual bool handlesNull() const { return mHandlesNull; }
346+
330347
private:
331348
QString mName;
332349
int mParams;
@@ -335,13 +352,26 @@ class CORE_EXPORT QgsExpression
335352
QString mHelpText;
336353
QStringList mReferencedColumns;
337354
bool mLazyEval;
355+
bool mHandlesNull;
338356
};
339357

340358
class StaticFunction : public Function
341359
{
342360
public:
343-
StaticFunction( QString fnname, int params, FcnEval fcn, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false, const QStringList& aliases = QStringList() )
344-
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns, lazyEval ), mFnc( fcn ), mAliases( aliases ) {}
361+
StaticFunction( QString fnname,
362+
int params,
363+
FcnEval fcn,
364+
QString group,
365+
QString helpText = QString(),
366+
bool usesGeometry = false,
367+
QStringList referencedColumns = QStringList(),
368+
bool lazyEval = false,
369+
const QStringList& aliases = QStringList(),
370+
bool handlesNull = false )
371+
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns, lazyEval, handlesNull )
372+
, mFnc( fcn )
373+
, mAliases( aliases )
374+
{}
345375

346376
virtual ~StaticFunction() {}
347377

‎tests/src/core/testqgsexpression.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ class TestQgsExpression: public QObject
387387
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis\nsupports many multiline',-5,' ')" << false << QVariant( "university\nof qgis\nsupports\nmany multiline" );
388388
QTest::newRow( "format" ) << "format('%1 %2 %3 %1', 'One', 'Two', 'Three')" << false << QVariant( "One Two Three One" );
389389
QTest::newRow( "concat" ) << "concat('a', 'b', 'c', 'd')" << false << QVariant( "abcd" );
390-
QTest::newRow( "concat single" ) << "concat('a')" << false << QVariant( "a" );
390+
QTest::newRow( "concat function single" ) << "concat('a')" << false << QVariant( "a" );
391+
QTest::newRow( "concat function with NULL" ) << "concat(NULL,'a','b')" << false << QVariant( "ab" );
391392

392393
// implicit conversions
393394
QTest::newRow( "implicit int->text" ) << "length(123)" << false << QVariant( 3 );

0 commit comments

Comments
 (0)
Please sign in to comment.