Rowid column from ogr provider is ignored thanks to a blacklist join option

This commit is contained in:
Blottiere Paul 2017-08-29 10:00:52 +01:00
parent 4a8fce2b00
commit 0dcfd56cdf
7 changed files with 102 additions and 22 deletions

View File

@ -166,6 +166,23 @@ Returns whether values from the joined layer should be cached in memory to speed
:rtype: QgsFeature
%End
void setJoinFieldNamesBlackList( const QStringList &blackList );
QStringList joinFieldNamesBlackList() const;
%Docstring
:rtype: list of str
%End
bool hasSubset( bool blacklisted = true ) const;
%Docstring
:rtype: bool
%End
static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true );
%Docstring
:rtype: list of str
%End
bool operator==( const QgsVectorLayerJoinInfo &other ) const;
void setJoinFieldNamesSubset( QStringList *fieldNamesSubset /Transfer/ );
@ -194,6 +211,7 @@ Returns whether values from the joined layer should be cached in memory to speed
};

View File

@ -168,6 +168,7 @@ QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &fil
mJoinInfo.setEditable( true );
mJoinInfo.setUpsertOnEdit( true );
mJoinInfo.setCascadedDelete( true );
mJoinInfo.setJoinFieldNamesBlackList( QStringList() << "rowid" ); // introduced by ogr provider
}
QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const

View File

