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.
This commit is contained in:
Nyall Dawson 2017-06-15 12:08:43 +10:00
parent 7aec4d1a5f
commit fc339f9ac5
35 changed files with 213 additions and 144 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 );

View File

@ -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 );

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -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.

View File

@ -35,7 +35,7 @@ void QgsFeatureStore::setFields( const QgsFields &fields )
}
}
bool QgsFeatureStore::addFeature( QgsFeature &feature )
bool QgsFeatureStore::addFeature( QgsFeature &feature, Flags )
{
QgsFeature f( feature );
f.setFields( mFields );
@ -43,12 +43,12 @@ bool QgsFeatureStore::addFeature( QgsFeature &feature )
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;
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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.

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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 );

View File

@ -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();

View File

@ -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.

View File

@ -897,7 +897,7 @@ bool QgsDb2Provider::changeAttributeValues( const QgsChangedAttributesMap &attr_
return true;
}
bool QgsDb2Provider::addFeatures( QgsFeatureList &flist )
bool QgsDb2Provider::addFeatures( QgsFeatureList &flist, Flags flags )
{
QgsDebugMsg( "mGeometryColType: " + mGeometryColType );
int writeCount = 0;
@ -1122,31 +1122,34 @@ bool QgsDb2Provider::addFeatures( QgsFeatureList &flist )
}
}
statement = QString( "select IDENTITY_VAL_LOCAL() AS IDENTITY "
"FROM SYSIBM.SYSDUMMY1" );
if ( !( flags & QgsFeatureSink::FastInsert ) )
{
statement = QString( "select IDENTITY_VAL_LOCAL() AS IDENTITY "
"FROM SYSIBM.SYSDUMMY1" );
// QgsDebugMsg( statement );
if ( !queryFid.exec( statement ) )
{
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
if ( !queryFid.exec( statement ) )
{
pushError( msg );
return false;
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
{
pushError( msg );
return false;
}
}
}
if ( !queryFid.next() )
{
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
if ( !queryFid.next() )
{
pushError( msg );
return false;
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
{
pushError( msg );
return false;
}
}
it->setId( queryFid.value( 0 ).toLongLong() );
}
it->setId( queryFid.value( 0 ).toLongLong() );
writeCount++;
// QgsDebugMsg( QString( "count: %1; featureId: %2" ).arg( writeCount ).arg( queryFid.value( 0 ).toLongLong() ) );
}

View File

@ -83,7 +83,7 @@ class QgsDb2Provider : public QgsVectorDataProvider
virtual QgsVectorDataProvider::Capabilities capabilities() 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;

View File

@ -190,14 +190,14 @@ QgsFeatureIterator QgsGPXProvider::getFeatures( const QgsFeatureRequest &request
}
bool QgsGPXProvider::addFeatures( QgsFeatureList &flist )
bool QgsGPXProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
// add all the features
for ( QgsFeatureList::iterator iter = flist.begin();
iter != flist.end(); ++iter )
{
if ( !addFeature( *iter ) )
if ( !addFeature( *iter, flags ) )
return false;
}
@ -211,7 +211,7 @@ bool QgsGPXProvider::addFeatures( QgsFeatureList &flist )
}
bool QgsGPXProvider::addFeature( QgsFeature &f )
bool QgsGPXProvider::addFeature( QgsFeature &f, Flags )
{
QByteArray wkb( f.geometry().exportToWkb() );
const char *geo = wkb.constData();

View File

@ -54,7 +54,7 @@ class QgsGPXProvider : 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 changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
virtual QgsVectorDataProvider::Capabilities capabilities() const override;
@ -75,7 +75,7 @@ class QgsGPXProvider : public QgsVectorDataProvider
void changeAttributeValues( QgsGPSObject &obj,
const QgsAttributeMap &attrs );
bool addFeature( QgsFeature &f ) override;
bool addFeature( QgsFeature &f, QgsFeatureSink::Flags flags = 0 ) override;
enum DataType

View File

@ -818,7 +818,7 @@ bool QgsMssqlProvider::isValid() const
return mValid;
}
bool QgsMssqlProvider::addFeatures( QgsFeatureList &flist )
bool QgsMssqlProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
{
@ -1012,30 +1012,33 @@ bool QgsMssqlProvider::addFeatures( QgsFeatureList &flist )
}
statement = QStringLiteral( "SELECT IDENT_CURRENT('%1.%2')" ).arg( mSchemaName, mTableName );
if ( !query.exec( statement ) )
if ( !( flags & QgsFeatureSink::FastInsert ) )
{
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
{
pushError( msg );
return false;
}
}
statement = QStringLiteral( "SELECT IDENT_CURRENT('%1.%2')" ).arg( mSchemaName, mTableName );
if ( !query.next() )
{
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
if ( !query.exec( statement ) )
{
pushError( msg );
return false;
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
{
pushError( msg );
return false;
}
}
if ( !query.next() )
{
QString msg = query.lastError().text();
QgsDebugMsg( msg );
if ( !mSkipFailures )
{
pushError( msg );
return false;
}
}
it->setId( query.value( 0 ).toLongLong() );
}
it->setId( query.value( 0 ).toLongLong() );
}
return true;

