Skip to content
Permalink
Browse files

[Bugfix] Ensure order by attribute indices are valid

  • Loading branch information
manisandro committed Mar 15, 2019
1 parent 61b2f91 commit 0996c93d0955fb1a219ee3a17af769289db38f32
@@ -243,6 +243,17 @@ Deserialize from XML
QSet<QString> usedAttributes() const;
%Docstring
Returns a set of used attributes

.. note::

The returned attributes names are NOT guaranteed to be valid.
%End

QSet<int> usedAttributeIndices( const QgsFields &fields ) const;
%Docstring
Returns a set of used, validated attribute indices

.. versionadded:: 3.8
%End

QString dump() const;
@@ -485,6 +485,24 @@ QSet<QString> QgsFeatureRequest::OrderBy::usedAttributes() const
return usedAttributes;
}

QSet<int> QgsFeatureRequest::OrderBy::usedAttributeIndices( const QgsFields &fields ) const
{
QSet<int> usedAttributeIdx;
for ( const OrderByClause &clause : *this )
{
const auto referencedColumns = clause.expression().referencedColumns();
for ( const QString &fieldName : referencedColumns )
{
int idx = fields.lookupField( fieldName );
if ( idx >= 0 )
{
usedAttributeIdx.insert( idx );
}
}
}
return usedAttributeIdx;
}

QString QgsFeatureRequest::OrderBy::dump() const
{
QStringList results;
@@ -257,9 +257,16 @@ class CORE_EXPORT QgsFeatureRequest

/**
* Returns a set of used attributes
* \note The returned attributes names are NOT guaranteed to be valid.
*/
QSet<QString> CORE_EXPORT usedAttributes() const;

/**
* Returns a set of used, validated attribute indices
* \since QGIS 3.8
*/
QSet<int> CORE_EXPORT usedAttributeIndices( const QgsFields &fields ) const;

/**
* Dumps the content to an SQL equivalent syntax
*/
@@ -189,9 +189,10 @@ QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeat
// and only modify the subset if we cannot.
if ( !mProviderRequest.orderBy().isEmpty() )
{
Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIndex : usedAttributeIndices )
{
providerSubset << mSource->mFields.lookupField( attr );
providerSubset << attrIndex;
}
}

@@ -161,9 +161,9 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
QgsAttributeList attrs = request.subsetOfAttributes();
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIndex : usedAttributeIndices )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !attrs.contains( attrIndex ) )
attrs << attrIndex;
}
@@ -95,10 +95,9 @@ void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest &request )
}

// ensure that all attributes required for order by are fetched
const QSet< QString > orderByAttributes = mRequest.orderBy().usedAttributes();
for ( const QString &attr : orderByAttributes )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIndex : usedAttributeIndices )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !attrs.contains( attrIndex ) )
attrs << attrIndex;
}
@@ -136,9 +136,10 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource *source, bool
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
QSet<int> attributeIndexes;
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIdx : usedAttributeIndices )
{
attributeIndexes << mSource->mFields.lookupField( attr );
attributeIndexes << attrIdx;
}
attributeIndexes += attrs.toSet();
attrs = attributeIndexes.toList();
@@ -186,9 +186,9 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
QgsAttributeList attrs = mRequest.subsetOfAttributes();
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIndex : usedAttributeIndices )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !attrs.contains( attrIndex ) )
attrs << attrIndex;
}
@@ -196,9 +196,10 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
QSet<int> attributeIndexes;
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIdx : usedAttributeIndices )
{
attributeIndexes << mSource->mFields.lookupField( attr );
attributeIndexes << attrIdx;
}
attributeIndexes += mRequest.subsetOfAttributes().toSet();
mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
@@ -128,7 +128,8 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
// copy only selected fields
Q_FOREACH ( int idx, request.subsetOfAttributes() )
const auto subsetOfAttributes = request.subsetOfAttributes();
for ( int idx : subsetOfAttributes )
{
mAttributes << idx;
}
@@ -147,9 +148,9 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
// also need attributes required by order by
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIdx : usedAttributeIndices )
{
int attrIdx = mSource->mFields.lookupField( attr );
if ( !mAttributes.contains( attrIdx ) )
mAttributes << attrIdx;
}
@@ -1030,7 +1030,8 @@ QgsFeatureRequest QgsWFSFeatureIterator::buildRequestCache( int genCounter )
{
QgsFields dataProviderFields = mShared->mCacheDataProvider->fields();
QgsAttributeList cacheSubSet;
Q_FOREACH ( int i, mRequest.subsetOfAttributes() )
const auto subsetOfAttributes = mRequest.subsetOfAttributes();
for ( int i : subsetOfAttributes )
{
int idx = dataProviderFields.indexFromName( mShared->mFields.at( i ).name() );
if ( idx >= 0 )
@@ -1043,7 +1044,8 @@ QgsFeatureRequest QgsWFSFeatureIterator::buildRequestCache( int genCounter )
// ensure that all attributes required for expression filter are being fetched
if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
{
Q_FOREACH ( const QString &field, mRequest.filterExpression()->referencedColumns() )
const auto referencedColumns = mRequest.filterExpression()->referencedColumns();
for ( const QString &field : referencedColumns )
{
int idx = dataProviderFields.indexFromName( field );
if ( idx >= 0 && !cacheSubSet.contains( idx ) )
@@ -1057,15 +1059,18 @@ QgsFeatureRequest QgsWFSFeatureIterator::buildRequestCache( int genCounter )
// also need attributes required by order by
if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
const auto usedProviderAttributeIndices = mRequest.orderBy().usedAttributeIndices( dataProviderFields );
for ( int attrIdx : usedProviderAttributeIndices )
{
int idx = dataProviderFields.indexFromName( attr );
if ( idx >= 0 && !cacheSubSet.contains( idx ) )
cacheSubSet.append( idx );
if ( !cacheSubSet.contains( attrIdx ) )
cacheSubSet.append( attrIdx );
}

idx = mShared->mFields.indexFromName( attr );
if ( idx >= 0 && !mSubSetAttributes.contains( idx ) )
mSubSetAttributes.append( idx );
const auto usedSharedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mShared->mFields );
for ( int attrIdx : usedSharedAttributeIndices )
{
if ( !mSubSetAttributes.contains( attrIdx ) )
mSubSetAttributes.append( attrIdx );
}
}

0 comments on commit 0996c93

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