@ -944,10 +944,12 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg
// maybe user requested just a subset of layer's attributes
// so we do not have to cache everything
bool hasSubset = joinInfo->joinFieldNamesSubset();
QVector<int> subsetIndices;
if ( hasSubset )
subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
if ( joinInfo->hasSubset() )
{
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
}
// select (no geometry)
QgsFeatureRequest request;
@ -963,7 +965,7 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg
{
int index = indexOffset;
QgsAttributes attr = fet.attributes();
if ( hasSubset )
if ( joinInfo->hasSubset() )
{
for ( int i = 0; i < subsetIndices.count(); ++i )
f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );

View File

@ -137,11 +137,11 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo
request.setFlags( QgsFeatureRequest::NoGeometry );
// maybe user requested just a subset of layer's attributes
// so we do not have to cache everything
bool hasSubset = joinInfo.joinFieldNamesSubset();
QVector<int> subsetIndices;
if ( hasSubset )
if ( joinInfo.hasSubset() )
{
subsetIndices = joinSubsetIndices( cacheLayer, *joinInfo.joinFieldNamesSubset() );
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( joinInfo );
subsetIndices = joinSubsetIndices( cacheLayer, subsetNames );
// we need just subset of attributes - but make sure to include join field name
QgsAttributeList cacheLayerAttrs = subsetIndices.toList();
@ -156,7 +156,7 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo
{
QgsAttributes attrs = f.attributes();
QString key = attrs.at( joinFieldIndex ).toString();
if ( hasSubset )
if ( joinInfo.hasSubset() )
{
QgsAttributes subsetAttrs( subsetIndices.count() );
for ( int i = 0; i < subsetIndices.count(); ++i )
@ -213,11 +213,10 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields )
QString joinFieldName = joinIt->joinFieldName();
QSet<QString> subset;
bool hasSubset = false;
if ( joinIt->joinFieldNamesSubset() )
if ( joinIt->hasSubset() )
{
hasSubset = true;
subset = QSet<QString>::fromList( *joinIt->joinFieldNamesSubset() );
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt );
subset = QSet<QString>::fromList( subsetNames );
}
if ( joinIt->prefix().isNull() )
@ -232,12 +231,12 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields )
for ( int idx = 0; idx < joinFields.count(); ++idx )
{
// if using just a subset of fields, filter some of them out
if ( hasSubset && !subset.contains( joinFields.at( idx ).name() ) )
if ( joinIt->hasSubset() && !subset.contains( joinFields.at( idx ).name() ) )
continue;
//skip the join field to avoid double field names (fields often have the same name)
// when using subset of field, use all the selected fields
if ( hasSubset || joinFields.at( idx ).name() != joinFieldName )
if ( joinIt->hasSubset() || joinFields.at( idx ).name() != joinFieldName )
{
QgsField f = joinFields.at( idx );
f.setName( prefix + f.name() );
@ -279,10 +278,12 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc
joinElem.setAttribute( QStringLiteral( "upsertOnEdit" ), joinIt->hasUpsertOnEdit() );
joinElem.setAttribute( QStringLiteral( "cascadedDelete" ), joinIt->hasCascadedDelete() );
if ( joinIt->joinFieldNamesSubset() )
if ( joinIt->hasSubset() )
{
QDomElement subsetElem = document.createElement( QStringLiteral( "joinFieldsSubset" ) );
Q_FOREACH ( const QString &fieldName, *joinIt->joinFieldNamesSubset() )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt );
Q_FOREACH ( const QString &fieldName, subsetNames )
{
QDomElement fieldElem = document.createElement( QStringLiteral( "field" ) );
fieldElem.setAttribute( QStringLiteral( "name" ), fieldName );
@ -552,10 +553,10 @@ bool QgsVectorLayerJoinBuffer::addFeatures( QgsFeatureList &features, QgsFeature
if ( existingFeature.isValid() )
{
const QStringList *subsetFields = info.joinFieldNamesSubset();
if ( subsetFields )
if ( info.hasSubset() )
{
Q_FOREACH ( const QString &field, *subsetFields )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( info );
Q_FOREACH ( const QString &field, subsetNames )
{
QVariant newValue = joinFeature.attribute( field );
int fieldIndex = joinLayer->fields().indexOf( field );

View File

@ -68,3 +68,50 @@ QgsFeature QgsVectorLayerJoinInfo::extractJoinedFeature( const QgsFeature &featu
return joinFeature;
}
QStringList QgsVectorLayerJoinInfo::joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted )
{
QStringList fieldNames;
if ( blacklisted && !info.joinFieldNamesBlackList().isEmpty() )
{
QStringList *lst = info.joinFieldNamesSubset();
if ( lst )
{
Q_FOREACH ( const QString &s, *lst )
{
if ( !info.joinFieldNamesBlackList().contains( s ) )
fieldNames.append( s );
}
}
else
{
Q_FOREACH ( const QgsField &f, info.joinLayer()->fields() )
{
if ( !info.joinFieldNamesBlackList().contains( f.name() )
&& f.name() != info.joinFieldName() )
fieldNames.append( f.name() );
}
}
}
else
{
QStringList *lst = info.joinFieldNamesSubset();
if ( lst )
{
fieldNames = *lst;
}
}
return fieldNames;
}
bool QgsVectorLayerJoinInfo::hasSubset( bool blacklisted ) const
{
bool subset = joinFieldNamesSubset();
if ( blacklisted )
subset |= !joinFieldNamesBlackList().isEmpty();
return subset;
}

View File

@ -141,6 +141,14 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
*/
QgsFeature extractJoinedFeature( const QgsFeature &feature ) const;
void setJoinFieldNamesBlackList( const QStringList &blackList ) { mBlackList = blackList; }
QStringList joinFieldNamesBlackList() const { return mBlackList; }
bool hasSubset( bool blacklisted = true ) const;
static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true );
bool operator==( const QgsVectorLayerJoinInfo &other ) const
{
return mTargetFieldName == other.mTargetFieldName &&
@ -197,6 +205,8 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
bool mCascadedDelete = false;
QStringList mBlackList;
//! Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
QHash< QString, QgsAttributes> cachedAttributes;

View File

@ -1996,10 +1996,11 @@ void QgsAttributeForm::updateJoinedFields( const QgsEditorWidgetWrapper &eww )
mJoinedFeatures[info] = joinFeature;
QStringList *subsetFields = info->joinFieldNamesSubset();
if ( subsetFields )
if ( info->hasSubset() )
{
Q_FOREACH ( const QString &field, *subsetFields )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *info );
Q_FOREACH ( const QString &field, subsetNames )
{
QString prefixedName = info->prefixedFieldName( field );
QVariant val;