Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Remove QgsFeatureRequest::FilterRect from providers/iterators
  • Loading branch information
m-kuhn committed Jul 29, 2015
1 parent 7571264 commit 5be0ee7
Show file tree
Hide file tree
Showing 21 changed files with 170 additions and 100 deletions.
7 changes: 6 additions & 1 deletion python/core/qgsvectorlayer.sip
Expand Up @@ -801,7 +801,12 @@ class QgsVectorLayer : QgsMapLayer
/** Return the extent of the layer as a QRect */
QgsRectangle extent();

/** Returns field list in the to-be-committed state */
/**
* Returns the list of fields of this layer.
* This also includes fields which have not yet been saved to the provider.
*
* @return A list of fields
*/
const QgsFields &pendingFields() const;

/** Returns list of attributes */
Expand Down
5 changes: 0 additions & 5 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -2220,11 +2220,6 @@ bool QgsVectorLayer::deleteFeature( QgsFeatureId fid )
return res;
}

const QgsFields &QgsVectorLayer::pendingFields() const
{
return mUpdatedFields;
}

QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
{
return mUpdatedFields.allAttributesList();
Expand Down
9 changes: 7 additions & 2 deletions src/core/qgsvectorlayer.h
Expand Up @@ -1300,8 +1300,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Return the extent of the layer as a QRect */
QgsRectangle extent() override;

/** Returns field list in the to-be-committed state */
const QgsFields &pendingFields() const;
/**
* Returns the list of fields of this layer.
* This also includes fields which have not yet been saved to the provider.
*
* @return A list of fields
*/
const QgsFields &pendingFields() const { return mUpdatedFields; }

/** Returns list of attributes */
QgsAttributeList pendingAllAttributesList();
Expand Down
15 changes: 6 additions & 9 deletions src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -176,7 +176,7 @@ bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature& f )
return res;
}

