Skip to content

Commit 11b2683

Browse files
committed
Thread safety for get_feature
1 parent 62a56b1 commit 11b2683

File tree

5 files changed

+59
-5
lines changed

5 files changed

+59
-5
lines changed

python/core/auto_generated/qgsvectorlayerfeatureiterator.sip.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ this source.
5252
Returns the coordinate reference system for features retrieved from this source.
5353

5454
.. versionadded:: 3.0
55+
%End
56+
57+
QString id() const;
58+
%Docstring
59+
Returns the layer id of the source layer.
60+
61+
.. versionadded:: 3.4
5562
%End
5663

5764
protected:
@@ -63,6 +70,7 @@ Returns the coordinate reference system for features retrieved from this source.
6370

6471

6572

73+
6674
};
6775

6876

src/core/expression/qgsexpressionfunction.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "qgscolorramp.h"
4444
#include "qgsfieldformatterregistry.h"
4545
#include "qgsfieldformatter.h"
46+
#include "qgsvectorlayerfeatureiterator.h"
4647

4748
const QString QgsExpressionFunction::helpText() const
4849
{
@@ -3582,24 +3583,25 @@ static QVariant fcnGetFeatureById( const QVariantList &values, const QgsExpressi
35823583
static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
35833584
{
35843585
//arguments: 1. layer id / name, 2. key attribute, 3. eq value
3585-
QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
3586+
3587+
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource = QgsExpressionUtils::getFeatureSource( values.at( 0 ), parent );
35863588

35873589
//no layer found
3588-
if ( !vl )
3590+
if ( !featureSource )
35893591
{
35903592
return QVariant();
35913593
}
35923594

35933595
QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
3594-
int attributeId = vl->fields().lookupField( attribute );
3596+
int attributeId = featureSource->fields().lookupField( attribute );
35953597
if ( attributeId == -1 )
35963598
{
35973599
return QVariant();
35983600
}
35993601

36003602
const QVariant &attVal = values.at( 2 );
36013603

3602-
const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( vl->id(), QString::number( attributeId ), attVal.toString() );
3604+
const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( featureSource->id(), QString::number( attributeId ), attVal.toString() );
36033605
if ( context && context->hasCachedValue( cacheValueKey ) )
36043606
{
36053607
return context->cachedValue( cacheValueKey );
@@ -3613,7 +3615,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
36133615
{
36143616
req.setFlags( QgsFeatureRequest::NoGeometry );
36153617
}
3616-
QgsFeatureIterator fIt = vl->getFeatures( req );
3618+
QgsFeatureIterator fIt = featureSource->getFeatures( req );
36173619

36183620
QgsFeature fet;
36193621
QVariant res;

src/core/expression/qgsexpressionutils.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "qgsexpression.h"
2424
#include "qgscolorramp.h"
2525
#include "qgsvectorlayer.h"
26+
#include "qgsvectorlayerfeatureiterator.h"
2627
#include "qgsrasterlayer.h"
2728
#include "qgsproject.h"
2829
#include "qgsrelationmanager.h"
@@ -351,6 +352,34 @@ class QgsExpressionUtils
351352
return ml;
352353
}
353354

355+
static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, QgsExpression *e )
356+
{
357+
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
358+
359+
auto getFeatureSource = [ &value, e, &featureSource ]
360+
{
361+
QgsVectorLayer *layer = getVectorLayer( value, e );
362+
363+
if ( layer )
364+
{
365+
featureSource.reset( new QgsVectorLayerFeatureSource( layer ) );
366+
}
367+
};
368+
369+
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
370+
// Make sure we only deal with the vector layer on the main thread where it lives.
371+
// Anything else risks a crash.
372+
if ( QThread::currentThread() == qApp->thread() )
373+
getFeatureSource();
374+
else
375+
QMetaObject::invokeMethod( qApp, getFeatureSource, Qt::BlockingQueuedConnection );
376+
#else
377+
getFeatureSource();
378+
#endif
379+
380+
return featureSource;
381+
}
382+
354383
static QgsVectorLayer *getVectorLayer( const QVariant &value, QgsExpression *e )
355384
{
356385
return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );

src/core/qgsvectorlayerfeatureiterator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
3232
QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
3333
mProviderFeatureSource = layer->dataProvider()->featureSource();
3434
mFields = layer->fields();
35+
mId = layer->id();
3536

3637
// update layer's join caches if necessary
3738
if ( layer->mJoinBuffer->containsJoins() )
@@ -107,6 +108,11 @@ QgsCoordinateReferenceSystem QgsVectorLayerFeatureSource::crs() const
107108
return mCrs;
108109
}
109110

111+
QString QgsVectorLayerFeatureSource::id() const
112+
{
113+
return mId;
114+
}
115+
110116

111117
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
112118
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )

src/core/qgsvectorlayerfeatureiterator.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
7878
*/
7979
QgsCoordinateReferenceSystem crs() const;
8080

81+
/**
82+
* Returns the layer id of the source layer.
83+
*
84+
* \since QGIS 3.4
85+
*/
86+
QString id() const;
87+
8188
protected:
8289

8390
QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
@@ -88,6 +95,8 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
8895

8996
QgsFields mFields;
9097

98+
QString mId;
99+
91100
QgsExpressionContextScope mLayerScope;
92101

93102
bool mHasEditBuffer;

0 commit comments

Comments
 (0)