void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context ) { mEditorContext = context; connect( mTableView, SIGNAL( willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT( viewWillShowContextMenu( QMenu*, QModelIndex ) ) ); initLayerCache( layer, !request.filterRect().isNull() ); initModels( mapCanvas, request ); mConditionalFormatWidget->setLayer( layer ); mTableView->setModel( mFilterModel ); mFeatureList->setModel( mFeatureListModel ); mAttributeForm = new QgsAttributeForm( layer, QgsFeature(), mEditorContext ); if ( !mAttributeEditorScrollArea->layout() ) mAttributeEditorScrollArea->setLayout( new QGridLayout() ); mAttributeEditorScrollArea->layout()->addWidget( mAttributeForm ); mAttributeEditorScrollArea->setWidget( mAttributeForm ); mAttributeForm->hideButtonBox(); connect( mAttributeForm, SIGNAL( attributeChanged( QString, QVariant ) ), this, SLOT( featureFormAttributeChanged() ) ); connect( mMasterModel, SIGNAL( modelChanged() ), mAttributeForm, SLOT( refreshFeature() ) ); if ( mFeatureListPreviewButton->defaultAction() ) mFeatureList->setDisplayExpression( mDisplayExpression ); else columnBoxInit(); // This slows down load of the attribute table heaps and uses loads of memory. //mTableView->resizeColumnsToContents(); mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) ); }
QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>( source, ownSource, request ) { sMutex.lock(); // Init structures mPoints = Vect_new_line_struct(); mCats = Vect_new_cats_struct(); mList = Vect_new_list(); // Create selection array allocateSelection( mSource->mMap ); resetSelection( 1 ); if ( request.filterType() == QgsFeatureRequest::FilterRect ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { // TODO: implement fast lookup by feature id //no filter - use all features resetSelection( 1 ); } }
QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassProvider* p, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), P( p ) { // 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( "GRASS" ) ); P->mActiveIterator->close(); } P->mActiveIterator = this; // check if outdated and update if necessary P->ensureUpdated(); // Init structures mPoints = Vect_new_line_struct(); mCats = Vect_new_cats_struct(); mList = Vect_new_list(); // Create selection array allocateSelection( P->mMap ); resetSelection( 1 ); if ( request.filterType() == QgsFeatureRequest::FilterRect ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { // TODO: implement fast lookup by feature id //no filter - use all features resetSelection( 1 ); } }
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(); }
void QgsDualView::updateSelectedFeatures() { QgsFeatureRequest r = mMasterModel->request(); if ( r.filterType() == QgsFeatureRequest::FilterNone && r.filterRect().isNull() ) return; // already requested all features r.setFilterFids( masterModel()->layer()->selectedFeatureIds() ); mMasterModel->setRequest( r ); mMasterModel->loadLayer(); emit filterChanged(); }
void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context, bool loadFeatures ) { if ( !layer ) return; mLayer = layer; mEditorContext = context; connect( mTableView, &QgsAttributeTableView::willShowContextMenu, this, &QgsDualView::viewWillShowContextMenu ); mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu ); connect( mTableView->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QgsDualView::showViewHeaderMenu ); connect( mTableView, &QgsAttributeTableView::columnResized, this, &QgsDualView::tableColumnResized ); connect( mFeatureList, &QgsFeatureListView::willShowContextMenu, this, &QgsDualView::widgetWillShowContextMenu ); initLayerCache( !( request.flags() & QgsFeatureRequest::NoGeometry ) || !request.filterRect().isNull() ); initModels( mapCanvas, request, loadFeatures ); mConditionalFormatWidget->setLayer( mLayer ); mTableView->setModel( mFilterModel ); mFeatureList->setModel( mFeatureListModel ); delete mAttributeForm; mAttributeForm = new QgsAttributeForm( mLayer, mTempAttributeFormFeature, mEditorContext ); mTempAttributeFormFeature = QgsFeature(); if ( !context.parentContext() ) { mAttributeEditorScrollArea = new QgsScrollArea(); mAttributeEditorScrollArea->setWidgetResizable( true ); mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea ); mAttributeEditorScrollArea->setWidget( mAttributeForm ); } else { mAttributeEditor->layout()->addWidget( mAttributeForm ); } connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged ); connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged ); connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature ); connect( mAttributeForm, &QgsAttributeForm::filterExpressionSet, this, &QgsDualView::filterExpressionSet ); connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged ); if ( mFeatureListPreviewButton->defaultAction() ) mFeatureList->setDisplayExpression( mDisplayExpression ); else columnBoxInit(); // This slows down load of the attribute table heaps and uses loads of memory. //mTableView->resizeColumnsToContents(); mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) ); }
QgsGrassFeatureIterator::QgsGrassFeatureIterator( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>( source, ownSource, request ) , mCanceled( false ) , mNextCidx( 0 ) , mNextLid( 1 ) { QgsDebugMsg( "entered" ); // WARNING: the iterater cannot use mutex lock for its whole life, because QgsVectorLayerFeatureIterator is opening // multiple iterators if features are edited -> lock only critical sections // Create selection int size = 1 + qMax( Vect_get_num_lines( mSource->map() ), Vect_get_num_areas( mSource->map() ) ); QgsDebugMsg( QString( "mSelection.resize(%1)" ).arg( size ) ); mSelection.resize( size ); if ( !request.filterRect().isNull() ) { setSelectionRect( request.filterRect(), request.flags() & QgsFeatureRequest::ExactIntersect ); } else { //no filter - use all features mSelection.fill( true ); } connect( mSource->mLayer->map(), SIGNAL( cancelIterators() ), this, SLOT( cancel() ), Qt::DirectConnection ); Qt::ConnectionType connectionType = Qt::DirectConnection; if ( mSource->mLayer->map()->thread() != thread() ) { // Using BlockingQueuedConnection may be dangerous, if the iterator was later moved to maps thread, it would cause dead lock on emit closeIterators() QgsDebugMsg( "map and iterator are on different threads -> connect closeIterators() with BlockingQueuedConnection" ); connectionType = Qt::BlockingQueuedConnection; } connect( mSource->mLayer->map(), SIGNAL( closeIterators() ), this, SLOT( doClose() ), connectionType ); }
void QgsDualView::init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsFeatureRequest &request, const QgsAttributeEditorContext &context ) { if ( !layer ) return; mEditorContext = context; connect( mTableView, SIGNAL( willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT( viewWillShowContextMenu( QMenu*, QModelIndex ) ) ); mTableView->horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu ); connect( mTableView->horizontalHeader(), SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( showViewHeaderMenu( QPoint ) ) ); connect( mTableView, SIGNAL( columnResized( int, int ) ), this, SLOT( tableColumnResized( int, int ) ) ); initLayerCache( layer, !request.filterRect().isNull() ); initModels( mapCanvas, request ); mConditionalFormatWidget->setLayer( layer ); mTableView->setModel( mFilterModel ); mFeatureList->setModel( mFeatureListModel ); delete mAttributeForm; mAttributeForm = new QgsAttributeForm( layer, QgsFeature(), mEditorContext ); if ( !context.parentContext() ) { mAttributeEditorScrollArea = new QScrollArea(); mAttributeEditorScrollArea->setWidgetResizable( true ); mAttributeEditor->layout()->addWidget( mAttributeEditorScrollArea ); mAttributeEditorScrollArea->setWidget( mAttributeForm ); } else { mAttributeEditor->layout()->addWidget( mAttributeForm ); } connect( mAttributeForm, SIGNAL( attributeChanged( QString, QVariant ) ), this, SLOT( featureFormAttributeChanged() ) ); connect( mAttributeForm, SIGNAL( modeChanged( QgsAttributeForm::Mode ) ), this, SIGNAL( formModeChanged( QgsAttributeForm::Mode ) ) ); connect( mMasterModel, SIGNAL( modelChanged() ), mAttributeForm, SLOT( refreshFeature() ) ); connect( mAttributeForm, SIGNAL( filterExpressionSet( QString, QgsAttributeForm::FilterType ) ), this, SIGNAL( filterExpressionSet( QString, QgsAttributeForm::FilterType ) ) ); connect( mFilterModel, SIGNAL( sortColumnChanged( int, Qt::SortOrder ) ), this, SLOT( onSortColumnChanged() ) ); if ( mFeatureListPreviewButton->defaultAction() ) mFeatureList->setDisplayExpression( mDisplayExpression ); else columnBoxInit(); // This slows down load of the attribute table heaps and uses loads of memory. //mTableView->resizeColumnsToContents(); mFeatureList->setEditSelection( QgsFeatureIds() << mFeatureListModel->idxToFid( mFeatureListModel->index( 0, 0 ) ) ); }
QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsSpatiaLiteFeatureSource>( source, ownSource, request ) , sqliteStatement( NULL ) { mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath ); mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty(); mRowNumber = 0; QString whereClause; if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() ) { // some kind of MBR spatial filtering is required whereClause += whereClauseRect(); } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause += whereClauseFid(); } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause += whereClauseFids(); } if ( !mSource->mSubsetString.isEmpty() ) { if ( !whereClause.isEmpty() ) { whereClause += " AND "; } whereClause += "( " + mSource->mSubsetString + ")"; } // preparing the SQL statement if ( !prepareStatement( whereClause ) ) { // some error occurred sqliteStatement = NULL; close(); return; } }
QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsMemoryFeatureSource>( source, ownSource, request ) , mSelectRectGeom( nullptr ) , mSubsetExpression( nullptr ) { if ( !mSource->mSubsetString.isEmpty() ) { mSubsetExpression = new QgsExpression( mSource->mSubsetString ); mSubsetExpression->prepare( &mSource->mExpressionContext ); } 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.filterRect().isNull() && mSource->mSpatialIndex ) { mUsingFeatureIdList = true; mFeatureIdList = mSource->mSpatialIndex->intersects( mRequest.filterRect() ); QgsDebugMsg( "Features returned by spatial index: " + QString::number( mFeatureIdList.count() ) ); } else if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { mUsingFeatureIdList = true; QgsFeatureMap::const_iterator it = mSource->mFeatures.constFind( mRequest.filterFid() ); if ( it != mSource->mFeatures.constEnd() ) mFeatureIdList.append( mRequest.filterFid() ); } else { mUsingFeatureIdList = false; } rewind(); }
QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryProvider* p, const QgsFeatureRequest& request ) : QgsAbstractFeatureIterator( request ), P( p ), mSelectRectGeom( NULL ) { // 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( "Memory provider" ) ); P->mActiveIterator->close(); } P->mActiveIterator = this; if ( mRequest.filterType() == QgsFeatureRequest::FilterRect && 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 && P->mSpatialIndex ) { mUsingFeatureIdList = true; mFeatureIdList = P->mSpatialIndex->intersects( mRequest.filterRect() ); QgsDebugMsg( "Features returned by spatial index: " + QString::number( mFeatureIdList.count() ) ); } else if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { mUsingFeatureIdList = true; QgsFeatureMap::iterator it = P->mFeatures.find( mRequest.filterFid() ); if ( it != P->mFeatures.end() ) mFeatureIdList.append( mRequest.filterFid() ); } else { mUsingFeatureIdList = false; } rewind(); }
QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsSpatiaLiteFeatureSource>( source, ownSource, request ) , sqliteStatement( NULL ) , mExpressionCompiled( false ) { mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath ); mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty(); mRowNumber = 0; QStringList whereClauses; QString whereClause; if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() ) { // some kind of MBR spatial filtering is required whereClause = whereClauseRect(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = whereClauseFid(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause = whereClauseFids(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } else if ( request.filterType() == QgsFeatureRequest::FilterExpression && QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { QgsSpatiaLiteExpressionCompiler compiler = QgsSpatiaLiteExpressionCompiler( source ); QgsSqlExpressionCompiler::Result result = compiler.compile( request.filterExpression() ); if ( result == QgsSqlExpressionCompiler::Complete || result == QgsSqlExpressionCompiler::Partial ) { whereClause = compiler.result(); if ( !whereClause.isEmpty() ) { whereClauses.append( whereClause ); //if only partial success when compiling expression, we need to double-check results using QGIS' expressions mExpressionCompiled = ( result == QgsSqlExpressionCompiler::Complete ); } } } if ( !mSource->mSubsetString.isEmpty() ) { whereClause = "( " + mSource->mSubsetString + ')'; if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } whereClause = whereClauses.join( " AND " ); // preparing the SQL statement if ( !prepareStatement( whereClause ) ) { // some error occurred sqliteStatement = NULL; close(); return; } }
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(); }
QgsFeatureIterator QgsWFSFeatureSource::getFeatures( const QgsFeatureRequest& request ) { if ( !request.filterRect().isNull() ) emit extentRequested( request.filterRect() ); return QgsFeatureIterator( new QgsWFSFeatureIterator( this, false, request ) ); }
QgsFeatureRequest parseFilterElement( const QString &typeName, QDomElement &filterElem, const QgsProject *project ) { QgsFeatureRequest request; QDomNodeList fidNodes = filterElem.elementsByTagName( QStringLiteral( "FeatureId" ) ); QDomNodeList goidNodes = filterElem.elementsByTagName( QStringLiteral( "GmlObjectId" ) ); if ( !fidNodes.isEmpty() ) { QgsFeatureIds fids; QDomElement fidElem; for ( int f = 0; f < fidNodes.size(); f++ ) { fidElem = fidNodes.at( f ).toElement(); if ( !fidElem.hasAttribute( QStringLiteral( "fid" ) ) ) { throw QgsRequestNotWellFormedException( "FeatureId element without fid attribute" ); } QString fid = fidElem.attribute( QStringLiteral( "fid" ) ); if ( fid.contains( QLatin1String( "." ) ) ) { if ( fid.section( QStringLiteral( "." ), 0, 0 ) != typeName ) continue; fid = fid.section( QStringLiteral( "." ), 1, 1 ); } fids.insert( fid.toInt() ); } if ( !fids.isEmpty() ) { request.setFilterFids( fids ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "No FeatureId element correctly parse against typeName '%1'" ).arg( typeName ) ); } request.setFlags( QgsFeatureRequest::NoFlags ); return request; } else if ( !goidNodes.isEmpty() ) { QgsFeatureIds fids; QDomElement goidElem; for ( int f = 0; f < goidNodes.size(); f++ ) { goidElem = goidNodes.at( f ).toElement(); if ( !goidElem.hasAttribute( QStringLiteral( "id" ) ) && !goidElem.hasAttribute( QStringLiteral( "gml:id" ) ) ) { throw QgsRequestNotWellFormedException( "GmlObjectId element without gml:id attribute" ); } QString fid = goidElem.attribute( QStringLiteral( "id" ) ); if ( fid.isEmpty() ) fid = goidElem.attribute( QStringLiteral( "gml:id" ) ); if ( fid.contains( QLatin1String( "." ) ) ) { if ( fid.section( QStringLiteral( "." ), 0, 0 ) != typeName ) continue; fid = fid.section( QStringLiteral( "." ), 1, 1 ); } fids.insert( fid.toInt() ); } if ( !fids.isEmpty() ) { request.setFilterFids( fids ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "No GmlObjectId element correctly parse against typeName '%1'" ).arg( typeName ) ); } request.setFlags( QgsFeatureRequest::NoFlags ); return request; } else if ( filterElem.firstChildElement().tagName() == QLatin1String( "BBOX" ) ) { QDomElement bboxElem = filterElem.firstChildElement(); QDomElement childElem = bboxElem.firstChildElement(); while ( !childElem.isNull() ) { if ( childElem.tagName() == QLatin1String( "Box" ) ) { request.setFilterRect( QgsOgcUtils::rectangleFromGMLBox( childElem ) ); } else if ( childElem.tagName() != QLatin1String( "PropertyName" ) ) { QgsGeometry geom = QgsOgcUtils::geometryFromGML( childElem ); request.setFilterRect( geom.boundingBox() ); } childElem = childElem.nextSiblingElement(); } request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags ); return request; } // Apply BBOX through filterRect even inside an And to use spatial index else if ( filterElem.firstChildElement().tagName() == QLatin1String( "And" ) && !filterElem.firstChildElement().firstChildElement( QLatin1String( "BBOX" ) ).isNull() ) { QDomElement childElem = filterElem.firstChildElement().firstChildElement(); while ( !childElem.isNull() ) { QDomElement childFilterElement = filterElem.ownerDocument().createElement( QLatin1String( "Filter" ) ); childFilterElement.appendChild( childElem.cloneNode( true ) ); QgsFeatureRequest childRequest = parseFilterElement( typeName, childFilterElement ); if ( childElem.tagName() == QLatin1String( "BBOX" ) ) { if ( request.filterRect().isEmpty() ) { request.setFilterRect( childRequest.filterRect() ); } else { request.setFilterRect( request.filterRect().intersect( childRequest.filterRect() ) ); } } else { if ( !request.filterExpression() ) { request.setFilterExpression( childRequest.filterExpression()->expression() ); } else { QgsExpressionNode *opLeft = request.filterExpression()->rootNode()->clone(); QgsExpressionNode *opRight = childRequest.filterExpression()->rootNode()->clone(); std::unique_ptr<QgsExpressionNodeBinaryOperator> node = qgis::make_unique<QgsExpressionNodeBinaryOperator>( QgsExpressionNodeBinaryOperator::boAnd, opLeft, opRight ); QgsExpression expr( node->dump() ); request.setFilterExpression( expr ); } } childElem = childElem.nextSiblingElement(); } request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags ); return request; } else { QgsVectorLayer *layer = nullptr; if ( project != nullptr ) { layer = layerByTypeName( project, typeName ); } std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem, layer ) ); if ( filter ) { if ( filter->hasParserError() ) { throw QgsRequestNotWellFormedException( filter->parserErrorString() ); } if ( filter->needsGeometry() ) { request.setFlags( QgsFeatureRequest::NoFlags ); } request.setFilterExpression( filter->expression() ); return request; } } return request; }
QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsSpatiaLiteFeatureSource>( source, ownSource, request ) , sqliteStatement( nullptr ) , mExpressionCompiled( false ) { mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath ); mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty(); mRowNumber = 0; QStringList whereClauses; bool useFallbackWhereClause = false; QString fallbackWhereClause; QString whereClause; //beware - limitAtProvider needs to be set to false if the request cannot be completely handled //by the provider (eg utilising QGIS expression filters) bool limitAtProvider = ( mRequest.limit() >= 0 ); if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() ) { // some kind of MBR spatial filtering is required whereClause = whereClauseRect(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( !mSource->mSubsetString.isEmpty() ) { whereClause = "( " + mSource->mSubsetString + ')'; if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = whereClauseFid(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause = whereClauseFids(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } //IMPORTANT - this MUST be the last clause added! else if ( request.filterType() == QgsFeatureRequest::FilterExpression ) { // ensure that all attributes required for expression filter are being fetched if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && request.filterType() == QgsFeatureRequest::FilterExpression ) { QgsAttributeList attrs = request.subsetOfAttributes(); Q_FOREACH ( const QString& field, request.filterExpression()->referencedColumns() ) { int attrIdx = mSource->mFields.fieldNameIndex( field ); if ( !attrs.contains( attrIdx ) ) attrs << attrIdx; } mRequest.setSubsetOfAttributes( attrs ); } if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { QgsSpatiaLiteExpressionCompiler compiler = QgsSpatiaLiteExpressionCompiler( source ); QgsSqlExpressionCompiler::Result result = compiler.compile( request.filterExpression() ); if ( result == QgsSqlExpressionCompiler::Complete || result == QgsSqlExpressionCompiler::Partial ) { whereClause = compiler.result(); if ( !whereClause.isEmpty() ) { useFallbackWhereClause = true; fallbackWhereClause = whereClauses.join( " AND " ); whereClauses.append( whereClause ); //if only partial success when compiling expression, we need to double-check results using QGIS' expressions mExpressionCompiled = ( result == QgsSqlExpressionCompiler::Complete ); } } if ( result != QgsSqlExpressionCompiler::Complete ) { //can't apply limit at provider side as we need to check all results using QGIS expressions limitAtProvider = false; } } else { limitAtProvider = false; } }
void QgsDualView::extentChanged() { QgsFeatureRequest r = mMasterModel->request(); if ( mFilterModel->mapCanvas() && ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) ) { QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() ); r.setFilterRect( rect ); mMasterModel->setRequest( r ); mMasterModel->loadLayer(); } emit filterChanged(); }
void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filterMode ) { // cleanup any existing connections switch ( mFilterModel->filterMode() ) { case QgsAttributeTableFilterModel::ShowVisible: disconnect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged ); break; case QgsAttributeTableFilterModel::ShowAll: case QgsAttributeTableFilterModel::ShowEdited: case QgsAttributeTableFilterModel::ShowFilteredList: break; case QgsAttributeTableFilterModel::ShowSelected: disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures ); break; } QgsFeatureRequest r = mMasterModel->request(); bool needsGeometry = filterMode == QgsAttributeTableFilterModel::ShowVisible; bool requiresTableReload = ( r.filterType() != QgsFeatureRequest::FilterNone || !r.filterRect().isNull() ) // previous request was subset || ( needsGeometry && r.flags() & QgsFeatureRequest::NoGeometry ) // no geometry for last request || ( mMasterModel->rowCount() == 0 ); // no features if ( !needsGeometry ) r.setFlags( r.flags() | QgsFeatureRequest::NoGeometry ); else r.setFlags( r.flags() & ~( QgsFeatureRequest::NoGeometry ) ); r.setFilterFids( QgsFeatureIds() ); r.setFilterRect( QgsRectangle() ); r.disableFilter(); // setup new connections and filter request parameters switch ( filterMode ) { case QgsAttributeTableFilterModel::ShowVisible: connect( mFilterModel->mapCanvas(), &QgsMapCanvas::extentsChanged, this, &QgsDualView::extentChanged ); if ( mFilterModel->mapCanvas() ) { QgsRectangle rect = mFilterModel->mapCanvas()->mapSettings().mapToLayerCoordinates( mLayer, mFilterModel->mapCanvas()->extent() ); r.setFilterRect( rect ); } break; case QgsAttributeTableFilterModel::ShowAll: case QgsAttributeTableFilterModel::ShowEdited: case QgsAttributeTableFilterModel::ShowFilteredList: break; case QgsAttributeTableFilterModel::ShowSelected: connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures ); r.setFilterFids( masterModel()->layer()->selectedFeatureIds() ); break; } if ( requiresTableReload ) { mMasterModel->setRequest( r ); whileBlocking( mLayerCache )->setCacheGeometry( needsGeometry ); mMasterModel->loadLayer(); } //update filter model mFilterModel->setFilterMode( filterMode ); emit filterChanged(); }
QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsSpatiaLiteFeatureSource>( source, ownSource, request ) , sqliteStatement( nullptr ) , mExpressionCompiled( false ) { mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath ); mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty(); mRowNumber = 0; QStringList whereClauses; bool useFallbackWhereClause = false; QString fallbackWhereClause; QString whereClause; //beware - limitAtProvider needs to be set to false if the request cannot be completely handled //by the provider (eg utilising QGIS expression filters) bool limitAtProvider = ( mRequest.limit() >= 0 ); if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() ) { // some kind of MBR spatial filtering is required whereClause = whereClauseRect(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( !mSource->mSubsetString.isEmpty() ) { whereClause = "( " + mSource->mSubsetString + ')'; if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = whereClauseFid(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause = whereClauseFids(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } //IMPORTANT - this MUST be the last clause added! else if ( request.filterType() == QgsFeatureRequest::FilterExpression ) { if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { QgsSpatiaLiteExpressionCompiler compiler = QgsSpatiaLiteExpressionCompiler( source ); QgsSqlExpressionCompiler::Result result = compiler.compile( request.filterExpression() ); if ( result == QgsSqlExpressionCompiler::Complete || result == QgsSqlExpressionCompiler::Partial ) { whereClause = compiler.result(); if ( !whereClause.isEmpty() ) { useFallbackWhereClause = true; fallbackWhereClause = whereClauses.join( " AND " ); whereClauses.append( whereClause ); //if only partial success when compiling expression, we need to double-check results using QGIS' expressions mExpressionCompiled = ( result == QgsSqlExpressionCompiler::Complete ); } } if ( result != QgsSqlExpressionCompiler::Complete ) { //can't apply limit at provider side as we need to check all results using QGIS expressions limitAtProvider = false; } } else { limitAtProvider = false; } } whereClause = whereClauses.join( " AND " ); // Setup the order by QStringList orderByParts; mOrderByCompiled = true; if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { Q_FOREACH ( const QgsFeatureRequest::OrderByClause& clause, request.orderBy() ) { QgsSpatiaLiteExpressionCompiler compiler = QgsSpatiaLiteExpressionCompiler( source ); QgsExpression expression = clause.expression(); if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete ) { QString part; part = compiler.result(); if ( clause.nullsFirst() ) orderByParts << QString( "%1 IS NOT NULL" ).arg( part ); else orderByParts << QString( "%1 IS NULL" ).arg( part ); part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC"; orderByParts << part; } else { // Bail out on first non-complete compilation. // Most important clauses at the beginning of the list // will still be sent and used to pre-sort so the local // CPU can use its cycles for fine-tuning. mOrderByCompiled = false; break; } } }
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 }
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; }
QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeatureSource* source, bool ownSource, const QgsFeatureRequest& request ) : QgsAbstractFeatureIteratorFromSource<QgsSpatiaLiteFeatureSource>( source, ownSource, request ) , sqliteStatement( NULL ) , mExpressionCompiled( false ) { mHandle = QgsSpatiaLiteConnPool::instance()->acquireConnection( mSource->mSqlitePath ); mFetchGeometry = !mSource->mGeometryColumn.isNull() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); mHasPrimaryKey = !mSource->mPrimaryKey.isEmpty(); mRowNumber = 0; QStringList whereClauses; bool useFallbackWhereClause = false; QString fallbackWhereClause; QString whereClause; //beware - limitAtProvider needs to be set to false if the request cannot be completely handled //by the provider (eg utilising QGIS expression filters) bool limitAtProvider = ( mRequest.limit() >= 0 ); if ( !request.filterRect().isNull() && !mSource->mGeometryColumn.isNull() ) { // some kind of MBR spatial filtering is required whereClause = whereClauseRect(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( !mSource->mSubsetString.isEmpty() ) { whereClause = "( " + mSource->mSubsetString + ')'; if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } if ( request.filterType() == QgsFeatureRequest::FilterFid ) { whereClause = whereClauseFid(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } else if ( request.filterType() == QgsFeatureRequest::FilterFids ) { whereClause = whereClauseFids(); if ( ! whereClause.isEmpty() ) { whereClauses.append( whereClause ); } } //IMPORTANT - this MUST be the last clause added! else if ( request.filterType() == QgsFeatureRequest::FilterExpression ) { if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { QgsSpatiaLiteExpressionCompiler compiler = QgsSpatiaLiteExpressionCompiler( source ); QgsSqlExpressionCompiler::Result result = compiler.compile( request.filterExpression() ); if ( result == QgsSqlExpressionCompiler::Complete || result == QgsSqlExpressionCompiler::Partial ) { whereClause = compiler.result(); if ( !whereClause.isEmpty() ) { useFallbackWhereClause = true; fallbackWhereClause = whereClauses.join( " AND " ); whereClauses.append( whereClause ); //if only partial success when compiling expression, we need to double-check results using QGIS' expressions mExpressionCompiled = ( result == QgsSqlExpressionCompiler::Complete ); } } if ( result != QgsSqlExpressionCompiler::Complete ) { //can't apply limit at provider side as we need to check all results using QGIS expressions limitAtProvider = false; } } else { limitAtProvider = false; } } whereClause = whereClauses.join( " AND " ); // preparing the SQL statement bool success = prepareStatement( whereClause, limitAtProvider ? mRequest.limit() : -1 ); if ( !success && useFallbackWhereClause ) { //try with the fallback where clause, eg for cases when using compiled expression failed to prepare mExpressionCompiled = false; success = prepareStatement( fallbackWhereClause, -1 ); } if ( !success ) { // some error occurred sqliteStatement = NULL; close(); } }
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(); } }
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; } }