Skip to content
Permalink
Browse files

Add a flag argument to QgsFeatureSink::addFeatures

Flags can be used to control how features are added to the sink.

For now, there's only a single flag available - FastInsert.
When FastInsert is set, faster inserts will be use at the cost
of updating the passed features to reflect changes made at the
provider.

This includes skipping the update of the passed feature IDs
to match the resulting feature IDs for the feature within
the data provider.

Individual sink subclasses may or may not choose to respect
this flag, depending on whether or not skipping this update
represents a significant speed boost for the operation.

QgsVectorLayer always ignores the flag - feature ids are
required for the featureAdded signal to be correctly emitted,
and it's expected that performance critical applications will
add features directly to a data provider instead of
via QgsVectorLayer's edit buffer.
  • Loading branch information
nyalldawson committed Jun 15, 2017
1 parent 7aec4d1 commit fc339f9ac548cdd1d51cd6d59ce9cee3c1b7d7c1
Showing with 210 additions and 141 deletions.
  1. +20 −9 python/core/qgsfeaturesink.sip
  2. +2 −2 python/core/qgsfeaturestore.sip
  3. +1 −1 python/core/qgsvectordataprovider.sip
  4. +2 −2 python/core/qgsvectorfilewriter.sip
  5. +2 −2 python/core/qgsvectorlayer.sip
  6. +2 −2 python/core/qgsvectorlayerexporter.sip
  7. +1 −1 src/core/providers/memory/qgsmemoryprovider.cpp
  8. +1 −1 src/core/providers/memory/qgsmemoryprovider.h
  9. +9 −6 src/core/qgsfeaturesink.cpp
  10. +26 −9 src/core/qgsfeaturesink.h
  11. +3 −3 src/core/qgsfeaturestore.cpp
  12. +2 −2 src/core/qgsfeaturestore.h
  13. +2 −1 src/core/qgsvectordataprovider.cpp
  14. +1 −1 src/core/qgsvectordataprovider.h
  15. +2 −2 src/core/qgsvectorfilewriter.cpp
  16. +2 −2 src/core/qgsvectorfilewriter.h
  17. +2 −2 src/core/qgsvectorlayer.cpp
  18. +2 −2 src/core/qgsvectorlayer.h
  19. +3 −3 src/core/qgsvectorlayerexporter.cpp
  20. +2 −2 src/core/qgsvectorlayerexporter.h
  21. +22 −19 src/providers/db2/qgsdb2provider.cpp
  22. +1 −1 src/providers/db2/qgsdb2provider.h
  23. +3 −3 src/providers/gpx/qgsgpxprovider.cpp
  24. +2 −2 src/providers/gpx/qgsgpxprovider.h
  25. +21 −18 src/providers/mssql/qgsmssqlprovider.cpp
  26. +1 −1 src/providers/mssql/qgsmssqlprovider.h
  27. +4 −4 src/providers/ogr/qgsogrprovider.cpp
  28. +2 −2 src/providers/ogr/qgsogrprovider.h
  29. +23 −20 src/providers/postgres/qgspostgresprovider.cpp
  30. +1 −1 src/providers/postgres/qgspostgresprovider.h
  31. +5 −2 src/providers/spatialite/qgsspatialiteprovider.cpp
  32. +1 −1 src/providers/spatialite/qgsspatialiteprovider.h
  33. +14 −11 src/providers/wfs/qgswfsprovider.cpp
  34. +1 −1 src/providers/wfs/qgswfsprovider.h
  35. +22 −0 tests/src/python/providertestbase.py
@@ -22,33 +22,44 @@ class QgsFeatureSink
%End
public:

enum Flag
{

FastInsert,
};
typedef QFlags<QgsFeatureSink::Flag> Flags;


virtual ~QgsFeatureSink();

virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );
%Docstring
Adds a single ``feature`` to the sink.
Adds a single ``feature`` to the sink. Feature addition behavior is controlled by the specified ``flags``.
.. seealso:: addFeatures()
:return: true in case of success and false in case of failure
:rtype: bool
%End

