QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
    : QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
    , mFetchedFid( false )
    , mInterruptionChecker( nullptr )
{
    if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
    {
        mRequest.expressionContext()->setFields( mSource->mFields );
        mRequest.filterExpression()->prepare( mRequest.expressionContext() );

        if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
        {
            //ensure that all fields required for filter expressions are prepared
            QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
            attributeIndexes += mRequest.subsetOfAttributes().toSet();
            mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
        }
    }

    prepareFields();

    mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();

    // by default provider's request is the same
    mProviderRequest = mRequest;

    if ( mProviderRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
    {
        // prepare list of attributes to match provider fields
        QSet<int> providerSubset;
        QgsAttributeList subset = mProviderRequest.subsetOfAttributes();
        int nPendingFields = mSource->mFields.count();
        Q_FOREACH ( int attrIndex, subset )
        {
            if ( attrIndex < 0 || attrIndex >= nPendingFields )
                continue;
            if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
                providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
        }

        // This is done in order to be prepared to do fallback order bys
        // and be sure we have the required columns.
        // TODO:
        // It would be nicer to first check if we can compile the order by
        // and only modify the subset if we cannot.
        if ( !mProviderRequest.orderBy().isEmpty() )
        {
            Q_FOREACH ( const QString& attr, mProviderRequest.orderBy().usedAttributes() )
            {
                providerSubset << mSource->mFields.lookupField( attr );
            }
        }
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
  : QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
  , mFetchedFid( false )

{
  if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mSource->mCrs )
  {
    mTransform = QgsCoordinateTransform( mSource->mCrs, mRequest.destinationCrs(), mRequest.transformContext() );
  }
  try
  {
    mFilterRect = filterRectToSourceCrs( mTransform );
  }
  catch ( QgsCsException & )
  {
    // can't reproject mFilterRect
    close();
    return;
  }
  if ( !mFilterRect.isNull() )
  {
    // update request to be the unprojected filter rect
    mRequest.setFilterRect( mFilterRect );
  }

  if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
  {
    mRequest.expressionContext()->setFields( mSource->mFields );
    mRequest.filterExpression()->prepare( mRequest.expressionContext() );

    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
    {
      //ensure that all fields required for filter expressions are prepared
      QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
      attributeIndexes += mRequest.subsetOfAttributes().toSet();
      mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
    }
  }

  prepareFields();

  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();

  // by default provider's request is the same
  mProviderRequest = mRequest;
  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
  // values
  if ( mRequest.destinationCrs().isValid() )
  {
    mProviderRequest.setDestinationCrs( QgsCoordinateReferenceSystem(), mRequest.transformContext() );
  }

  if ( mProviderRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
  {
    // prepare list of attributes to match provider fields
    QSet<int> providerSubset;
    QgsAttributeList subset = mProviderRequest.subsetOfAttributes();
    int nPendingFields = mSource->mFields.count();
    Q_FOREACH ( int attrIndex, subset )
    {
      if ( attrIndex < 0 || attrIndex >= nPendingFields )
        continue;
      if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
        providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
    }

    // This is done in order to be prepared to do fallback order bys
    // and be sure we have the required columns.
    // TODO:
    // It would be nicer to first check if we can compile the order by
    // and only modify the subset if we cannot.
    if ( !mProviderRequest.orderBy().isEmpty() )
    {
      Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
      {
        providerSubset << mSource->mFields.lookupField( attr );
      }
    }