Thread safety for get_feature

This commit is contained in:
Matthias Kuhn 2018-08-02 16:10:00 +02:00
parent 62a56b195c
commit 11b2683191
No known key found for this signature in database
GPG Key ID: A0E766808764D73F
5 changed files with 59 additions and 5 deletions

View File

@ -52,6 +52,13 @@ this source.
Returns the coordinate reference system for features retrieved from this source. Returns the coordinate reference system for features retrieved from this source.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End
QString id() const;
%Docstring
Returns the layer id of the source layer.
.. versionadded:: 3.4
%End %End
protected: protected:
@ -63,6 +70,7 @@ Returns the coordinate reference system for features retrieved from this source.
}; };

View File

@ -43,6 +43,7 @@
#include "qgscolorramp.h" #include "qgscolorramp.h"
#include "qgsfieldformatterregistry.h" #include "qgsfieldformatterregistry.h"
#include "qgsfieldformatter.h" #include "qgsfieldformatter.h"
#include "qgsvectorlayerfeatureiterator.h"
const QString QgsExpressionFunction::helpText() const const QString QgsExpressionFunction::helpText() const
{ {
@ -3582,16 +3583,17 @@ static QVariant fcnGetFeatureById( const QVariantList &values, const QgsExpressi
static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * ) static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{ {
//arguments: 1. layer id / name, 2. key attribute, 3. eq value //arguments: 1. layer id / name, 2. key attribute, 3. eq value
QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource = QgsExpressionUtils::getFeatureSource( values.at( 0 ), parent );
//no layer found //no layer found
if ( !vl ) if ( !featureSource )
{ {
return QVariant(); return QVariant();
} }
QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent ); QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
int attributeId = vl->fields().lookupField( attribute ); int attributeId = featureSource->fields().lookupField( attribute );
if ( attributeId == -1 ) if ( attributeId == -1 )
{ {
return QVariant(); return QVariant();
@ -3599,7 +3601,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
const QVariant &attVal = values.at( 2 ); const QVariant &attVal = values.at( 2 );
const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( vl->id(), QString::number( attributeId ), attVal.toString() ); const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( featureSource->id(), QString::number( attributeId ), attVal.toString() );
if ( context && context->hasCachedValue( cacheValueKey ) ) if ( context && context->hasCachedValue( cacheValueKey ) )
{ {
return context->cachedValue( cacheValueKey ); return context->cachedValue( cacheValueKey );
@ -3613,7 +3615,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
{ {
req.setFlags( QgsFeatureRequest::NoGeometry ); req.setFlags( QgsFeatureRequest::NoGeometry );
} }
QgsFeatureIterator fIt = vl->getFeatures( req ); QgsFeatureIterator fIt = featureSource->getFeatures( req );
QgsFeature fet; QgsFeature fet;
QVariant res; QVariant res;

View File

@ -23,6 +23,7 @@
#include "qgsexpression.h" #include "qgsexpression.h"
#include "qgscolorramp.h" #include "qgscolorramp.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsvectorlayerfeatureiterator.h"
#include "qgsrasterlayer.h" #include "qgsrasterlayer.h"
#include "qgsproject.h" #include "qgsproject.h"
#include "qgsrelationmanager.h" #include "qgsrelationmanager.h"
@ -351,6 +352,34 @@ class QgsExpressionUtils
return ml; return ml;
} }
static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, QgsExpression *e )
{
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
auto getFeatureSource = [ &value, e, &featureSource ]
{
QgsVectorLayer *layer = getVectorLayer( value, e );
if ( layer )
{
featureSource.reset( new QgsVectorLayerFeatureSource( layer ) );
}
};
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
getFeatureSource();
else
QMetaObject::invokeMethod( qApp, getFeatureSource, Qt::BlockingQueuedConnection );
#else
getFeatureSource();
#endif
return featureSource;
}
static QgsVectorLayer *getVectorLayer( const QVariant &value, QgsExpression *e ) static QgsVectorLayer *getVectorLayer( const QVariant &value, QgsExpression *e )
{ {
return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) ); return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );

View File

@ -32,6 +32,7 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
QMutexLocker locker( &layer->mFeatureSourceConstructorMutex ); QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
mProviderFeatureSource = layer->dataProvider()->featureSource(); mProviderFeatureSource = layer->dataProvider()->featureSource();
mFields = layer->fields(); mFields = layer->fields();
mId = layer->id();
// update layer's join caches if necessary // update layer's join caches if necessary
if ( layer->mJoinBuffer->containsJoins() ) if ( layer->mJoinBuffer->containsJoins() )
@ -107,6 +108,11 @@ QgsCoordinateReferenceSystem QgsVectorLayerFeatureSource::crs() const
return mCrs; return mCrs;
} }
QString QgsVectorLayerFeatureSource::id() const
{
return mId;
}
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request ) QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request ) : QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )

View File

@ -78,6 +78,13 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
*/ */
QgsCoordinateReferenceSystem crs() const; QgsCoordinateReferenceSystem crs() const;
/**
* Returns the layer id of the source layer.
*
* \since QGIS 3.4
*/
QString id() const;
protected: protected:
QgsAbstractFeatureSource *mProviderFeatureSource = nullptr; QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
@ -88,6 +95,8 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
QgsFields mFields; QgsFields mFields;
QString mId;
QgsExpressionContextScope mLayerScope; QgsExpressionContextScope mLayerScope;
bool mHasEditBuffer; bool mHasEditBuffer;