Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expressions: let concat handle NULL like empty string (like in postgres) #2118

Merged
merged 1 commit into from
Jun 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions python/core/qgsexpression.sip
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,14 @@ class QgsExpression
class Function
{
public:
Function( const QString& fnname, int params, const QString& group, const QString& helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false );
Function( const QString& fnname,
int params,
QString group,
QString helpText = QString(),
bool usesGeometry = false,
QStringList referencedColumns = QStringList(),
bool lazyEval = false,
bool handlesNull = false );

virtual ~Function();

Expand Down Expand Up @@ -225,11 +232,11 @@ class QgsExpression
const QString helptext();

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

virtual bool handlesNull() const;
};

static const QList<QgsExpression::Function *>& Functions();

static const QStringList& BuiltinFunctions();

static bool registerFunction( Function* function );
Expand Down Expand Up @@ -310,6 +317,7 @@ class QgsExpression
public:
NodeList();
~NodeList();
/** Takes ownership of the provided node */
void append( QgsExpression::Node* node /Transfer/ );
int count();
const QList<QgsExpression::Node*>& list();
Expand Down
6 changes: 3 additions & 3 deletions src/core/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1741,7 +1741,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
<< new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
<< new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals" )
<< new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
<< new StaticFunction( "if", 3, fcnIf, "Conditionals", "", False, QStringList(), true )
<< new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
<< new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
Expand All @@ -1763,7 +1763,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
<< new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
<< new StaticFunction( "substr", 3, fcnSubstr, "String" )
<< new StaticFunction( "concat", -1, fcnConcat, "String" )
<< new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
<< new StaticFunction( "strpos", 2, fcnStrpos, "String" )
<< new StaticFunction( "left", 2, fcnLeft, "String" )
<< new StaticFunction( "right", 2, fcnRight, "String" )
Expand Down Expand Up @@ -2638,7 +2638,7 @@ QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, const QgsFeat
{
v = n->eval( parent, f );
ENSURE_NO_EVAL_ERROR;
if ( isNull( v ) && fd->name() != "coalesce" )
if ( isNull( v ) && !fd->handlesNull() )
return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
}
argValues.append( v );
Expand Down
38 changes: 34 additions & 4 deletions src/core/qgsexpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,23 @@ class CORE_EXPORT QgsExpression
class CORE_EXPORT Function
{
public:
Function( const QString& fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
: mName( fnname ), mParams( params ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ), mReferencedColumns( referencedColumns ), mLazyEval( lazyEval ) {}
Function( const QString& fnname,
int params,
QString group,
QString helpText = QString(),
bool usesGeometry = false,
QStringList referencedColumns = QStringList(),
bool lazyEval = false,
bool handlesNull = false )
: mName( fnname )
, mParams( params )
, mUsesGeometry( usesGeometry )
, mGroup( group )
, mHelpText( helpText )
, mReferencedColumns( referencedColumns )
, mLazyEval( lazyEval )
, mHandlesNull( handlesNull )
{}

virtual ~Function() {}

Expand Down Expand Up @@ -327,6 +342,8 @@ class CORE_EXPORT QgsExpression
return false;
}

virtual bool handlesNull() const { return mHandlesNull; }

private:
QString mName;
int mParams;
Expand All @@ -335,13 +352,26 @@ class CORE_EXPORT QgsExpression
QString mHelpText;
QStringList mReferencedColumns;
bool mLazyEval;
bool mHandlesNull;
};

class StaticFunction : public Function
{
public:
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() )
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns, lazyEval ), mFnc( fcn ), mAliases( aliases ) {}
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(),
bool handlesNull = false )
: Function( fnname, params, group, helpText, usesGeometry, referencedColumns, lazyEval, handlesNull )
, mFnc( fcn )
, mAliases( aliases )
{}

virtual ~StaticFunction() {}

Expand Down
3 changes: 2 additions & 1 deletion tests/src/core/testqgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,8 @@ class TestQgsExpression: public QObject
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis\nsupports many multiline',-5,' ')" << false << QVariant( "university\nof qgis\nsupports\nmany multiline" );
QTest::newRow( "format" ) << "format('%1 %2 %3 %1', 'One', 'Two', 'Three')" << false << QVariant( "One Two Three One" );
QTest::newRow( "concat" ) << "concat('a', 'b', 'c', 'd')" << false << QVariant( "abcd" );
QTest::newRow( "concat single" ) << "concat('a')" << false << QVariant( "a" );
QTest::newRow( "concat function single" ) << "concat('a')" << false << QVariant( "a" );
QTest::newRow( "concat function with NULL" ) << "concat(NULL,'a','b')" << false << QVariant( "ab" );

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