virtual bool addFeatures( QgsFeatureList &features ) = 0;
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) = 0;
%Docstring
Adds a list of ``features`` to the sink.
Adds a list of ``features`` to the sink. Feature addition behavior is controlled by the specified ``flags``.
.. seealso:: addFeature()
:return: true in case of success and false in case of failure
:rtype: bool
%End

virtual bool addFeatures( QgsFeatureIterator &iterator );
virtual bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = 0 );
%Docstring
Adds all features from the specified ``iterator`` to the sink.
Adds all features from the specified ``iterator`` to the sink. Feature addition behavior is controlled by the specified ``flags``.
:return: true if all features were added successfully, or false if any feature could not be added
:rtype: bool
%End

};

QFlags<QgsFeatureSink::Flag> operator|(QgsFeatureSink::Flag f1, QFlags<QgsFeatureSink::Flag> f2);



class QgsProxyFeatureSink : QgsFeatureSink
{
@@ -73,9 +84,9 @@ class QgsProxyFeatureSink : QgsFeatureSink
%Docstring
Constructs a new QgsProxyFeatureSink which forwards features onto a destination ``sink``.
%End
virtual bool addFeature( QgsFeature &feature );
virtual bool addFeatures( QgsFeatureList &features );
virtual bool addFeatures( QgsFeatureIterator &iterator );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );
virtual bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = 0 );

QgsFeatureSink *destinationSink();
%Docstring
@@ -53,9 +53,9 @@ Constructor
.. seealso:: crs()
%End

virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );

virtual bool addFeatures( QgsFeatureList &features );
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );


int count() const;
@@ -197,7 +197,7 @@ Bitmask of all provider's editing capabilities
\param enumList reference to the list to fill
%End

virtual bool addFeatures( QgsFeatureList &flist /In,Out/ );
virtual bool addFeatures( QgsFeatureList &flist /In,Out/, QgsFeatureSink::Flags flags = 0 );

virtual bool deleteFeatures( const QgsFeatureIds &id );
%Docstring
@@ -522,9 +522,9 @@ Retrieves error message
:rtype: str
%End

virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );

virtual bool addFeatures( QgsFeatureList &features );
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );


bool addFeature( QgsFeature &feature, QgsFeatureRenderer *renderer, QgsUnitTypes::DistanceUnit outputUnit = QgsUnitTypes::DistanceMeters );
@@ -928,7 +928,7 @@ Return the provider type for this layer
:rtype: QgsFeatureIterator
%End

virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );


bool updateFeature( QgsFeature &f );
@@ -1281,7 +1281,7 @@ Delete an attribute field (but does not commit it)
:rtype: bool
%End

virtual bool addFeatures( QgsFeatureList &features );
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );


bool deleteFeature( QgsFeatureId fid );
@@ -114,9 +114,9 @@ class QgsVectorLayerExporter : QgsFeatureSink
:rtype: int
%End

virtual bool addFeatures( QgsFeatureList &features );
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );

virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );


~QgsVectorLayerExporter();
@@ -323,7 +323,7 @@ QgsCoordinateReferenceSystem QgsMemoryProvider::crs() const
}


bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist )
bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags )
{
// whether or not to update the layer extent on the fly as we add features
bool updateExtent = mFeatures.isEmpty() || !mExtent.isEmpty();
@@ -50,7 +50,7 @@ class QgsMemoryProvider : public QgsVectorDataProvider
virtual QgsWkbTypes::Type wkbType() const override;
virtual long featureCount() const override;
virtual QgsFields fields() const override;
virtual bool addFeatures( QgsFeatureList &flist ) override;
virtual bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = 0 ) override;
virtual bool deleteFeatures( const QgsFeatureIds &id ) override;
virtual bool addAttributes( const QList<QgsField> &attributes ) override;
virtual bool renameAttributes( const QgsFieldNameMap &renamedAttributes ) override;
@@ -17,24 +17,27 @@

#include "qgsfeaturestore.h"

bool QgsFeatureSink::addFeature( QgsFeature &feature )
bool QgsFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
{
QgsFeatureList features;
features << feature;
bool result = addFeatures( features );
bool result = addFeatures( features, flags );

// need to update the passed feature reference to the updated copy from the features list
feature = features.at( 0 );
if ( !( flags & FastInsert ) )
{
// need to update the passed feature reference to the updated copy from the features list
feature = features.at( 0 );
}
return result;
}

