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.
.. versionadded:: 3.0
%End
QString id() const;
%Docstring
Returns the layer id of the source layer.
.. versionadded:: 3.4
%End
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 "qgsfieldformatterregistry.h"
#include "qgsfieldformatter.h"
#include "qgsvectorlayerfeatureiterator.h"
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 * )
{
//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
if ( !vl )
if ( !featureSource )
{
return QVariant();
}
QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
int attributeId = vl->fields().lookupField( attribute );
int attributeId = featureSource->fields().lookupField( attribute );
if ( attributeId == -1 )
{
return QVariant();
@ -3599,7 +3601,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
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 ) )
{
return context->cachedValue( cacheValueKey );
@ -3613,7 +3615,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
{
req.setFlags( QgsFeatureRequest::NoGeometry );
}
QgsFeatureIterator fIt = vl->getFeatures( req );
QgsFeatureIterator fIt = featureSource->getFeatures( req );
QgsFeature fet;
QVariant res;

View File

@ -23,6 +23,7 @@
#include "qgsexpression.h"
#include "qgscolorramp.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerfeatureiterator.h"
#include "qgsrasterlayer.h"
#include "qgsproject.h"
#include "qgsrelationmanager.h"
@ -351,6 +352,34 @@ class QgsExpressionUtils
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 )
{
return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );

View File

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

View File

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