[API] Introduce optional QgsVectorDataProvider::ChangeFeatures

capability and changeFeaturss method to allows joint geometry and
attribute updates.

Currently only implemented in the postgres provider
This commit is contained in:
Juergen E. Fischer 2016-01-15 10:10:58 +01:00
parent c063838f52
commit ad1fd2a922
18 changed files with 321 additions and 81 deletions

View File

@ -39,6 +39,7 @@ class QgsVectorDataProvider : QgsDataProvider
RandomSelectGeometryAtId,
/** DEPRECATED - do not use */
SequentialSelectGeometryAtId,
/** DEPRECATED - do not use */
CreateAttributeIndex,
/** Allows user to select encoding */
SelectEncoding,
@ -47,7 +48,13 @@ class QgsVectorDataProvider : QgsDataProvider
/** Supports topological simplification of geometries on provider side according to a distance tolerance */
SimplifyGeometriesWithTopologicalValidation,
/** Supports transactions*/
TransactionSupport
TransactionSupport,
/** Supports circular geometry types (circularstring, compoundcurve, curvepolygon)*/
CircularGeometries,
/** Supports joint updates for attributes and geometry
* Providers supporting this should still define ChangeGeometries | ChangeAttributeValues
*/
ChangeFeatures
};
/** Bitmask of all provider's editing capabilities */
@ -189,6 +196,17 @@ class QgsVectorDataProvider : QgsDataProvider
*/
virtual bool changeAttributeValues( const QMap<qint64, QMap<int, QVariant> > &attr_map );
/**
* Changes attribute values and geometries of existing features.
* @param attr_map a map containing changed attributes
* @param geometry_map A QgsGeometryMap whose index contains the feature IDs
* that will have their geometries changed.
* The second map parameter being the new geometries themselves
* @return true in case of success and false in case of failure
*/
virtual bool changeFeatures( const QMap<qint64, QMap<int, QVariant> > &attr_map,
const QMap<qint64, QgsGeometry> &geometry_map );
/**
* Returns the default value for field specified by @c fieldId
*/
@ -201,7 +219,7 @@ class QgsVectorDataProvider : QgsDataProvider
* The second map parameter being the new geometries themselves
* @return True in case of success and false in case of failure
*/
virtual bool changeGeometryValues( QMap<qint64, QgsGeometry> & geometry_map );
virtual bool changeGeometryValues( const QMap<qint64, QgsGeometry> &geometry_map );
/**
* Creates a spatial index on the datasource (if supported by the provider type).
@ -320,6 +338,13 @@ class QgsVectorDataProvider : QgsDataProvider
*/
virtual QgsTransaction* transaction() const;
/**
* Forces a reload of the underlying datasource if the provider implements this
* method.
* In particular on the OGR provider, a pooled connection will be invalidated.
* This forces QGIS to reopen a file or connection.
* This can be required if the underlying file is replaced.
*/
virtual void forceReload();
/**

View File

@ -87,12 +87,20 @@ QVariant QgsVectorDataProvider::defaultValue( int fieldId )
return QVariant();
}
bool QgsVectorDataProvider::changeGeometryValues( QgsGeometryMap &geometry_map )
bool QgsVectorDataProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
Q_UNUSED( geometry_map );
return false;
}
bool QgsVectorDataProvider::changeFeatures( const QgsChangedAttributesMap &attr_map,
const QgsGeometryMap &geometry_map )
{
Q_UNUSED( attr_map );
Q_UNUSED( geometry_map );
return false;
}
bool QgsVectorDataProvider::createSpatialIndex()
{
return false;
@ -206,8 +214,13 @@ QString QgsVectorDataProvider::capabilitiesString() const
QgsDebugMsg( "Capability: Simplify Geometries before fetch the feature ensuring that the result is a valid geometry" );
}
return abilitiesList.join( ", " );
if ( abilities & QgsVectorDataProvider::ChangeFeatures )
{
abilitiesList += tr( "Change Geometries and Attributes at once" );
QgsDebugMsg( "Capability: change attributes and geometries at once" );
}
return abilitiesList.join( ", " );
}

View File

@ -61,42 +61,47 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
enum Capability
{
/** Provider has no capabilities */
NoCapabilities = 0,
NoCapabilities = 0,
/** Allows adding features */
AddFeatures = 1,
AddFeatures = 1,
/** Allows deletion of features */
DeleteFeatures = 1 << 1,
DeleteFeatures = 1 << 1,
/** Allows modification of attribute values */
ChangeAttributeValues = 1 << 2,
ChangeAttributeValues = 1 << 2,
/** Allows addition of new attributes (fields) */
AddAttributes = 1 << 3,
AddAttributes = 1 << 3,
/** Allows deletion of attributes (fields) */
DeleteAttributes = 1 << 4,
DeleteAttributes = 1 << 4,
/** DEPRECATED - do not use */
SaveAsShapefile = 1 << 5,
SaveAsShapefile = 1 << 5,
/** Allows creation of spatial index */
CreateSpatialIndex = 1 << 6,
CreateSpatialIndex = 1 << 6,
/** Fast access to features using their ID */
SelectAtId = 1 << 7,
SelectAtId = 1 << 7,
/** Allows modifications of geometries */
ChangeGeometries = 1 << 8,
ChangeGeometries = 1 << 8,
/** DEPRECATED - do not use */
SelectGeometryAtId = 1 << 9,
SelectGeometryAtId = 1 << 9,
/** DEPRECATED - do not use */
RandomSelectGeometryAtId = 1 << 10,
RandomSelectGeometryAtId = 1 << 10,
/** DEPRECATED - do not use */
SequentialSelectGeometryAtId = 1 << 11,
CreateAttributeIndex = 1 << 12,
SequentialSelectGeometryAtId = 1 << 11,
/** DEPRECATED - do not use */
CreateAttributeIndex = 1 << 12,
/** Allows user to select encoding */
SelectEncoding = 1 << 13,
SelectEncoding = 1 << 13,
/** Supports simplification of geometries on provider side according to a distance tolerance */
SimplifyGeometries = 1 << 14,
SimplifyGeometries = 1 << 14,
/** Supports topological simplification of geometries on provider side according to a distance tolerance */
SimplifyGeometriesWithTopologicalValidation = 1 << 15,
/** Supports transactions*/
TransactionSupport = 1 << 16,
TransactionSupport = 1 << 16,
/** Supports circular geometry types (circularstring, compoundcurve, curvepolygon)*/
CircularGeometries = 1 << 17
CircularGeometries = 1 << 17,
/** Supports joint updates for attributes and geometry
* Providers supporting this should still define ChangeGeometries | ChangeAttributeValues
*/
ChangeFeatures = 1 << 18
};
/** Bitmask of all provider's editing capabilities */
@ -239,6 +244,16 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
*/
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map );
/**
* Changes attribute values and geometries of existing features.
* @param attr_map a map containing changed attributes
* @param geometry_map A QgsGeometryMap whose index contains the feature IDs
* that will have their geometries changed.
* The second map parameter being the new geometries themselves
* @return true in case of success and false in case of failure
*/
virtual bool changeFeatures( const QgsChangedAttributesMap &attr_map, const QgsGeometryMap &geometry_map );
/**
* Returns the default value for field specified by @c fieldId
*/
@ -251,7 +266,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
* The second map parameter being the new geometries themselves
* @return True in case of success and false in case of failure
*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map );
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map );
/**
* Creates a spatial index on the datasource (if supported by the provider type).

View File

@ -271,17 +271,21 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
int cap = provider->capabilities();
bool success = true;
// geometry updates attribute updates
// yes no => changeGeometryValues
// no yes => changeAttributeValues
// yes yes => changeFeatures
//
// update geometries
//
if ( !mChangedGeometries.isEmpty() )
if ( !mChangedGeometries.isEmpty() && (( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedAttributeValues.isEmpty() ) )
{
if (( cap & QgsVectorDataProvider::ChangeGeometries ) && provider->changeGeometryValues( mChangedGeometries ) )
if ( provider->changeGeometryValues( mChangedGeometries ) )
{
commitErrors << tr( "SUCCESS: %n geometries were changed.", "changed geometries count", mChangedGeometries.size() );
emit committedGeometriesChanges( L->id(), mChangedGeometries );
mChangedGeometries.clear();
}
else
@ -398,38 +402,58 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors )
if ( attributeChangesOk )
{
//
// change attributes
//
if ( !mChangedAttributeValues.isEmpty() )
if ( cap & QgsVectorDataProvider::ChangeFeatures && !mChangedGeometries.isEmpty() && !mChangedAttributeValues.isEmpty() )
{
if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && provider->changeAttributeValues( mChangedAttributeValues ) )
Q_ASSERT(( cap & ( QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries ) ) == ( QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries ) );
if ( provider->changeFeatures( mChangedAttributeValues, mChangedGeometries ) )
{
commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
commitErrors << tr( "SUCCESS: %1 attribute value(s) and %2 geometries changed." ).arg( mChangedAttributeValues.size(), mChangedGeometries.size() );
emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues );
mChangedAttributeValues.clear();
emit committedGeometriesChanges( L->id(), mChangedGeometries );
mChangedGeometries.clear();
}
else
{
commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
#if 0
QString list = "ERROR: pending changes:";
Q_FOREACH ( QgsFeatureId id, mChangedAttributeValues.keys() )
{
list.append( "\n " + FID_TO_STRING( id ) + '[' );
Q_FOREACH ( int idx, mChangedAttributeValues[ id ].keys() )
{
list.append( QString( " %1:%2" ).arg( L->pendingFields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
}
list.append( " ]" );
}
commitErrors << list;
#endif
success = false;
}
}
else
{
//
// change attributes
//
if ( !mChangedAttributeValues.isEmpty() && (( cap & QgsVectorDataProvider::ChangeFeatures ) == 0 || mChangedGeometries.isEmpty() ) )
{
if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && provider->changeAttributeValues( mChangedAttributeValues ) )
{
commitErrors << tr( "SUCCESS: %n attribute value(s) changed.", "changed attribute values count", mChangedAttributeValues.size() );
emit committedAttributeValuesChanges( L->id(), mChangedAttributeValues );
mChangedAttributeValues.clear();
}
else
{
commitErrors << tr( "ERROR: %n attribute value change(s) not applied.", "not changed attribute values count", mChangedAttributeValues.size() );
#if 0
QString list = "ERROR: pending changes:";
Q_FOREACH ( QgsFeatureId id, mChangedAttributeValues.keys() )
{
list.append( "\n " + FID_TO_STRING( id ) + '[' );
Q_FOREACH ( int idx, mChangedAttributeValues[ id ].keys() )
{
list.append( QString( " %1:%2" ).arg( L->pendingFields().at( idx ).name() ).arg( mChangedAttributeValues[id][idx].toString() ) );
}
list.append( " ]" );
}
commitErrors << list;
#endif
success = false;
}
}
}
//
// delete features

View File

@ -133,7 +133,7 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
virtual bool addAttributes( const QList<QgsField> &attributes ) override;
virtual bool deleteAttributes( const QgsAttributeIds &attributes ) override;
virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ) override { Q_UNUSED( attr_map ); return true; }
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map ) override { Q_UNUSED( geometry_map ); return true; }
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override { Q_UNUSED( geometry_map ); return true; }
//----------------------------------------------------------------------------

View File

@ -392,7 +392,7 @@ bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds& attributes )
return true;
}
bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap & attr_map )
bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
{
for ( QgsChangedAttributesMap::const_iterator it = attr_map.begin(); it != attr_map.end(); ++it )
{
@ -407,7 +407,7 @@ bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap & a
return true;
}
bool QgsMemoryProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsMemoryProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
for ( QgsGeometryMap::const_iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
{

View File

@ -109,7 +109,7 @@ class QgsMemoryProvider : public QgsVectorDataProvider
* the second map parameter being the new geometries themselves
* @return true in case of success and false in case of failure
*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
virtual bool changeGeometryValues( const QgsGeometryMap & geometry_map ) override;
/** Accessor for sql where clause used to limit dataset */
QString subsetString() override;

