QgsWFSFeatureIterator::QgsWFSFeatureIterator( QgsWFSProvider* provider, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ) , mProvider( provider ) { //select ids //get iterator if ( !mProvider ) { return; } mProvider->mActiveIterators << this; switch ( request.filterType() ) { case QgsFeatureRequest::FilterRect: if ( mProvider->mSpatialIndex ) { mSelectedFeatures = mProvider->mSpatialIndex->intersects( request.filterRect() ); } break; case QgsFeatureRequest::FilterFid: mSelectedFeatures.push_back( request.filterFid() ); break; case QgsFeatureRequest::FilterNone: mSelectedFeatures = mProvider->mFeatures.keys(); default: //QgsFeatureRequest::FilterNone mSelectedFeatures = mProvider->mFeatures.keys(); } mFeatureIterator = mSelectedFeatures.constBegin(); }
QgsWFSFeatureIterator::QgsWFSFeatureIterator( QgsWFSFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsWFSFeatureSource>( source, ownSource, request ) { if ( !request.filterRect().isNull() && mSource->mSpatialIndex ) { mSelectedFeatures = mSource->mSpatialIndex->intersects( request.filterRect() ); } else if ( request.filterType() == QgsFeatureRequest::FilterFid ) { mSelectedFeatures.push_back( request.filterFid() ); } else { mSelectedFeatures = mSource->mFeatures.keys(); } mFeatureIterator = mSelectedFeatures.constBegin(); }
QgsCachedFeatureIterator::QgsCachedFeatureIterator( QgsVectorLayerCache *vlCache, const QgsFeatureRequest &featureRequest ) : QgsAbstractFeatureIterator( featureRequest ) , mVectorLayerCache( vlCache ) { if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mVectorLayerCache->sourceCrs() ) { mTransform = QgsCoordinateTransform( mVectorLayerCache->sourceCrs(), mRequest.destinationCrs() ); } 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 ); } switch ( featureRequest.filterType() ) { case QgsFeatureRequest::FilterFids: mFeatureIds = featureRequest.filterFids(); break; case QgsFeatureRequest::FilterFid: mFeatureIds = QgsFeatureIds() << featureRequest.filterFid(); break; default: mFeatureIds = mVectorLayerCache->mCache.keys().toSet(); break; } mFeatureIdIterator = mFeatureIds.constBegin(); if ( mFeatureIdIterator == mFeatureIds.constEnd() ) close(); }
QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresProvider* p, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), P( p ) , mFeatureQueueSize( sFeatureQueueSize ) { // make sure that only one iterator is active if ( P->mActiveIterator ) { QgsMessageLog::logMessage( QObject::tr( "Already active iterator on this provider was closed." ), QObject::tr( "PostgreSQL" ) ); P->mActiveIterator->close(); } mCursorName = QString( "qgisf%1" ).arg( P->mProviderId ); QString whereClause; if ( request.filterType() == QgsFeatureRequest::FilterRect && !P->mGeometryColumn.isNull() ) { whereClause = whereClauseRect(); } else if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = P->whereClause( request.filterFid() ); } if ( !P->mSqlWhereClause.isEmpty() ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += "(" + P->mSqlWhereClause + ")"; } if ( !declareCursor( whereClause ) ) { mClosed = true; return; } P->mActiveIterator = this; mFetched = 0; }
QgsCachedFeatureIterator::QgsCachedFeatureIterator( QgsVectorLayerCache *vlCache, QgsFeatureRequest featureRequest ) : QgsAbstractFeatureIterator( featureRequest ) , mVectorLayerCache( vlCache ) { switch ( featureRequest.filterType() ) { case QgsFeatureRequest::FilterFids: mFeatureIds = featureRequest.filterFids(); break; case QgsFeatureRequest::FilterFid: mFeatureIds = QgsFeatureIds() << featureRequest.filterFid(); break; default: mFeatureIds = mVectorLayerCache->mCache.keys().toSet(); break; } mFeatureIdIterator = mFeatureIds.begin(); }
QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresProvider* p, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), P( p ) , mFeatureQueueSize( sFeatureQueueSize ) { mCursorName = QString( "qgisf%1_%2" ).arg( P->mProviderId ).arg( P->mIteratorCounter++ ); P->mActiveIterators << this; QString whereClause; if ( request.filterType() == QgsFeatureRequest::FilterRect && !P->mGeometryColumn.isNull() ) { whereClause = whereClauseRect(); } else if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = P->whereClause( request.filterFid() ); } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause = P->whereClause( request.filterFids() ); } if ( !P->mSqlWhereClause.isEmpty() ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += "(" + P->mSqlWhereClause + ")"; } if ( !declareCursor( whereClause ) ) { mClosed = true; return; } mFetched = 0; }
bool QgsCacheIndexFeatureId::getCacheIterator( QgsFeatureIterator &featureIterator, const QgsFeatureRequest &featureRequest ) { switch ( featureRequest.filterType() ) { case QgsFeatureRequest::FilterFid: { if ( C->isFidCached( featureRequest.filterFid() ) ) { featureIterator = QgsFeatureIterator( new QgsCachedFeatureIterator( C, featureRequest ) ); return true; } break; } case QgsFeatureRequest::FilterFids: { if ( C->cachedFeatureIds().contains( featureRequest.filterFids() ) ) { featureIterator = QgsFeatureIterator( new QgsCachedFeatureIterator( C, featureRequest ) ); return true; } break; } case QgsFeatureRequest::FilterNone: case QgsFeatureRequest::FilterExpression: { if ( C->hasFullCache() ) { featureIterator = QgsFeatureIterator( new QgsCachedFeatureIterator( C, featureRequest ) ); return true; } break; } } return false; }
void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request ) { // build sql statement mStatement = QString( "select " ); int fieldCount = 0; mFidCol = -1; mGeometryCol = -1; if ( !request.subsetOfAttributes().empty() ) { // subset of attributes has been specified for ( QgsAttributeList::const_iterator it = request.subsetOfAttributes().begin(); it != request.subsetOfAttributes().end(); ++it ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFields[*it].name() + "]"; if ( !mSource->mFidColName.isEmpty() && mSource->mFidColName == mSource->mFields[*it].name() ) mFidCol = fieldCount; ++fieldCount; mAttributesToFetch.append( *it ); } } else { // get all attributes for ( int i = 0; i < mSource->mFields.count(); i++ ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFields[i].name() + "]"; if ( !mSource->mFidColName.isEmpty() && mSource->mFidColName == mSource->mFields[i].name() ) mFidCol = fieldCount; ++fieldCount; mAttributesToFetch.append( i ); } } // get fid col if not yet required if ( mFidCol == -1 && !mSource->mFidColName.isEmpty() ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mFidColName + "]"; mFidCol = fieldCount; ++fieldCount; } // get geometry col if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && !mSource->mGeometryColName.isEmpty() ) { if ( fieldCount != 0 ) mStatement += ","; mStatement += "[" + mSource->mGeometryColName + "]"; mGeometryCol = fieldCount; ++fieldCount; } mStatement += " from "; if ( !mSource->mSchemaName.isEmpty() ) mStatement += "[" + mSource->mSchemaName + "]."; mStatement += "[" + mSource->mTableName + "]"; bool filterAdded = false; // set spatial filter if ( request.filterType() & QgsFeatureRequest::FilterRect ) { // polygons should be CCW for SqlGeography QString r; QTextStream foo( &r ); foo.setRealNumberPrecision( 8 ); foo.setRealNumberNotation( QTextStream::FixedNotation ); foo << request.filterRect().xMinimum() << " " << request.filterRect().yMinimum() << ", " << request.filterRect().xMaximum() << " " << request.filterRect().yMinimum() << ", " << request.filterRect().xMaximum() << " " << request.filterRect().yMaximum() << ", " << request.filterRect().xMinimum() << " " << request.filterRect().yMaximum() << ", " << request.filterRect().xMinimum() << " " << request.filterRect().yMinimum(); mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg( mSource->mGeometryColName, mSource->mGeometryColType, r, QString::number( mSource->mSRId ) ); filterAdded = true; } // set fid filter if (( request.filterType() & QgsFeatureRequest::FilterFid ) && !mSource->mFidColName.isEmpty() ) { // set attribute filter if ( !filterAdded ) mStatement += QString( " where [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); else mStatement += QString( " and [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); filterAdded = true; } if ( !mSource->mSqlWhereClause.isEmpty() ) { if ( !filterAdded ) mStatement += " where (" + mSource->mSqlWhereClause + ")"; else mStatement += " and (" + mSource->mSqlWhereClause + ")"; } if ( fieldCount == 0 ) { QgsDebugMsg( "QgsMssqlProvider::select no fields have been requested" ); mStatement.clear(); } }
QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTextFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsDelimitedTextFeatureSource>( source, ownSource, request ) , mTestGeometryExact( false ) { // Determine mode to use based on request... QgsDebugMsg( "Setting up QgsDelimitedTextIterator" ); // Does the layer have geometry - will revise later to determine if we actually need to // load it. bool hasGeometry = mSource->mGeomRep != QgsDelimitedTextProvider::GeomNone; // Does the layer have an explicit or implicit subset (implicit subset is if we have geometry which can // be invalid) mTestSubset = mSource->mSubsetExpression; mTestGeometry = false; mMode = FileScan; if ( request.filterType() == QgsFeatureRequest::FilterFid ) { QgsDebugMsg( "Configuring for returning single id" ); mFeatureIds.append( request.filterFid() ); mMode = FeatureIds; mTestSubset = false; } // If have geometry and testing geometry then evaluate options... // If we don't have geometry then all records pass geometry filter. // CC: 2013-05-09 // Not sure about intended relationship between filtering on geometry and // requesting no geometry? Have preserved current logic of ignoring spatial filter // if not requesting geometry. else if ( request.filterType() == QgsFeatureRequest::FilterRect && hasGeometry ) { QgsDebugMsg( "Configuring for rectangle select" ); mTestGeometry = true; // Exact intersection test only applies for WKT geometries mTestGeometryExact = mRequest.flags() & QgsFeatureRequest::ExactIntersect && mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt; QgsRectangle rect = request.filterRect(); // If request doesn't overlap extents, then nothing to return if ( ! rect.intersects( mSource->mExtent ) ) { QgsDebugMsg( "Rectangle outside layer extents - no features to return" ); mMode = FeatureIds; } // If the request extents include the entire layer, then revert to // a file scan else if ( rect.contains( mSource->mExtent ) ) { QgsDebugMsg( "Rectangle contains layer extents - bypass spatial filter" ); mTestGeometry = false; } // If we have a spatial index then use it. The spatial index already accounts // for the subset. Also means we don't have to test geometries unless doing exact // intersection else if ( mSource->mUseSpatialIndex ) { mFeatureIds = mSource->mSpatialIndex->intersects( rect ); // Sort for efficient sequential retrieval qSort( mFeatureIds.begin(), mFeatureIds.end() ); QgsDebugMsg( QString( "Layer has spatial index - selected %1 features from index" ).arg( mFeatureIds.size() ) ); mMode = FeatureIds; mTestSubset = false; mTestGeometry = mTestGeometryExact; } } // If we have a subset index then use it.. if ( mMode == FileScan && mSource->mUseSubsetIndex ) { QgsDebugMsg( QString( "Layer has subset index - use %1 items from subset index" ).arg( mSource->mSubsetIndex.size() ) ); mTestSubset = false; mMode = SubsetIndex; } // Otherwise just have to scan the file if ( mMode == FileScan ) { QgsDebugMsg( "File will be scanned for desired features" ); } // If the layer has geometry, do we really need to load it? // We need it if it is asked for explicitly in the request, // if we are testing geometry (ie spatial filter), or // if testing the subset expression. if ( hasGeometry && ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) || mTestGeometry || ( mTestSubset && mSource->mSubsetExpression->needsGeometry() ) ) ) { mLoadGeometry = true; } else { QgsDebugMsgLevel( "Feature geometries not required", 4 ); mLoadGeometry = false; } QgsDebugMsg( QString( "Iterator is scanning file: " ) + ( mMode == FileScan ? "Yes" : "No" ) ); QgsDebugMsg( QString( "Iterator is loading geometries: " ) + ( mLoadGeometry ? "Yes" : "No" ) ); QgsDebugMsg( QString( "Iterator is testing geometries: " ) + ( mTestGeometry ? "Yes" : "No" ) ); QgsDebugMsg( QString( "Iterator is testing subset: " ) + ( mTestSubset ? "Yes" : "No" ) ); rewind(); }
QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTextFeatureSource *source, bool ownSource, const QgsFeatureRequest &request ) : QgsAbstractFeatureIteratorFromSource<QgsDelimitedTextFeatureSource>( source, ownSource, request ) , mTestSubset( mSource->mSubsetExpression ) { // Determine mode to use based on request... QgsDebugMsg( "Setting up QgsDelimitedTextIterator" ); // Does the layer have geometry - will revise later to determine if we actually need to // load it. bool hasGeometry = mSource->mGeomRep != QgsDelimitedTextProvider::GeomNone; if ( mRequest.destinationCrs().isValid() && mRequest.destinationCrs() != mSource->mCrs ) { mTransform = QgsCoordinateTransform( mSource->mCrs, mRequest.destinationCrs() ); } try { mFilterRect = filterRectToSourceCrs( mTransform ); } catch ( QgsCsException & ) { // can't reproject mFilterRect mClosed = true; return; } if ( !mFilterRect.isNull() && hasGeometry ) { QgsDebugMsg( "Configuring for rectangle select" ); mTestGeometry = true; // Exact intersection test only applies for WKT geometries mTestGeometryExact = mRequest.flags() & QgsFeatureRequest::ExactIntersect && mSource->mGeomRep == QgsDelimitedTextProvider::GeomAsWkt; // If request doesn't overlap extents, then nothing to return if ( ! mFilterRect.intersects( mSource->mExtent ) && !mTestSubset ) { QgsDebugMsg( "Rectangle outside layer extents - no features to return" ); mMode = FeatureIds; } // If the request extents include the entire layer, then revert to // a file scan else if ( mFilterRect.contains( mSource->mExtent ) && !mTestSubset ) { QgsDebugMsg( "Rectangle contains layer extents - bypass spatial filter" ); mTestGeometry = false; } // If we have a spatial index then use it. The spatial index already accounts // for the subset. Also means we don't have to test geometries unless doing exact // intersection else if ( mSource->mUseSpatialIndex ) { mFeatureIds = mSource->mSpatialIndex->intersects( mFilterRect ); // Sort for efficient sequential retrieval std::sort( mFeatureIds.begin(), mFeatureIds.end() ); QgsDebugMsg( QString( "Layer has spatial index - selected %1 features from index" ).arg( mFeatureIds.size() ) ); mMode = FeatureIds; mTestSubset = false; mTestGeometry = mTestGeometryExact; } } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { QgsDebugMsg( "Configuring for returning single id" ); if ( mFilterRect.isNull() || mFeatureIds.contains( request.filterFid() ) ) { mFeatureIds = QList<QgsFeatureId>() << request.filterFid(); } mMode = FeatureIds; mTestSubset = false; } // If have geometry and testing geometry then evaluate options... // If we don't have geometry then all records pass geometry filter. // CC: 2013-05-09 // Not sure about intended relationship between filtering on geometry and // requesting no geometry? Have preserved current logic of ignoring spatial filter // if not requesting geometry. else // If we have a subset index then use it.. if ( mMode == FileScan && mSource->mUseSubsetIndex ) { QgsDebugMsg( QString( "Layer has subset index - use %1 items from subset index" ).arg( mSource->mSubsetIndex.size() ) ); mTestSubset = false; mMode = SubsetIndex; } // Otherwise just have to scan the file if ( mMode == FileScan ) { QgsDebugMsg( "File will be scanned for desired features" ); } // If the layer has geometry, do we really need to load it? // We need it if it is asked for explicitly in the request, // if we are testing geometry (ie spatial filter), or // if testing the subset expression. if ( hasGeometry && ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) || mTestGeometry || ( mTestSubset && mSource->mSubsetExpression->needsGeometry() ) || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) ) ) { mLoadGeometry = true; } else { QgsDebugMsgLevel( "Feature geometries not required", 4 ); mLoadGeometry = false; } // ensure that all attributes required for expression filter are being fetched if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && request.filterType() == QgsFeatureRequest::FilterExpression ) { QgsAttributeList attrs = request.subsetOfAttributes(); //ensure that all fields required for filter expressions are prepared QSet<int> attributeIndexes = request.filterExpression()->referencedAttributeIndexes( mSource->mFields ); attributeIndexes += attrs.toSet(); mRequest.setSubsetOfAttributes( attributeIndexes.toList() ); } // also need attributes required by order by if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() ) { QgsAttributeList attrs = request.subsetOfAttributes(); Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() ) { int attrIndex = mSource->mFields.lookupField( attr ); if ( !attrs.contains( attrIndex ) ) attrs << attrIndex; } mRequest.setSubsetOfAttributes( attrs ); }
void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request ) { // build sql statement mStatement = QString( "SELECT " ); mStatement += QString( "[%1]" ).arg( mSource->mFidColName ); mFidCol = mSource->mFields.indexFromName( mSource->mFidColName ); mAttributesToFetch.append( mFidCol ); bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; foreach ( int i, subsetOfAttributes ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList() ) { QString fieldname = mSource->mFields[i].name(); if ( mSource->mFidColName == fieldname ) continue; mStatement += QString( ",[%1]" ).arg( fieldname ); mAttributesToFetch.append( i ); } // get geometry col if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && mSource->isSpatial() ) { mStatement += QString( ",[%1]" ).arg( mSource->mGeometryColName ); } mStatement += QString( "FROM [%1].[%2]" ).arg( mSource->mSchemaName, mSource->mTableName ); bool filterAdded = false; // set spatial filter if ( request.filterType() == QgsFeatureRequest::FilterRect && mSource->isSpatial() && !request.filterRect().isEmpty() ) { // polygons should be CCW for SqlGeography QString r; QTextStream foo( &r ); foo.setRealNumberPrecision( 8 ); foo.setRealNumberNotation( QTextStream::FixedNotation ); foo << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ) << ", " << qgsDoubleToString( request.filterRect().xMaximum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ) << ", " << qgsDoubleToString( request.filterRect().xMaximum() ) << " " << qgsDoubleToString( request.filterRect().yMaximum() ) << ", " << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMaximum() ) << ", " << qgsDoubleToString( request.filterRect().xMinimum() ) << " " << qgsDoubleToString( request.filterRect().yMinimum() ); mStatement += QString( " where [%1].STIntersects([%2]::STGeomFromText('POLYGON((%3))',%4)) = 1" ).arg( mSource->mGeometryColName, mSource->mGeometryColType, r, QString::number( mSource->mSRId ) ); filterAdded = true; } // set fid filter if ( request.filterType() == QgsFeatureRequest::FilterFid && !mSource->mFidColName.isEmpty() ) { QString fidfilter = QString( " [%1] = %2" ).arg( mSource->mFidColName, QString::number( request.filterFid() ) ); // set attribute filter if ( !filterAdded ) mStatement += " WHERE "; else mStatement += " AND "; mStatement += fidfilter; filterAdded = true; } if ( !mSource->mSqlWhereClause.isEmpty() ) { if ( !filterAdded ) mStatement += " WHERE (" + mSource->mSqlWhereClause + ")"; else mStatement += " AND (" + mSource->mSqlWhereClause + ")"; } QgsDebugMsg( mStatement ); #if 0 if ( fieldCount == 0 ) { QgsDebugMsg( "QgsMssqlProvider::select no fields have been requested" ); mStatement.clear(); } #endif }
QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayer* layer, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), L( layer ), mEditGeometrySimplifier( NULL ) { QgsVectorLayerJoinBuffer* joinBuffer = L->mJoinBuffer; mChangedFeaturesRequest = mRequest; if ( L->editBuffer() ) { if ( request.filterType() == QgsFeatureRequest::FilterFid ) { // only copy relevant parts if( L->editBuffer()->addedFeatures().contains( request.filterFid() ) ) mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid() ] ); if( L->editBuffer()->changedGeometries().contains( request.filterFid() ) ) mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid() ] ); if( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) ) mDeletedFeatureIds.insert( request.filterFid() ); if( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) ) mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid() ] ); if( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) ) mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() ); } else { mAddedFeatures = QgsFeatureMap( L->editBuffer()->addedFeatures() ); mChangedGeometries = QgsGeometryMap( L->editBuffer()->changedGeometries() ); mDeletedFeatureIds = QgsFeatureIds( L->editBuffer()->deletedFeatureIds() ); mChangedAttributeValues = QgsChangedAttributesMap( L->editBuffer()->changedAttributeValues() ); mChangedFeaturesRequest.setFilterFids( L->editBuffer()->changedAttributeValues().keys().toSet() ); } mAddedAttributes = QList<QgsField>( L->editBuffer()->addedAttributes() ); mDeletedAttributeIds = QgsAttributeList( L->editBuffer()->deletedAttributeIds() ); } // prepare joins: may add more attributes to fetch (in order to allow join) if ( joinBuffer->containsJoins() ) prepareJoins(); // by default provider's request is the same mProviderRequest = mRequest; if ( mProviderRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { // prepare list of attributes to match provider fields QgsAttributeList providerSubset; QgsAttributeList subset = mProviderRequest.subsetOfAttributes(); const QgsFields &pendingFields = L->pendingFields(); int nPendingFields = pendingFields.count(); for ( int i = 0; i < subset.count(); ++i ) { int attrIndex = subset[i]; if ( attrIndex < 0 || attrIndex >= nPendingFields ) continue; if ( L->pendingFields().fieldOrigin( attrIndex ) == QgsFields::OriginProvider ) providerSubset << L->pendingFields().fieldOriginIndex( attrIndex ); } mProviderRequest.setSubsetOfAttributes( providerSubset ); } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { mFetchedFid = false; } else // no filter or filter by rect { if ( L->editBuffer() ) { mChangedFeaturesIterator = L->dataProvider()->getFeatures( mChangedFeaturesRequest ); } else { mProviderIterator = L->dataProvider()->getFeatures( mProviderRequest ); } rewindEditBuffer(); } if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression ) { mRequest.filterExpression()->prepare( L->pendingFields() ); } }
QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request ) : QgsAbstractFeatureIteratorFromSource<QgsVirtualLayerFeatureSource>( source, ownSource, request ) { // NOTE: this is really bad and should be removed. // it's only here to guard mSource->mSqlite - because if the provider is removed // then mSqlite will be meaningless. // this needs to be totally reworked so that mSqlite no longer depends on the provider // and can be fully encapsulated in the source if ( !mSource->mProvider ) { close(); return; } 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; } try { QString tableName = mSource->mTableName; QStringList wheres; QString offset; QString subset = mSource->mSubset; if ( !subset.isEmpty() ) { wheres << subset; } if ( !mSource->mDefinition.uid().isNull() ) { // filters are only available when a column with unique id exists if ( mSource->mDefinition.hasDefinedGeometry() && !mFilterRect.isNull() ) { bool do_exact = request.flags() & QgsFeatureRequest::ExactIntersect; QString mbr = QStringLiteral( "%1,%2,%3,%4" ).arg( mFilterRect.xMinimum() ).arg( mFilterRect.yMinimum() ).arg( mFilterRect.xMaximum() ).arg( mFilterRect.yMaximum() ); wheres << quotedColumn( mSource->mDefinition.geometryField() ) + " is not null"; wheres << QStringLiteral( "%1Intersects(%2,BuildMbr(%3))" ) .arg( do_exact ? "" : "Mbr", quotedColumn( mSource->mDefinition.geometryField() ), mbr ); } else if ( request.filterType() == QgsFeatureRequest::FilterFid ) { wheres << QStringLiteral( "%1=%2" ) .arg( quotedColumn( mSource->mDefinition.uid() ) ) .arg( request.filterFid() ); } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { QString values = quotedColumn( mSource->mDefinition.uid() ) + " IN ("; bool first = true; const auto constFilterFids = request.filterFids(); for ( QgsFeatureId v : constFilterFids ) { if ( !first ) { values += QLatin1String( "," ); } first = false; values += QString::number( v ); } values += QLatin1String( ")" ); wheres << values; } } else { if ( request.filterType() == QgsFeatureRequest::FilterFid ) { if ( request.filterFid() >= 0 ) offset = QStringLiteral( " LIMIT 1 OFFSET %1" ).arg( request.filterFid() ); else // never return a feature if the id is negative offset = QStringLiteral( " LIMIT 0" ); } else if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { // if an exact intersection is requested, prepare the geometry to intersect QgsGeometry rectGeom = QgsGeometry::fromRect( mFilterRect ); mRectEngine.reset( QgsGeometry::createGeometryEngine( rectGeom.constGet() ) ); mRectEngine->prepareGeometry(); } } if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes ) { // copy only selected fields const auto subsetOfAttributes = request.subsetOfAttributes(); for ( int idx : subsetOfAttributes ) { mAttributes << idx; } // ensure that all attributes required for expression filter are being fetched if ( request.filterType() == QgsFeatureRequest::FilterExpression ) { const auto constReferencedColumns = request.filterExpression()->referencedColumns(); for ( const QString &field : constReferencedColumns ) { int attrIdx = mSource->mFields.lookupField( field ); if ( !mAttributes.contains( attrIdx ) ) mAttributes << attrIdx; } } // also need attributes required by order by if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() ) { const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields ); for ( int attrIdx : usedAttributeIndices ) { if ( !mAttributes.contains( attrIdx ) ) mAttributes << attrIdx; } } } else { mAttributes = mSource->mFields.allAttributesList(); } QString columns; { // the first column is always the uid (or 0) if ( !mSource->mDefinition.uid().isNull() ) { columns = quotedColumn( mSource->mDefinition.uid() ); } else { if ( request.filterType() == QgsFeatureRequest::FilterFid ) { columns = QString::number( request.filterFid() ); } else { columns = QStringLiteral( "0" ); } } const auto constMAttributes = mAttributes; for ( int i : constMAttributes ) { columns += QLatin1String( "," ); QString cname = mSource->mFields.at( i ).name().toLower(); columns += quotedColumn( cname ); } } // the last column is the geometry, if any if ( ( !( request.flags() & QgsFeatureRequest::NoGeometry ) || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) ) && !mSource->mDefinition.geometryField().isNull() && mSource->mDefinition.geometryField() != QLatin1String( "*no*" ) ) { columns += "," + quotedColumn( mSource->mDefinition.geometryField() ); } mSqlQuery = "SELECT " + columns + " FROM " + tableName; if ( !wheres.isEmpty() ) { mSqlQuery += " WHERE " + wheres.join( QStringLiteral( " AND " ) ); } if ( !offset.isEmpty() ) { mSqlQuery += offset; } mQuery.reset( new Sqlite::Query( mSource->mSqlite, mSqlQuery ) ); mFid = 0; } catch ( std::runtime_error &e ) { QgsMessageLog::logMessage( e.what(), QObject::tr( "VLayer" ) ); close(); } }
QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* source, bool ownSource, const QgsFeatureRequest &request ) : QgsAbstractFeatureIteratorFromSource( source, ownSource, request ) , mRewind( false ) { mConnection = QgsOracleConn::connectDb( mSource->mUri.connectionInfo() ); if ( !mConnection ) { close(); return; } mQry = QSqlQuery( *mConnection ); if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { mAttributeList = mRequest.subsetOfAttributes(); if ( mAttributeList.isEmpty() ) mAttributeList = mSource->mFields.allAttributesList(); } else mAttributeList = mSource->mFields.allAttributesList(); QString whereClause; switch ( request.filterType() ) { case QgsFeatureRequest::FilterExpression: break; case QgsFeatureRequest::FilterRect: if ( !mSource->mGeometryColumn.isNull() ) { QgsRectangle rect( mRequest.filterRect() ); QString bbox = QString( "mdsys.sdo_geometry(2003,%1,NULL," "mdsys.sdo_elem_info_array(1,1003,3)," "mdsys.sdo_ordinate_array(%2,%3,%4,%5)" ")" ) .arg( mSource->mSrid < 1 ? "NULL" : QString::number( mSource->mSrid ) ) .arg( qgsDoubleToString( rect.xMinimum() ) ) .arg( qgsDoubleToString( rect.yMinimum() ) ) .arg( qgsDoubleToString( rect.xMaximum() ) ) .arg( qgsDoubleToString( rect.yMaximum() ) ); if ( !mSource->mSpatialIndex.isNull() ) { whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) ).arg( bbox ); #if 0 if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { whereClause += QString( " AND sdo_relate(%1,%2,'mask=ANYINTERACT')='TRUE'" ) .arg( quotedIdentifier( P->mGeometryColumn ) ) .arg( bbox ); } #endif } } break; case QgsFeatureRequest::FilterFid: whereClause = QgsOracleUtils::whereClause( request.filterFid(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared ); break; case QgsFeatureRequest::FilterFids: whereClause = QgsOracleUtils::whereClause( request.filterFids(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared ); break; case QgsFeatureRequest::FilterNone: break; } if ( mSource->mRequestedGeomType != QGis::WKBUnknown && mSource->mRequestedGeomType != mSource->mDetectedGeomType ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += QgsOracleConn::databaseTypeFilter( "featureRequest", mSource->mGeometryColumn, mSource->mRequestedGeomType ); } if ( !mSource->mSqlWhereClause.isEmpty() ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += "(" + mSource->mSqlWhereClause + ")"; } if ( !openQuery( whereClause ) ) return; }
QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleProvider *p, const QgsFeatureRequest &request ) : QgsAbstractFeatureIterator( request ) , P( p ) , mRewind( false ) { P->mActiveIterators << this; mQry = QSqlQuery( *P->mConnection ); if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { mAttributeList = mRequest.subsetOfAttributes(); if ( mAttributeList.isEmpty() ) mAttributeList = P->attributeIndexes(); } else mAttributeList = P->attributeIndexes(); QString whereClause; switch ( request.filterType() ) { case QgsFeatureRequest::FilterExpression: break; case QgsFeatureRequest::FilterRect: if ( !P->mGeometryColumn.isNull() ) { QgsRectangle rect( mRequest.filterRect() ); QString bbox = QString( "mdsys.sdo_geometry(2003,%1,NULL," "mdsys.sdo_elem_info_array(1,1003,3)," "mdsys.sdo_ordinate_array(%2,%3,%4,%5)" ")" ) .arg( P->mSrid < 1 ? "NULL" : QString::number( P->mSrid ) ) .arg( qgsDoubleToString( rect.xMinimum() ) ) .arg( qgsDoubleToString( rect.yMinimum() ) ) .arg( qgsDoubleToString( rect.xMaximum() ) ) .arg( qgsDoubleToString( rect.yMaximum() ) ); if ( !P->mSpatialIndex.isNull() ) { whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( P->quotedIdentifier( P->mGeometryColumn ) ).arg( bbox ); #if 0 if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) { whereClause += QString( " AND sdo_relate(%1,%2,'mask=ANYINTERACT')='TRUE'" ) .arg( quotedIdentifier( P->mGeometryColumn ) ) .arg( bbox ); } #endif } } break; case QgsFeatureRequest::FilterFid: whereClause = P->whereClause( request.filterFid() ); break; case QgsFeatureRequest::FilterFids: whereClause = P->whereClause( request.filterFids() ); break; case QgsFeatureRequest::FilterNone: break; } if ( P->mRequestedGeomType != QGis::WKBUnknown && P->mRequestedGeomType != P->mDetectedGeomType ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += QgsOracleConn::databaseTypeFilter( "featureRequest", P->mGeometryColumn, P->mRequestedGeomType ); } if ( !P->mSqlWhereClause.isEmpty() ) { if ( !whereClause.isEmpty() ) whereClause += " AND "; whereClause += "(" + P->mSqlWhereClause + ")"; } if ( !openQuery( whereClause ) ) return; }