View File

@ -101,7 +101,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider
virtual bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
virtual bool addFeatures( QgsFeatureList &flist ) override;
virtual bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = 0 ) override;
virtual bool deleteFeatures( const QgsFeatureIds &id ) override;

View File

@ -1228,7 +1228,7 @@ OGRGeometryH QgsOgrProvider::ConvertGeometryIfNecessary( OGRGeometryH hGeom )
return OGR_G_ForceTo( hGeom, layerGeomType, nullptr );
}
bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f )
bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags )
{
bool returnValue = true;
OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( ogrLayer );
@ -1357,7 +1357,7 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f )
pushError( tr( "OGR error creating feature %1: %2" ).arg( f.id() ).arg( CPLGetLastErrorMsg() ) );
returnValue = false;
}
else
else if ( !( flags & QgsFeatureSink::FastInsert ) )
{
QgsFeatureId id = static_cast<QgsFeatureId>( OGR_F_GetFID( feature ) );
if ( id >= 0 )
@ -1376,7 +1376,7 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f )
}
bool QgsOgrProvider::addFeatures( QgsFeatureList &flist )
bool QgsOgrProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
if ( !doInitialActionsForEdition() )
return false;
@ -1388,7 +1388,7 @@ bool QgsOgrProvider::addFeatures( QgsFeatureList &flist )
bool returnvalue = true;
for ( QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it )
{
if ( !addFeaturePrivate( *it ) )
if ( !addFeaturePrivate( *it, flags ) )
{
returnvalue = false;
}

View File

@ -78,7 +78,7 @@ class QgsOgrProvider : public QgsVectorDataProvider
virtual QgsRectangle extent() const override;
QVariant defaultValue( int fieldId ) const override;
virtual void updateExtents() 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 deleteAttributes( const QgsAttributeIds &attributes ) override;
@ -225,7 +225,7 @@ class QgsOgrProvider : public QgsVectorDataProvider
mutable QStringList mSubLayerList;
bool addFeaturePrivate( QgsFeature &f );
bool addFeaturePrivate( QgsFeature &f, QgsFeatureSink::Flags flags );
//! Deletes one feature
bool deleteFeature( QgsFeatureId id );

View File

@ -1935,7 +1935,7 @@ QString QgsPostgresProvider::geomParam( int offset ) const
return geometry;
}
bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
if ( flist.isEmpty() )
return true;
@ -2160,33 +2160,36 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
}
}
// update feature ids
if ( mPrimaryKeyType == PktInt || mPrimaryKeyType == PktFidMap || mPrimaryKeyType == PktUint64 )
if ( !( flags & QgsFeatureSink::FastInsert ) )
{
for ( QgsFeatureList::iterator features = flist.begin(); features != flist.end(); ++features )
// update feature ids
if ( mPrimaryKeyType == PktInt || mPrimaryKeyType == PktFidMap || mPrimaryKeyType == PktUint64 )
{
QgsAttributes attrs = features->attributes();
for ( QgsFeatureList::iterator features = flist.begin(); features != flist.end(); ++features )
{
QgsAttributes attrs = features->attributes();
if ( mPrimaryKeyType == PktUint64 )
{
features->setId( STRING_TO_FID( attrs.at( mPrimaryKeyAttrs.at( 0 ) ) ) );
}
else if ( mPrimaryKeyType == PktInt )
{
features->setId( PKINT2FID( STRING_TO_FID( attrs.at( mPrimaryKeyAttrs.at( 0 ) ) ) ) );
}
else
{
QVariantList primaryKeyVals;
Q_FOREACH ( int idx, mPrimaryKeyAttrs )
if ( mPrimaryKeyType == PktUint64 )
{
primaryKeyVals << attrs.at( idx );
features->setId( STRING_TO_FID( attrs.at( mPrimaryKeyAttrs.at( 0 ) ) ) );
}
else if ( mPrimaryKeyType == PktInt )
{
features->setId( PKINT2FID( STRING_TO_FID( attrs.at( mPrimaryKeyAttrs.at( 0 ) ) ) ) );
}
else
{
QVariantList primaryKeyVals;
features->setId( mShared->lookupFid( primaryKeyVals ) );
Q_FOREACH ( int idx, mPrimaryKeyAttrs )
{
primaryKeyVals << attrs.at( idx );
}
features->setId( mShared->lookupFid( primaryKeyVals ) );
}
QgsDebugMsgLevel( QString( "new fid=%1" ).arg( features->id() ), 4 );
}
QgsDebugMsgLevel( QString( "new fid=%1" ).arg( features->id() ), 4 );
}
}

View File

@ -138,7 +138,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
QString defaultValueClause( int fieldId ) const override;
QVariant defaultValue( int fieldId ) const override;
bool skipConstraintCheck( int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value = QVariant() ) const override;
bool addFeatures( QgsFeatureList &flist ) override;
bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = 0 ) override;
bool deleteFeatures( const QgsFeatureIds &id ) override;
bool truncate() override;
bool addAttributes( const QList<QgsField> &attributes ) override;