View File

@ -1167,7 +1167,7 @@ bool QgsMssqlProvider::changeAttributeValues( const QgsChangedAttributesMap &att
return true;
}
bool QgsMssqlProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsMssqlProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
if ( geometry_map.isEmpty() )
return true;
@ -1175,7 +1175,7 @@ bool QgsMssqlProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
if ( mFidColName.isEmpty() )
return false;
for ( QgsGeometryMap::iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
for ( QgsGeometryMap::const_iterator it = geometry_map.constBegin(); it != geometry_map.constEnd(); ++it )
{
QgsFeatureId fid = it.key();
// skip added features

View File

@ -207,10 +207,10 @@ class QgsMssqlProvider : public QgsVectorDataProvider
virtual bool deleteAttributes( const QgsAttributeIds &attributes ) override;
/** Changes attribute values of existing features */
virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ) override;
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
/** Changes existing geometries*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
/**
* Create a spatial index for the current layer

View File

@ -1261,14 +1261,14 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
return true;
}
bool QgsOgrProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
OGRFeatureH theOGRFeature = nullptr;
OGRGeometryH theNewGeometry = nullptr;
setRelevantFields( ogrLayer, true, attributeIndexes() );
for ( QgsGeometryMap::iterator it = geometry_map.begin(); it != geometry_map.end(); ++it )
for ( QgsGeometryMap::const_iterator it = geometry_map.constBegin(); it != geometry_map.constEnd(); ++it )
{
if ( FID_TO_NUMBER( it.key() ) > std::numeric_limits<long>::max() )
{

View File

@ -152,10 +152,10 @@ class QgsOgrProvider : public QgsVectorDataProvider
virtual bool deleteAttributes( const QgsAttributeIds &attributes ) override;
/** Changes attribute values of existing features */
virtual bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ) override;
virtual bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
/** Changes existing geometries*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
/** Tries to create a .qix index file for faster access if only a subset of the features is required
@return true in case of success*/

