mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[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:
parent
c063838f52
commit
ad1fd2a922
@ -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();
|
||||
|
||||
/**
|
||||
|
@ -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( ", " );
|
||||
}
|
||||
|
||||
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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() )
|
||||
{
|
||||
|
@ -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*/
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
@ -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() );
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user