bool QgsFeatureSink::addFeatures( QgsFeatureIterator &iterator )
bool QgsFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
{
QgsFeature f;
bool result = true;
while ( iterator.nextFeature( f ) )
{
result = result && addFeature( f );
result = result && addFeature( f, flags );
}
return result;
}
@@ -34,30 +34,47 @@ class CORE_EXPORT QgsFeatureSink
{
public:

//! Flags controlling how features are added to a sink.
enum Flag
{

/**
* Use faster inserts, at the cost of updating the passed features to reflect changes made at the provider.
* This includes skipping the update of the passed feature IDs to match the resulting feature IDs for the
* feature within the data provider.
* Individual sink subclasses may or may not choose to respect this flag, depending on whether or not
* skipping this update represents a significant speed boost for the operation.
*/
FastInsert = 1 << 1,
};
Q_DECLARE_FLAGS( Flags, Flag )

virtual ~QgsFeatureSink() = default;

/**
* Adds a single \a feature to the sink.
* Adds a single \a feature to the sink. Feature addition behavior is controlled by the specified \a flags.
* \see addFeatures()
* \returns true in case of success and false in case of failure
*/
virtual bool addFeature( QgsFeature &feature );
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );

/**
* Adds a list of \a features to the sink.
* Adds a list of \a features to the sink. Feature addition behavior is controlled by the specified \a flags.
* \see addFeature()
* \returns true in case of success and false in case of failure
*/
virtual bool addFeatures( QgsFeatureList &features ) = 0;
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) = 0;

/**
* Adds all features from the specified \a iterator to the sink.
* Adds all features from the specified \a iterator to the sink. Feature addition behavior is controlled by the specified \a flags.
* \returns true if all features were added successfully, or false if any feature could not be added
*/
virtual bool addFeatures( QgsFeatureIterator &iterator );
virtual bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = 0 );

};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsFeatureSink::Flags )


/**
* \class QgsProxyFeatureSink
@@ -80,9 +97,9 @@ class CORE_EXPORT QgsProxyFeatureSink : public QgsFeatureSink
* Constructs a new QgsProxyFeatureSink which forwards features onto a destination \a sink.
*/
QgsProxyFeatureSink( QgsFeatureSink *sink );
bool addFeature( QgsFeature &feature ) override { return mSink->addFeature( feature ); }
bool addFeatures( QgsFeatureList &features ) override { return mSink->addFeatures( features ); }
bool addFeatures( QgsFeatureIterator &iterator ) override { return mSink->addFeatures( iterator ); }
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ) override { return mSink->addFeature( feature, flags ); }
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) override { return mSink->addFeatures( features, flags ); }
bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = 0 ) override { return mSink->addFeatures( iterator, flags ); }

/**
* Returns the destination QgsFeatureSink which the proxy will forward features to.
@@ -35,20 +35,20 @@ void QgsFeatureStore::setFields( const QgsFields &fields )
}
}

bool QgsFeatureStore::addFeature( QgsFeature &feature )
bool QgsFeatureStore::addFeature( QgsFeature &feature, Flags )
{
QgsFeature f( feature );
f.setFields( mFields );
mFeatures.append( f );
return true;
}

bool QgsFeatureStore::addFeatures( QgsFeatureList &features )
bool QgsFeatureStore::addFeatures( QgsFeatureList &features, Flags flags )
{
QgsFeatureList::iterator fIt = features.begin();
for ( ; fIt != features.end(); ++fIt )
{
addFeature( *fIt );
addFeature( *fIt, flags );
}
return true;
}
@@ -61,8 +61,8 @@ class CORE_EXPORT QgsFeatureStore : public QgsFeatureSink
*/
void setCrs( const QgsCoordinateReferenceSystem &crs ) { mCrs = crs; }

bool addFeature( QgsFeature &feature ) override;
bool addFeatures( QgsFeatureList &features ) override;
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) override;