if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
if ( !mRequest.filterRect().isNull() )
{
if ( fetchNextChangedGeomFeature( f ) )
return true;
Expand Down Expand Up @@ -352,21 +352,18 @@ bool QgsVectorLayerFeatureIterator::fetchNextChangedAttributeFeature( QgsFeature
{
while ( mChangedFeaturesIterator.nextFeature( f ) )
{
if ( mFetchConsidered.contains( f.id() ) )
// skip deleted features and those already handled by the geometry
continue;

mFetchConsidered << f.id();

updateChangedAttributes( f );

if ( mHasVirtualAttributes )
addVirtualAttributes( f );

if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
{
if ( mRequest.filterExpression()->evaluate( &f ).toBool() )
{
return true;
}
}
else
if ( mRequest.filterExpression()->evaluate( &f ).toBool() )
{
return true;
}
Expand Down
1 change: 1 addition & 0 deletions src/core/qgsvectorlayerrenderer.cpp
Expand Up @@ -136,6 +136,7 @@ bool QgsVectorLayerRenderer::render()

QgsRenderOptions opts = mRendererV2->startRender( mContext, mFields );

QgsDebugMsg( opts.whereClause() );
QgsRectangle requestExtent = mContext.extent();
mRendererV2->modifyRequestExtent( requestExtent, mContext );

Expand Down
42 changes: 24 additions & 18 deletions src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
Expand Up @@ -44,21 +44,8 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
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 )
if ( !request.filterRect().isNull() && hasGeometry )
{
QgsDebugMsg( "Configuring for rectangle select" );
mTestGeometry = true;
Expand Down Expand Up @@ -98,13 +85,32 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe
}
}

// If we have a subset index then use it..
if ( mMode == FileScan && mSource->mUseSubsetIndex )
if ( request.filterType() == QgsFeatureRequest::FilterFid )
{
QgsDebugMsg( QString( "Layer has subset index - use %1 items from subset index" ).arg( mSource->mSubsetIndex.size() ) );
QgsDebugMsg( "Configuring for returning single id" );
if ( request.filterRect().isNull() || ( !request.filterRect().isNull() && mFeatureIds.contains( request.filterFid() ) ) )
{
mFeatureIds = QList<QgsFeatureId>() << request.filterFid();
}
mMode = FeatureIds;
mTestSubset = false;
mMode = SubsetIndex;
}
// 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 )
Expand Down
6 changes: 3 additions & 3 deletions src/providers/gpx/qgsgpxfeatureiterator.cpp
Expand Up @@ -176,7 +176,7 @@ bool QgsGPXFeatureIterator::readFid( QgsFeature& feature )

bool QgsGPXFeatureIterator::readWaypoint( const QgsWaypoint& wpt, QgsFeature& feature )
{
if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
if ( !mRequest.filterRect().isNull() )
{
const QgsRectangle& rect = mRequest.filterRect();
if ( ! rect.contains( QgsPoint( wpt.lon, wpt.lat ) ) )
Expand Down Expand Up @@ -206,7 +206,7 @@ bool QgsGPXFeatureIterator::readRoute( const QgsRoute& rte, QgsFeature& feature

QgsGeometry* theGeometry = readRouteGeometry( rte );

if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
if ( !mRequest.filterRect().isNull() )
{
const QgsRectangle& rect = mRequest.filterRect();
if (( rte.xMax < rect.xMinimum() ) || ( rte.xMin > rect.xMaximum() ) ||
Expand Down Expand Up @@ -248,7 +248,7 @@ bool QgsGPXFeatureIterator::readTrack( const QgsTrack& trk, QgsFeature& feature

QgsGeometry* theGeometry = readTrackGeometry( trk );

if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
if ( !mRequest.filterRect().isNull() )
{
const QgsRectangle& rect = mRequest.filterRect();
if (( trk.xMax < rect.xMinimum() ) || ( trk.xMin > rect.xMaximum() ) ||
Expand Down
2 changes: 1 addition & 1 deletion src/providers/grass/qgsgrassfeatureiterator.cpp
Expand Up @@ -80,7 +80,7 @@ QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassFeatureSource* source,
allocateSelection( mSource->mMap );
resetSelection( 1 );

if ( request.filterType() == QgsFeatureRequest::FilterRect )
if ( !request.filterRect().isNull() )
{
setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect );
}
Expand Down
8 changes: 4 additions & 4 deletions src/providers/memory/qgsmemoryfeatureiterator.cpp
Expand Up @@ -33,14 +33,14 @@ QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource* sour
mSubsetExpression->prepare( mSource->mFields );
}

if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
if ( !mRequest.filterRect().isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
mSelectRectGeom = QgsGeometry::fromRect( request.filterRect() );
}

// if there's spatial index, use it!
// (but don't use it when selection rect is not specified)
if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && mSource->mSpatialIndex )
if ( !mRequest.filterRect().isNull() && mSource->mSpatialIndex )
{
mUsingFeatureIdList = true;
mFeatureIdList = mSource->mSpatialIndex->intersects( mRequest.filterRect() );
Expand Down Expand Up @@ -90,7 +90,7 @@ bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature& feature )
// option 1: we have a list of features to traverse
while ( mFeatureIdListIterator != mFeatureIdList.constEnd() )
{
if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
if ( !mRequest.filterRect().isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect )
{
// do exact check in case we're doing intersection
if ( mSource->mFeatures[*mFeatureIdListIterator].geometry() && mSource->mFeatures[*mFeatureIdListIterator].geometry()->intersects( mSelectRectGeom ) )
Expand Down Expand Up @@ -131,7 +131,7 @@ bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature& feature )
// option 2: traversing the whole layer
while ( mSelectIterator != mSource->mFeatures.constEnd() )
{
if ( mRequest.filterType() != QgsFeatureRequest::FilterRect )
if ( mRequest.filterRect().isNull() )
{
// selection rect empty => using all features
hasFeature = true;
Expand Down
2 changes: 1 addition & 1 deletion src/providers/mssql/qgsmssqlfeatureiterator.cpp
Expand Up @@ -89,7 +89,7 @@ void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request )

bool filterAdded = false;
// set spatial filter
if ( request.filterType() == QgsFeatureRequest::FilterRect && mSource->isSpatial() && !request.filterRect().isEmpty() )
if ( !request.filterRect().isNull() && mSource->isSpatial() && !request.filterRect().isEmpty() )
{
// polygons should be CCW for SqlGeography
QString r;
Expand Down
8 changes: 4 additions & 4 deletions src/providers/ogr/qgsogrfeatureiterator.cpp
Expand Up @@ -58,20 +58,20 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
mSubsetStringSet = true;
}

mFetchGeometry = ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) || !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
mFetchGeometry = ( !mRequest.filterRect().isNull() ) || !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
QgsAttributeList attrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();

// make sure we fetch just relevant fields
// unless it's a VRT data source filtered by geometry as we don't know which
// attributes make up the geometry and OGR won't fetch them to evaluate the
// filter if we choose to ignore them (fixes #11223)
if (( mSource->mDriverName != "VRT" && mSource->mDriverName != "OGR_VRT" ) || mRequest.filterType() != QgsFeatureRequest::FilterRect )
if (( mSource->mDriverName != "VRT" && mSource->mDriverName != "OGR_VRT" ) || mRequest.filterRect().isNull() )
{
QgsOgrUtils::setRelevantFields( ogrLayer, mSource->mFields.count(), mFetchGeometry, attrs );
}

// spatial query to select features
if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
if ( !mRequest.filterRect().isNull() )
{
const QgsRectangle& rect = mRequest.filterRect();

Expand Down Expand Up @@ -179,7 +179,7 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
if ( !readFeature( fet, feature ) )
continue;

if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && !feature.constGeometry() )
if ( !mRequest.filterRect().isNull() && !feature.constGeometry() )
continue;

// we have a feature, end this cycle
Expand Down
62 changes: 33 additions & 29 deletions src/providers/oracle/qgsoraclefeatureiterator.cpp
Expand Up @@ -46,45 +46,49 @@ QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* sour

QString whereClause;

if ( !mRequest.filterRect().isNull && !mSource->mGeometryColumn.isNull() && mSource->mHasSpatialIndex )
{
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() ) );

whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) ).arg( bbox );

if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect && mConnection->hasSpatial() )
{
whereClause += QString( " AND sdo_relate(%1,%2,'mask=ANYINTERACT')='TRUE'" )
.arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) )
.arg( bbox );
}
}

switch ( request.filterType() )
{
case QgsFeatureRequest::FilterExpression:
case QgsFeatureRequest::FilterFid:
QString fidWhereClause = QgsOracleUtils::whereClause( request.filterFid(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidWhereClause );
break;

case QgsFeatureRequest::FilterRect:
if ( !mSource->mGeometryColumn.isNull() && mSource->mHasSpatialIndex )
{
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() ) );

whereClause = QString( "sdo_filter(%1,%2)='TRUE'" ).arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) ).arg( bbox );