View File

@ -1889,7 +1889,7 @@ void QgsOracleProvider::appendGeomParam( const QgsGeometry *geom, QSqlQuery &qry
qry.addBindValue( QVariant::fromValue( g ) );
}
bool QgsOracleProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsOracleProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
QgsDebugMsg( "entering." );
@ -1919,8 +1919,8 @@ bool QgsOracleProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
throw OracleException( tr( "Could not prepare update statement." ), qry );
}
for ( QgsGeometryMap::iterator iter = geometry_map.begin();
iter != geometry_map.end();
for ( QgsGeometryMap::const_iterator iter = geometry_map.constBegin();
iter != geometry_map.constEnd();
++iter )
{
appendGeomParam( &iter.value(), qry );

View File

@ -1143,6 +1143,14 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
// supports circular geometries
mEnabledCapabilities |= QgsVectorDataProvider::CircularGeometries;
if (( mEnabledCapabilities & QgsVectorDataProvider::ChangeGeometries ) &&
( mEnabledCapabilities & QgsVectorDataProvider::ChangeAttributeValues ) &&
mSpatialColType != sctTopoGeometry )
{
mEnabledCapabilities |= QgsVectorDataProvider::ChangeFeatures;
}
return true;
}
@ -1214,7 +1222,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
mPrimaryKeyType = pktTid;
QgsMessageLog::logMessage( tr( "Primary key is ctid - changing of existing features disabled (%1; %2)" ).arg( mGeometryColumn, mQuery ) );
mEnabledCapabilities &= ~( QgsVectorDataProvider::DeleteFeatures | QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries );
mEnabledCapabilities &= ~( QgsVectorDataProvider::DeleteFeatures | QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::ChangeFeatures );
}
else
{
@ -2192,7 +2200,7 @@ bool QgsPostgresProvider::changeAttributeValues( const QgsChangedAttributesMap &
conn->begin();
// cycle through the features
for ( QgsChangedAttributesMap::const_iterator iter = attr_map.begin(); iter != attr_map.end(); ++iter )
for ( QgsChangedAttributesMap::const_iterator iter = attr_map.constBegin(); iter != attr_map.constEnd(); ++iter )
{
QgsFeatureId fid = iter.key();
@ -2210,7 +2218,7 @@ bool QgsPostgresProvider::changeAttributeValues( const QgsChangedAttributesMap &
// cycle through the changed attributes of the feature
QString delim;
for ( QgsAttributeMap::const_iterator siter = attrs.begin(); siter != attrs.end(); ++siter )
for ( QgsAttributeMap::const_iterator siter = attrs.constBegin(); siter != attrs.constEnd(); ++siter )
{
try
{
@ -2302,7 +2310,7 @@ void QgsPostgresProvider::appendGeomParam( const QgsGeometry *geom, QStringList
params << param;
}
bool QgsPostgresProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsPostgresProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
QgsDebugMsg( "entering." );
@ -2389,8 +2397,8 @@ bool QgsPostgresProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
QgsDebugMsg( "iterating over the map of changed geometries..." );
for ( QgsGeometryMap::iterator iter = geometry_map.begin();
iter != geometry_map.end();
for ( QgsGeometryMap::const_iterator iter = geometry_map.constBegin();
iter != geometry_map.constEnd();
++iter )
{
QgsDebugMsg( "iterating over feature id " + FID_TO_STRING( iter.key() ) );
@ -2483,7 +2491,152 @@ bool QgsPostgresProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
conn->unlock();
QgsDebugMsg( "exiting." );
QgsDebugMsg( "leaving." );
return returnvalue;
}
bool QgsPostgresProvider::changeFeatures( const QgsChangedAttributesMap &attr_map,
const QgsGeometryMap &geometry_map )
{
QgsDebugMsg( "entering." );
Q_ASSERT( mSpatialColType != sctTopoGeometry );
bool returnvalue = true;
if ( mIsQuery )
return false;
if ( attr_map.isEmpty() )
return true;
QgsPostgresConn *conn = connectionRW();
if ( !conn )
return false;
conn->lock();
try
{
conn->begin();
QgsFeatureIds ids( attr_map.keys().toSet() );
ids |= geometry_map.keys().toSet();
// cycle through the features
Q_FOREACH ( const QgsFeatureId &fid, ids )
{
// skip added features
if ( FID_IS_NEW( fid ) )
continue;
const QgsAttributeMap &attrs = attr_map.value( fid );
if ( attrs.isEmpty() && !geometry_map.contains( fid ) )
continue;
QString sql = QString( "UPDATE %1 SET " ).arg( mQuery );
bool pkChanged = false;
// cycle through the changed attributes of the feature
QString delim;
for ( QgsAttributeMap::const_iterator siter = attrs.constBegin(); siter != attrs.constEnd(); ++siter )
{
try
{
QgsField fld = field( siter.key() );
pkChanged = pkChanged || mPrimaryKeyAttrs.contains( siter.key() );
sql += delim + QString( "%1=" ).arg( quotedIdentifier( fld.name() ) );
delim = ',';
if ( fld.typeName() == "geometry" )
{
sql += QString( "%1(%2)" )
.arg( connectionRO()->majorVersion() < 2 ? "geomfromewkt" : "st_geomfromewkt",
quotedValue( siter->toString() ) );
}
else if ( fld.typeName() == "geography" )
{
sql += QString( "st_geographyfromewkt(%1)" )
.arg( quotedValue( siter->toString() ) );
}
else
{
sql += quotedValue( *siter );
}
}
catch ( PGFieldNotFound )
{
// Field was missing - shouldn't happen
}
}
if ( !geometry_map.contains( fid ) )
{
sql += QString( " WHERE %1" ).arg( whereClause( fid ) );
QgsPostgresResult result( conn->PQexec( sql ) );
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
throw PGException( result );
}
else
{
sql += QString( "%1%2=%3" ).arg( delim, quotedIdentifier( mGeometryColumn ), geomParam( 1 ) );
sql += QString( " WHERE %1" ).arg( whereClause( fid ) );
QgsPostgresResult result( conn->PQprepare( "updatefeature", sql, 1, nullptr ) );
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
{
QgsDebugMsg( QString( "Exception thrown due to PQprepare of this query returning != PGRES_COMMAND_OK (%1 != expected %2): %3" )
.arg( result.PQresultStatus() ).arg( PGRES_COMMAND_OK ).arg( sql ) );
throw PGException( result );
}
QStringList params;
const QgsGeometry &geom = geometry_map[ fid ];
appendGeomParam( &geom, params );
result = conn->PQexecPrepared( "updatefeature", params );
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
throw PGException( result );
conn->PQexecNR( "DEALLOCATE updatefeature" );
}
// update feature id map if key was changed
if ( pkChanged && mPrimaryKeyType == pktFidMap )
{
QVariant v = mShared->removeFid( fid );
QList<QVariant> k = v.toList();
for ( int i = 0; i < mPrimaryKeyAttrs.size(); i++ )
{
int idx = mPrimaryKeyAttrs.at( i );
if ( !attrs.contains( idx ) )
continue;
k[i] = attrs[ idx ];
}
mShared->insertFid( fid, k );
}
}
returnvalue &= conn->commit();
}
catch ( PGException &e )
{
pushError( tr( "PostGIS error while changing attributes: %1" ).arg( e.errorMessage() ) );
conn->rollback();
returnvalue = false;
}
conn->unlock();
QgsDebugMsg( "leaving." );
return returnvalue;
}

View File

@ -205,13 +205,13 @@ class QgsPostgresProvider : public QgsVectorDataProvider
/** Deletes existing attributes
@param names of the attributes to delete
@return true in case of success and false in case of failure*/
bool deleteAttributes( const QgsAttributeIds & name ) override;
bool deleteAttributes( const QgsAttributeIds &name ) override;
/** Changes attribute values of existing features
@param attr_map a map containing the new attributes. The integer is the feature id,
the first QString is the attribute name and the second one is the new attribute value
@return true in case of success and false in case of failure*/
bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ) override;
bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
/**
Changes geometries of existing features
@ -219,7 +219,17 @@ class QgsPostgresProvider : public QgsVectorDataProvider
the second map parameter being the new geometries themselves
@return true in case of success and false in case of failure
*/
bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
/**
* Changes attribute values and geometries of existing features.
* @param attr_map a map containing changed attributes
* @param geometry_map A QgsGeometryMap whose index contains the feature IDs
* that will have their geometries changed.
* The second map parameter being the new geometries themselves
* @return true in case of success and false in case of failure
*/
bool changeFeatures( const QgsChangedAttributesMap &attr_map, const QgsGeometryMap &geometry_map ) override;
//! Get the postgres connection
PGconn * pgConnection();

View File

@ -3978,7 +3978,7 @@ abort:
return false;
}
bool QgsSpatiaLiteProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsSpatiaLiteProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
sqlite3_stmt *stmt = nullptr;
char *errMsg = nullptr;
@ -4007,7 +4007,7 @@ bool QgsSpatiaLiteProvider::changeGeometryValues( QgsGeometryMap & geometry_map
return false;
}
for ( QgsGeometryMap::iterator iter = geometry_map.begin(); iter != geometry_map.end(); ++iter )
for ( QgsGeometryMap::const_iterator iter = geometry_map.constBegin(); iter != geometry_map.constEnd(); ++iter )
{
// resetting Prepared Statement and bindings
sqlite3_reset( stmt );

View File

@ -176,7 +176,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
@param attr_map a map containing the new attributes. The integer is the feature id,
the first QString is the attribute name and the second one is the new attribute value
@return true in case of success and false in case of failure*/
bool changeAttributeValues( const QgsChangedAttributesMap & attr_map ) override;
bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
/**
Changes geometries of existing features
@ -184,7 +184,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
the second map parameter being the new geometries themselves
@return true in case of success and false in case of failure
*/
bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
/** Returns a bitmask containing the supported capabilities*/
int capabilities() const override;

View File

@ -466,7 +466,7 @@ bool QgsWFSProvider::deleteFeatures( const QgsFeatureIds &id )
}
}
bool QgsWFSProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
bool QgsWFSProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
{
//find out typename from uri and strip namespace prefix
QString tname = parameterFromUrl( "typename" );
@ -480,8 +480,8 @@ bool QgsWFSProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
QDomElement transactionElem = createTransactionElement( transactionDoc );
transactionDoc.appendChild( transactionElem );
QgsGeometryMap::iterator geomIt = geometry_map.begin();
for ( ; geomIt != geometry_map.end(); ++geomIt )
QgsGeometryMap::const_iterator geomIt = geometry_map.constBegin();
for ( ; geomIt != geometry_map.constEnd(); ++geomIt )
{
//find out feature id
QMap< QgsFeatureId, QString >::const_iterator fidIt = mIdMap.constFind( geomIt.key() );

View File

@ -135,7 +135,7 @@ class QgsWFSProvider : public QgsVectorDataProvider
* The second map parameter being the new geometries themselves
* @return True in case of success and false in case of failure
*/
virtual bool changeGeometryValues( QgsGeometryMap & geometry_map ) override;
virtual bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
/**
* Changes attribute values of existing features.