/**
* Returns the number of features contained in the store.
@@ -62,9 +62,10 @@ QString QgsVectorDataProvider::dataComment() const
return QString();
}

bool QgsVectorDataProvider::addFeatures( QgsFeatureList &flist )
bool QgsVectorDataProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
Q_UNUSED( flist );
Q_UNUSED( flags );
return false;
}

@@ -224,7 +224,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual void enumValues( int index, QStringList &enumList SIP_OUT ) const { Q_UNUSED( index ); enumList.clear(); }

virtual bool addFeatures( QgsFeatureList &flist SIP_INOUT ) override;
virtual bool addFeatures( QgsFeatureList &flist SIP_INOUT, QgsFeatureSink::Flags flags = 0 ) override;

/**
* Deletes one or more features from the provider. This requires the DeleteFeatures capability.
@@ -1836,12 +1836,12 @@ QString QgsVectorFileWriter::errorMessage()
return mErrorMessage;
}

bool QgsVectorFileWriter::addFeature( QgsFeature &feature )
bool QgsVectorFileWriter::addFeature( QgsFeature &feature, Flags )
{
return addFeature( feature, nullptr, QgsUnitTypes::DistanceMeters );
}

bool QgsVectorFileWriter::addFeatures( QgsFeatureList &features )
bool QgsVectorFileWriter::addFeatures( QgsFeatureList &features, Flags )
{
QgsFeatureList::iterator fIt = features.begin();
bool result = true;
@@ -516,8 +516,8 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
//! Retrieves error message
QString errorMessage();

bool addFeature( QgsFeature &feature ) override;
bool addFeatures( QgsFeatureList &features ) override;
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) override;

//! Add feature to the currently opened data source
bool addFeature( QgsFeature &feature, QgsFeatureRenderer *renderer, QgsUnitTypes::DistanceUnit outputUnit = QgsUnitTypes::DistanceMeters );
@@ -940,7 +940,7 @@ QgsFeatureIterator QgsVectorLayer::getFeatures( const QgsFeatureRequest &request
return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
}

bool QgsVectorLayer::addFeature( QgsFeature &feature )
bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
{
if ( !mValid || !mEditBuffer || !mDataProvider )
return false;
@@ -2587,7 +2587,7 @@ QgsFeatureIterator QgsVectorLayer::getSelectedFeatures( QgsFeatureRequest reques
return getFeatures( request );
}

bool QgsVectorLayer::addFeatures( QgsFeatureList &features )
bool QgsVectorLayer::addFeatures( QgsFeatureList &features, Flags )
{
if ( !mEditBuffer || !mDataProvider )
return false;
@@ -900,7 +900,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
return getFeatures( QgsFeatureRequest( rectangle ) );
}

bool addFeature( QgsFeature &feature ) override;
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ) override;

/** Updates an existing feature. This method needs to query the datasource
on every call. Consider using changeAttributeValue() or
@@ -1222,7 +1222,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
bool deleteAttributes( QList<int> attrs );

bool addFeatures( QgsFeatureList &features ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) override;

//! Delete a feature from the layer (but does not commit it)
bool deleteFeature( QgsFeatureId fid );
@@ -142,18 +142,18 @@ QString QgsVectorLayerExporter::errorMessage() const
return mErrorMessage;
}

bool QgsVectorLayerExporter::addFeatures( QgsFeatureList &features )
bool QgsVectorLayerExporter::addFeatures( QgsFeatureList &features, Flags flags )
{
QgsFeatureList::iterator fIt = features.begin();
bool result = true;
for ( ; fIt != features.end(); ++fIt )
{
result = result && addFeature( *fIt );
result = result && addFeature( *fIt, flags );
}
return result;
}

bool QgsVectorLayerExporter::addFeature( QgsFeature &feat )
bool QgsVectorLayerExporter::addFeature( QgsFeature &feat, Flags )
{
QgsAttributes attrs = feat.attributes();

@@ -133,8 +133,8 @@ class CORE_EXPORT QgsVectorLayerExporter : public QgsFeatureSink
*/
int errorCount() const { return mErrorCount; }

bool addFeatures( QgsFeatureList &features ) override;
bool addFeature( QgsFeature &feature ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) override;
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ) override;

/**
* Finalizes the export and closes the new created layer.

0 comments on commit fc339f9

Please sign in to comment.
You can’t perform that action at this time.