View File

@ -3829,7 +3829,7 @@ static void deleteWkbBlob( void *wkbBlob )
delete[]( char * )wkbBlob;
}
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist )
bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
sqlite3_stmt *stmt = nullptr;
char *errMsg = nullptr;
@ -3978,7 +3978,10 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist )
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
{
// update feature id
feature->setId( sqlite3_last_insert_rowid( mSqliteHandle ) );
if ( !( flags & QgsFeatureSink::FastInsert ) )
{
feature->setId( sqlite3_last_insert_rowid( mSqliteHandle ) );
}
mNumberFeatures++;
}
else

View File

@ -102,7 +102,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
bool isValid() const override;
virtual bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
bool addFeatures( QgsFeatureList &flist ) override;
bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = 0 ) override;
bool deleteFeatures( const QgsFeatureIds &id ) override;
bool truncate() override;
bool addAttributes( const QList<QgsField> &attributes ) override;

View File

@ -779,7 +779,7 @@ QgsFeatureIterator QgsWFSProvider::getFeatures( const QgsFeatureRequest &request
return QgsFeatureIterator( new QgsWFSFeatureIterator( new QgsWFSFeatureSource( this ), true, request ) );
}
bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
bool QgsWFSProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
//create <Transaction> xml
QDomDocument transactionDoc;
@ -872,17 +872,20 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
}
mShared->serializeFeatures( serializedFeatureList );
// And now set the feature id from the one got from the database
QMap< QString, QgsFeatureId > map;
for ( int idx = 0; idx < serializedFeatureList.size(); idx++ )
map[ serializedFeatureList[idx].second ] = serializedFeatureList[idx].first.id();
idIt = idList.constBegin();
featureIt = flist.begin();
for ( ; idIt != idList.constEnd() && featureIt != flist.end(); ++idIt, ++featureIt )
if ( !( flags & QgsFeatureSink::FastInsert ) )
{
if ( map.find( *idIt ) != map.end() )
featureIt->setId( map[*idIt] );
// And now set the feature id from the one got from the database
QMap< QString, QgsFeatureId > map;
for ( int idx = 0; idx < serializedFeatureList.size(); idx++ )
map[ serializedFeatureList[idx].second ] = serializedFeatureList[idx].first.id();
idIt = idList.constBegin();
featureIt = flist.begin();
for ( ; idIt != idList.constEnd() && featureIt != flist.end(); ++idIt, ++featureIt )
{
if ( map.find( *idIt ) != map.end() )
featureIt->setId( map[*idIt] );
}
}
return true;

View File

@ -102,7 +102,7 @@ class QgsWFSProvider : public QgsVectorDataProvider
//Editing operations
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 changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;

View File

@ -25,6 +25,7 @@ from qgis.core import (
QgsExpressionContext,
QgsVectorDataProvider,
QgsVectorLayerFeatureSource,
QgsFeatureSink,
NULL
)
@ -361,6 +362,27 @@ class ProviderTestCase(FeatureSourceTestCase):
# expect fail
self.assertFalse(l.dataProvider().addFeatures([f1, f2]), 'Provider reported no AddFeatures capability, but returned true to addFeatures')
def testAddFeatureFastInsert(self):
if not getattr(self, 'getEditableLayer', None):
return
l = self.getEditableLayer()
self.assertTrue(l.isValid())
f1 = QgsFeature()
f1.setAttributes([6, -220, NULL, 'String', '15'])
f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))
f2 = QgsFeature()
f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13'])
if l.dataProvider().capabilities() & QgsVectorDataProvider.AddFeatures:
# expect success
result, added = l.dataProvider().addFeatures([f1, f2], QgsFeatureSink.FastInsert)
self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures')
self.assertEqual(l.dataProvider().featureCount(),7)
def testAddFeaturesUpdateExtent(self):
if not getattr(self, 'getEditableLayer', None):
return