QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
    : QgsAbstractFeatureIteratorFromSource<QgsPostgresFeatureSource>( source, ownSource, request )
    , mFeatureQueueSize( sFeatureQueueSize )
    , mFetched( 0 )
    , mFetchGeometry( false )
    , mExpressionCompiled( false )
    , mLastFetch( false )
{
    if ( !source->mTransactionConnection )
    {
        mConn = QgsPostgresConnPool::instance()->acquireConnection( mSource->mConnInfo );
        mIsTransactionConnection = false;
    }
    else
    {
        mConn = source->mTransactionConnection;
        mConn->lock();
        mIsTransactionConnection = true;
    }

    if ( !mConn )
    {
        mClosed = true;
        iteratorClosed();
        return;
    }

    mCursorName = mConn->uniqueCursorName();
    QString whereClause;

    if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() )
    {
        whereClause = whereClauseRect();
    }

    if ( request.filterType() == QgsFeatureRequest::FilterFid )
    {
        QString fidWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFid(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );

        whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidWhereClause );
    }
    else if ( request.filterType() == QgsFeatureRequest::FilterFids )
    {
        QString fidsWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFids(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );

        whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidsWhereClause );
    }
    else if ( request.filterType() == QgsFeatureRequest::FilterExpression
              && QSettings().value( "/qgis/compileExpressions", true ).toBool() )
    {
        QgsPostgresExpressionCompiler compiler = QgsPostgresExpressionCompiler( source );

        if ( compiler.compile( request.filterExpression() ) == QgsSqlExpressionCompiler::Complete )
        {
            whereClause = QgsPostgresUtils::andWhereClauses( whereClause, compiler.result() );
            mExpressionCompiled = true;
        }
    }

    if ( !mSource->mSqlWhereClause.isEmpty() )
    {
        if ( !whereClause.isEmpty() )
            whereClause += " AND ";

        whereClause += '(' + mSource->mSqlWhereClause + ')';
    }

    if ( !declareCursor( whereClause ) )
    {
        mClosed = true;
        iteratorClosed();
        return;
    }

    mFetched = 0;
}
QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
    : QgsAbstractFeatureIteratorFromSource<QgsPostgresFeatureSource>( source, ownSource, request )
    , mFeatureQueueSize( sFeatureQueueSize )
    , mFetched( 0 )
    , mFetchGeometry( false )
    , mExpressionCompiled( false )
    , mOrderByCompiled( false )
    , mLastFetch( false )
    , mFilterRequiresGeometry( false )
{
  if ( !source->mTransactionConnection )
  {
    mConn = QgsPostgresConnPool::instance()->acquireConnection( mSource->mConnInfo );
    mIsTransactionConnection = false;
  }
  else
  {
    mConn = source->mTransactionConnection;
    mIsTransactionConnection = true;
  }

  if ( !mConn )
  {
    mClosed = true;
    iteratorClosed();
    return;
  }

  mCursorName = mConn->uniqueCursorName();
  QString whereClause;

  bool limitAtProvider = ( mRequest.limit() >= 0 );

  bool useFallbackWhereClause = false;
  QString fallbackWhereClause;

  if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() )
  {
    whereClause = whereClauseRect();
  }

  if ( !mSource->mSqlWhereClause.isEmpty() )
  {
    whereClause = QgsPostgresUtils::andWhereClauses( whereClause, '(' + mSource->mSqlWhereClause + ')' );
  }

  if ( request.filterType() == QgsFeatureRequest::FilterFid )
  {
    QString fidWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFid(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );

    whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidWhereClause );
  }
  else if ( request.filterType() == QgsFeatureRequest::FilterFids )
  {
    QString fidsWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFids(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );

    whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidsWhereClause );
  }
  else if ( request.filterType() == QgsFeatureRequest::FilterExpression )
  {
    // ensure that all attributes required for expression filter are being fetched
    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
    {
      QgsAttributeList attrs = mRequest.subsetOfAttributes();
      Q_FOREACH ( const QString& field, request.filterExpression()->referencedColumns() )
      {
        int attrIdx = mSource->mFields.fieldNameIndex( field );
        if ( !attrs.contains( attrIdx ) )
          attrs << attrIdx;
      }
      mRequest.setSubsetOfAttributes( attrs );
    }
    mFilterRequiresGeometry = request.filterExpression()->needsGeometry();

    if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() )
    {
      //IMPORTANT - this MUST be the last clause added!
      QgsPostgresExpressionCompiler compiler = QgsPostgresExpressionCompiler( source );

      if ( compiler.compile( request.filterExpression() ) == QgsSqlExpressionCompiler::Complete )
      {
        useFallbackWhereClause = true;
        fallbackWhereClause = whereClause;
        whereClause = QgsPostgresUtils::andWhereClauses( whereClause, compiler.result() );
        mExpressionCompiled = true;
        mCompileStatus = Compiled;
      }
      else
      {
        limitAtProvider = false;
      }
    }
    else
    {
      limitAtProvider = false;
    }
  }