if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect && mConnection->hasSpatial() )
{
whereClause += QString( " AND sdo_relate(%1,%2,'mask=ANYINTERACT')='TRUE'" )
.arg( QgsOracleProvider::quotedIdentifier( mSource->mGeometryColumn ) )
.arg( bbox );
}
}
case QgsFeatureRequest::FilterFids:
QString fidsWhereClause = QgsOracleUtils::whereClause( request.filterFids(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidsWhereClause );
break;

case QgsFeatureRequest::FilterFid:
whereClause = QgsOracleUtils::whereClause( request.filterFid(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
case QgsFeatureRequest::FilterNone:
break;

case QgsFeatureRequest::FilterFids:
whereClause = QgsOracleUtils::whereClause( request.filterFids(), mSource->mFields, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
case QgsFeatureRequest::FilterExpression:
break;

case QgsFeatureRequest::FilterNone:
case QgsFeatureRequest::FilterRect:
// Handled in the if-statement above
break;
}

Expand Down
9 changes: 9 additions & 0 deletions src/providers/oracle/qgsoracleprovider.cpp
Expand Up @@ -464,6 +464,15 @@ QString QgsOracleUtils::whereClause( QgsFeatureIds featureIds, const QgsFields &
return whereClauses.isEmpty() ? "" : whereClauses.join( " OR " ).prepend( "(" ).append( ")" );
}

QString QgsOracleUtils::andWhereClauses( const QString& c1, const QString& c2 )
{
if ( c1.isNull() )
return c2;
if ( c2.isNull() )
return c1;

return QString( "(%1) AND (%2)" ).arg( c1 ).arg( c2 );
}

QString QgsOracleProvider::whereClause( QgsFeatureId featureId ) const
{
Expand Down
2 changes: 2 additions & 0 deletions src/providers/oracle/qgsoracleprovider.h
Expand Up @@ -423,6 +423,8 @@ class QgsOracleUtils
QgsOraclePrimaryKeyType primaryKeyType,
const QList<int>& primaryKeyAttrs,
QSharedPointer<QgsOracleSharedData> sharedData );

static QString andWhereClauses( const QString& c1, const QString& c2 );
};


Expand Down
25 changes: 24 additions & 1 deletion src/providers/postgres/qgspostgresexpressioncompiler.cpp
Expand Up @@ -184,9 +184,32 @@ QgsPostgresExpressionCompiler::Result QgsPostgresExpressionCompiler::compile( co
return Complete;
}

case QgsExpression::ntInOperator:
{
const QgsExpression::NodeInOperator* n = static_cast<const QgsExpression::NodeInOperator*>( node );
QStringList list;

Q_FOREACH ( const QgsExpression::Node* ln, n->list()->list() )
{
QString s;
Result r = compile( ln, s );
if ( r == Complete )
list << s;
else
return r;
}

QString nd;
Result rn = compile( n->node(), nd );
if ( rn != Complete )
return rn;

result = QString( "%1 %2IN(%3)" ).arg( nd ).arg( n->isNotIn() ? "NOT " : "" ).arg( list.join( "," ) );
return Complete;
}

case QgsExpression::ntFunction:
case QgsExpression::ntCondition:
case QgsExpression::ntInOperator:
break;
}

Expand Down

0 comments on commit 5be0ee7

Please sign in to comment.