QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsvectorlayerfeatureiterator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerfeatureiterator.cpp
3  ---------------------
4  begin : Dezember 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
18 #include "qgsgeometrysimplifier.h"
19 #include "qgssimplifymethod.h"
20 #include "qgsvectordataprovider.h"
22 #include "qgsvectorlayer.h"
24 #include "qgsexpressioncontext.h"
25 #include "qgsdistancearea.h"
26 #include "qgsproject.h"
27 #include "qgsmessagelog.h"
28 #include "qgsexception.h"
30 #include "qgsgeometryengine.h"
31 
32 #include <QThreadStorage>
33 #include <QStack>
34 
36 {
37  const QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
38  const QgsVectorDataProvider *provider = layer->dataProvider();
39  if ( provider )
40  mProviderFeatureSource.reset( provider->featureSource() );
41  mFields = layer->fields();
42  mId = layer->id();
43 
44  // update layer's join caches if necessary
45  if ( layer->mJoinBuffer->containsJoins() )
46  layer->mJoinBuffer->createJoinCaches();
47 
48  mJoinBuffer.reset( layer->mJoinBuffer->clone() );
49 
50  mExpressionFieldBuffer.reset( new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer ) );
51  mCrs = layer->crs();
52 
53  mHasEditBuffer = layer->editBuffer();
54  if ( mHasEditBuffer )
55  {
56 #if 0
57  // TODO[MD]: after merge
58  if ( request.filterType() == QgsFeatureRequest::FilterFid )
59  {
60 
61  // only copy relevant parts
62  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
63  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
64 
65  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
66  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
67 
68  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
69  mDeletedFeatureIds.insert( request.filterFid() );
70 
71  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
72  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
73 
74  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
75  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
76  }
77  else
78  {
79 #endif
80  // If we are inside a transaction the iterator "sees" the current status
81  if ( provider && ! provider->transaction() )
82  {
87  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
89  }
90 #if 0
91  }
92 #endif
93  }
94 
95  const std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
96  mLayerScope = *layerScope;
97 }
98 
100 
102 {
103  // return feature iterator that does not own this source
104  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
105 }
106 
108 {
109  return mFields;
110 }
111 
113 {
114  return mCrs;
115 }
116 
118 {
119  return mId;
120 }
121 
122 
125  , mFetchedFid( false )
126 {
128  {
130  }
131  try
132  {
134  }
135  catch ( QgsCsException & )
136  {
137  // can't reproject mFilterRect
138  close();
139  return;
140  }
141 
142 
143  // prepare spatial filter geometries for optimal speed
144  switch ( mRequest.spatialFilterType() )
145  {
148  break;
149 
152  {
155  mDistanceWithinEngine->prepareGeometry();
157  }
158  break;
159  }
160 
161  if ( !mFilterRect.isNull() )
162  {
163  // update request to be the unprojected filter rect
165  }
166 
167  // check whether the order by clause(s) can be delegated to the provider
168  mDelegatedOrderByToProvider = !mSource->mHasEditBuffer;
169  if ( !mRequest.orderBy().isEmpty() )
170  {
171  QSet<int> attributeIndexes;
172  const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
173  for ( const int attrIndex : usedAttributeIndices )
174  {
175  if ( mSource->mFields.fieldOrigin( attrIndex ) != QgsFields::OriginProvider )
176  mDelegatedOrderByToProvider = false;
177 
178  attributeIndexes << attrIndex;
179  }
180 
181  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mDelegatedOrderByToProvider )
182  {
183  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
184  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
185  }
186  }
187 
189  {
192 
194  {
195  // ensure that all fields required for filter expressions are prepared
197  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
198  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
199  }
200  }
201 
202  prepareFields();
203 
204  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
205 
206  // by default provider's request is the same
208  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
209  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
210  // values
211  if ( mRequest.destinationCrs().isValid() )
212  {
214  }
215 
216  if ( !mDelegatedOrderByToProvider )
217  {
219  }
220 
222  {
223  // prepare list of attributes to match provider fields
224  QSet<int> providerSubset;
226  const int nPendingFields = mSource->mFields.count();
227  for ( const int attrIndex : subset )
228  {
229  if ( attrIndex < 0 || attrIndex >= nPendingFields )
230  continue;
231  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
232  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
233  }
234 
235  // This is done in order to be prepared to do fallback order bys
236  // and be sure we have the required columns.
237  // TODO:
238  // It would be nicer to first check if we can compile the order by
239  // and only modify the subset if we cannot.
240  if ( !mProviderRequest.orderBy().isEmpty() )
241  {
242  const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
243  for ( const int attrIndex : usedAttributeIndices )
244  {
245  providerSubset << attrIndex;
246  }
247  }
248 
249  mProviderRequest.setSubsetOfAttributes( qgis::setToList( providerSubset ) );
250  }
251 
253  {
254  const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
255  const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
256  for ( const QString &field : constReferencedColumns )
257  {
258  const int idx = source->mFields.lookupField( field );
259 
260  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
261  // In this case we disable the expression filter.
262  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
263  {
265  // can't limit at provider side
267  if ( needsGeom )
268  {
269  // have to get geometry from provider in order to evaluate expression on client
271  }
272  break;
273  }
274  }
275  }
276 
277  if ( mSource->mHasEditBuffer )
278  {
280  QgsFeatureIds changedIds;
281  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
282  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
283  {
284  changedIds << attIt.key();
285  }
287 
288  if ( mChangedFeaturesRequest.limit() > 0 )
289  {
290  int providerLimit = mProviderRequest.limit();
291 
292  // features may be deleted in buffer, so increase limit sent to provider
293  providerLimit += mSource->mDeletedFeatureIds.size();
294 
296  {
297  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
298  providerLimit += mSource->mChangedAttributeValues.size();
299  }
300 
302  {
303  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
304  providerLimit += mSource->mChangedGeometries.size();
305  }
306 
307  mProviderRequest.setLimit( providerLimit );
308  mChangedFeaturesRequest.setLimit( providerLimit );
309  }
310  }
311 
312  if ( request.filterType() == QgsFeatureRequest::FilterFid )
313  {
314  mFetchedFid = false;
315  }
316  else // no filter or filter by rect
317  {
319  {
320  if ( mSource->mHasEditBuffer )
321  {
323  }
324  else
325  {
327  }
328  }
329 
331  }
332 }
333 
334 
336 {
337  qDeleteAll( mExpressionFieldInfo );
338 
339  close();
340 }
341 
343 
349 class QgsThreadStackOverflowGuard
350 {
351  public:
352 
353  QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
354  : mStorage( storage )
355  , mMaxDepth( maxDepth )
356  {
357  if ( !storage.hasLocalData() )
358  {
359  storage.setLocalData( QStack<QString>() );
360  }
361 
362  storage.localData().push( stackFrameInformation );
363  }
364 
365  ~QgsThreadStackOverflowGuard()
366  {
367  mStorage.localData().pop();
368  }
369 
370  bool hasStackOverflow() const
371  {
372  if ( mStorage.localData().size() > mMaxDepth )
373  return true;
374  else
375  return false;
376  }
377 
378  QString topFrames() const
379  {
380  QStringList dumpStack;
381  const QStack<QString> &stack = mStorage.localData();
382 
383  const int dumpSize = std::min( static_cast<int>( stack.size() ), 10 );
384  for ( int i = 0; i < dumpSize; ++i )
385  {
386  dumpStack += stack.at( i );
387  }
388 
389  return dumpStack.join( '\n' );
390  }
391 
392  int depth() const
393  {
394  return mStorage.localData().size();
395  }
396 
397  private:
398  QThreadStorage<QStack<QString>> &mStorage;
399  int mMaxDepth;
400 };
401 
403 
405 {
406  f.setValid( false );
407 
408  if ( mClosed )
409  return false;
410 
411  static QThreadStorage<QStack<QString>> sStack;
412 
413  const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
414 
415  if ( guard.hasStackOverflow() )
416  {
417  QgsMessageLog::logMessage( QObject::tr( "Stack overflow, too many nested feature iterators.\nIterated layers:\n%3\n..." ).arg( mSource->id(), guard.topFrames() ), QObject::tr( "General" ), Qgis::MessageLevel::Critical );
418  return false;
419  }
420 
422  {
423  if ( mFetchedFid )
424  return false;
425  const bool res = nextFeatureFid( f );
426  if ( res && postProcessFeature( f ) )
427  {
428  mFetchedFid = true;
429  return res;
430  }
431  else
432  {
433  return false;
434  }
435  }
436 
437  if ( !mFilterRect.isNull() )
438  {
439  if ( fetchNextChangedGeomFeature( f ) )
440  return true;
441 
442  // no more changed geometries
443  }
444 
446  {
448  return true;
449 
450  if ( fetchNextChangedGeomFeature( f ) )
451  return true;
452 
453  // no more changed features
454  }
455 
456  while ( fetchNextAddedFeature( f ) )
457  {
458  return true;
459  }
460  // no more added features
461 
462  if ( mProviderIterator.isClosed() )
463  {
466  {
468  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
469  }
470  }
471 
472  while ( mProviderIterator.nextFeature( f ) )
473  {
474  if ( mFetchConsidered.contains( f.id() ) )
475  continue;
476 
477  // TODO[MD]: just one resize of attributes
478  f.setFields( mSource->mFields );
479 
480  // update attributes
481  if ( mSource->mHasEditBuffer )
483 
484  if ( mHasVirtualAttributes )
486 
488  {
489  //filtering by expression, and couldn't do it on the provider side
492  {
493  //feature did not match filter
494  continue;
495  }
496  }
497 
498  // update geometry
499  // TODO[MK]: FilterRect check after updating the geometry
502 
503  if ( !postProcessFeature( f ) )
504  continue;
505 
506  return true;
507  }
508  // no more provider features
509 
510  close();
511  return false;
512 }
513 
514 
515 
517 {
518  if ( mClosed )
519  return false;
520 
522  {
523  mFetchedFid = false;
524  }
525  else
526  {
529  }
530 
531  return true;
532 }
533 
535 {
536  if ( mClosed )
537  return false;
538 
540 
541  iteratorClosed();
542 
543  mClosed = true;
544  return true;
545 }
546 
548 {
549  mProviderIterator.setInterruptionChecker( interruptionChecker );
550  mInterruptionChecker = interruptionChecker;
551 }
552 
554 {
555  return mProviderIterator.isValid();
556 }
557 
559 {
560  while ( mFetchAddedFeaturesIt != mSource->mAddedFeatures.constBegin() )
561  {
563  const QgsFeatureId fid = mFetchAddedFeaturesIt->id();
564 
565  if ( mFetchConsidered.contains( fid ) )
566  // must have changed geometry outside rectangle
567  continue;
568 
570 
571  // can't test for feature acceptance until after calling useAddedFeature
572  // since acceptFeature may rely on virtual fields
573  if ( !mRequest.acceptFeature( f ) )
574  // skip features which are not accepted by the filter
575  continue;
576 
577  if ( !postProcessFeature( f ) )
578  continue;
579 
580  return true;
581  }
582 
584  return false; // no more added features
585 }
586 
587 
589 {
590  // since QgsFeature is implicitly shared, it's more efficient to just copy the
591  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
592  // This helps potentially avoid an unnecessary detach of the feature
593  f = src;
594  f.setValid( true );
595  f.setFields( mSource->mFields );
596 
597  if ( mHasVirtualAttributes )
599 }
600 
601 
602 
604 {
605  // check if changed geometries are in rectangle
607  {
608  const QgsFeatureId fid = mFetchChangedGeomIt.key();
609 
610  if ( mFetchConsidered.contains( fid ) )
611  // skip deleted features
612  continue;
613 
614  mFetchConsidered << fid;
615 
616  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
617  // skip changed geometries not in rectangle and don't check again
618  continue;
619 
621 
623  {
626  {
627  continue;
628  }
629  }
630 
631  if ( postProcessFeature( f ) )
632  {
633  // return complete feature
635  return true;
636  }
637  }
638 
639  return false; // no more changed geometries
640 }
641 
643 {
645  {
646  if ( mFetchConsidered.contains( f.id() ) )
647  continue;
648 
649  mFetchConsidered << f.id();
650 
652 
653  // also update geometry if needed
654  const auto changedGeometryIt = mSource->mChangedGeometries.constFind( f.id() );
655  if ( changedGeometryIt != mSource->mChangedGeometries.constEnd() )
656  {
657  if ( !mFilterRect.isNull() && !changedGeometryIt->intersects( mFilterRect ) )
658  // skip changed geometries not in rectangle and don't check again
659  continue;
660 
661  f.setGeometry( *changedGeometryIt );
662  }
663 
664  if ( mHasVirtualAttributes )
666 
668  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
669  {
670  return true;
671  }
672  }
673 
674  return false;
675 }
676 
677 
679 {
680  f.setId( fid );
681  f.setValid( true );
682  f.setFields( mSource->mFields );
683 
686  {
687  f.setGeometry( geom );
688  }
689 
690  const bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
691  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
692  {
693  // retrieve attributes from provider
694  QgsFeature tmp;
695  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
696  QgsFeatureRequest request;
698  if ( subsetAttrs )
699  {
701  }
702  QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( request );
703  if ( fi.nextFeature( tmp ) )
704  {
707  f.setAttributes( tmp.attributes() );
708  }
709  }
710 
712 }
713 
714 
715 
717 {
719 
722 }
723 
725 {
726  if ( !mSource->mFields.exists( fieldIdx ) )
727  return;
728 
729  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
730  return;
731 
732  int sourceLayerIndex;
733  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
734  Q_ASSERT( joinInfo );
735 
736  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
737  if ( !joinLayer )
738  return; // invalid join (unresolved reference to layer)
739 
740  if ( !mFetchJoinInfo.contains( joinInfo ) )
741  {
742  FetchJoinInfo info;
743  info.joinInfo = joinInfo;
744  info.joinSource = std::make_shared< QgsVectorLayerFeatureSource >( joinLayer );
745  info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
747  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
748  info.joinLayerFields = joinLayer->fields();
749 
750  // for joined fields, we always need to request the targetField from the provider too
751  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
752  mFieldsToPrepare << info.targetField;
753 
756 
757  mFetchJoinInfo.insert( joinInfo, info );
758  }
759 
760  // store field source index - we'll need it when fetching from provider
761  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
762  mFetchJoinInfo[ joinInfo ].attributesSourceToDestLayerMap[sourceLayerIndex] = fieldIdx;
763 }
764 
765 
767 {
768  static QThreadStorage<QStack<QString>> sStack;
769 
770  const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
771 
772  if ( guard.hasStackOverflow() )
773  {
774  QgsMessageLog::logMessage( QObject::tr( "Stack overflow when preparing field %1 of layer %2.\nLast frames:\n%3\n..." ).arg( mSource->fields().at( fieldIdx ).name(), mSource->id(), guard.topFrames() ), QObject::tr( "General" ), Qgis::MessageLevel::Critical );
775  return;
776  }
777 
778  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
779 
780  const int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
781  std::unique_ptr<QgsExpression> exp = std::make_unique<QgsExpression>( exps[oi].cachedExpression );
782 
783  QgsDistanceArea da;
785  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
786  exp->setGeomCalculator( &da );
787  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
788  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
789 
790  if ( !mExpressionContext )
791  createExpressionContext();
792  exp->prepare( mExpressionContext.get() );
793  const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
794 
795  QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
796 
797  for ( const int dependentFieldIdx : referencedColumns )
798  {
800  {
801  requestedAttributes += dependentFieldIdx;
802  }
803  // also need to fetch this dependent field
804  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
805  mFieldsToPrepare << dependentFieldIdx;
806  }
807 
809  {
810  mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
811  }
812 
813  if ( exp->needsGeometry() )
814  {
816  }
817 
818  mExpressionFieldInfo.insert( fieldIdx, exp.release() );
819 }
820 
822 {
823  mPreparedFields.clear();
824  mFieldsToPrepare.clear();
825  mFetchJoinInfo.clear();
826  mOrderedJoinInfoList.clear();
827 
828  mExpressionContext.reset();
829 
830  mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
833 
834  while ( !mFieldsToPrepare.isEmpty() )
835  {
836  const int fieldIdx = mFieldsToPrepare.takeFirst();
837  if ( mPreparedFields.contains( fieldIdx ) )
838  continue;
839 
840  mPreparedFields << fieldIdx;
841  prepareField( fieldIdx );
842  }
843 
844  //sort joins by dependency
845  if ( !mFetchJoinInfo.empty() )
846  {
847  createOrderedJoinList();
848  }
849 }
850 
851 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
852 {
853  mOrderedJoinInfoList = mFetchJoinInfo.values();
854  if ( mOrderedJoinInfoList.size() < 2 )
855  {
856  return;
857  }
858 
859  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
860 
861  //add all provider fields without joins as resolved fields
862  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
863  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
864  {
865  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
866  {
867  resolvedFields.insert( *prepFieldIt );
868  }
869  }
870 
871  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
872 
873  //some join combinations might not have a resolution at all
874  const int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
875  int currentIteration = 0;
876 
877  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
878  {
879  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
880  {
881  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
882  mOrderedJoinInfoList.removeAt( i );
883  --i;
884  }
885  else
886  {
887  const int offset = mOrderedJoinInfoList.at( i ).indexOffset;
888  const int joinField = mOrderedJoinInfoList.at( i ).joinField;
889 
890  const QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
891  for ( int n = 0; n < attributes.size(); n++ )
892  {
893  if ( n != joinField )
894  {
895  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
896  }
897  }
898  }
899 
900  ++currentIteration;
901  if ( currentIteration >= maxIterations )
902  {
903  break;
904  }
905  }
906 }
907 
908 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
909 {
910  bool result = checkGeometryValidity( feature );
911  if ( result )
913 
914  if ( result && mDistanceWithinEngine && feature.hasGeometry() )
915  {
916  result = mDistanceWithinEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin );
917  }
918 
919  return result;
920 }
921 
922 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
923 {
924  if ( !feature.hasGeometry() )
925  return true;
926 
927  switch ( mRequest.invalidGeometryCheck() )
928  {
930  return true;
931 
933  {
934  if ( !feature.geometry().isGeosValid() )
935  {
936  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
938  {
939  mRequest.invalidGeometryCallback()( feature );
940  }
941  return false;
942  }
943  break;
944  }
945 
947  if ( !feature.geometry().isGeosValid() )
948  {
949  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
950  close();
952  {
953  mRequest.invalidGeometryCallback()( feature );
954  }
955  return false;
956  }
957  break;
958  }
959 
960  return true;
961 }
962 
964 {
965  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
966  {
968  prepareExpression( fieldIdx );
969  break;
970 
972  if ( mSource->mJoinBuffer->containsJoins() )
973  {
974  prepareJoin( fieldIdx );
975  }
976  break;
977 
981  break;
982  }
983 }
984 
986 {
987  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
988  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
989  {
990  const QVariant targetFieldValue = f.attribute( joinIt->targetField );
991  if ( !targetFieldValue.isValid() )
992  continue;
993 
994  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
995  if ( memoryCache.isEmpty() )
996  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
997  else
998  joinIt->addJoinedAttributesCached( f, targetFieldValue );
999  }
1000 }
1001 
1003 {
1004  // make sure we have space for newly added attributes
1005  QgsAttributes attr = f.attributes();
1006  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
1007  f.setAttributes( attr );
1008 
1009  // possible TODO - handle combinations of expression -> join -> expression -> join?
1010  // but for now, write that off as too complex and an unlikely rare, unsupported use case
1011 
1012  QList< int > fetchedVirtualAttributes;
1013  //first, check through joins for any virtual fields we need
1014  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
1015  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
1016  {
1017  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
1018  {
1019  // have to calculate expression field before we can handle this join
1020  addExpressionAttribute( f, joinIt->targetField );
1021  fetchedVirtualAttributes << joinIt->targetField;
1022  }
1023  }
1024 
1025  if ( !mFetchJoinInfo.isEmpty() )
1026  addJoinedAttributes( f );
1027 
1028  // add remaining expression fields
1029  if ( !mExpressionFieldInfo.isEmpty() )
1030  {
1031  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
1032  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
1033  {
1034  if ( fetchedVirtualAttributes.contains( it.key() ) )
1035  continue;
1036 
1037  addExpressionAttribute( f, it.key() );
1038  }
1039  }
1040 }
1041 
1043 {
1044  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
1045  if ( exp )
1046  {
1047  if ( !mExpressionContext )
1048  createExpressionContext();
1049 
1050  mExpressionContext->setFeature( f );
1051  QVariant val = exp->evaluate( mExpressionContext.get() );
1052  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1053  f.setAttribute( attrIndex, val );
1054  }
1055  else
1056  {
1057  f.setAttribute( attrIndex, QVariant() );
1058  }
1059 }
1060 
1062 {
1063  Q_UNUSED( simplifyMethod )
1064  return false;
1065 }
1066 
1067 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1068 {
1069  Q_UNUSED( methodType )
1070  return false;
1071 }
1072 
1073 
1075 {
1076  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1077  const QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1078  if ( it == memoryCache.constEnd() )
1079  return; // joined value not found -> leaving the attributes empty (null)
1080 
1081  int index = indexOffset;
1082 
1083  const QgsAttributes &featureAttributes = it.value();
1084  for ( int i = 0; i < featureAttributes.count(); ++i )
1085  {
1086  f.setAttribute( index++, featureAttributes.at( i ) );
1087  }
1088 }
1089 
1090 
1091 
1093 {
1094 #if 0 // this is not thread safe -- we cannot access the layer here as this will be called from non-main threads.
1095  // Shortcut
1096  if ( joinLayer && ! joinLayer->hasFeatures() )
1097  {
1098  return;
1099  }
1100 #endif
1101 
1102  // no memory cache, query the joined values by setting substring
1103  QString subsetString;
1104 
1105  const QString joinFieldName = joinInfo->joinFieldName();
1106 
1107  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1108 
1109  if ( joinValue.isNull() )
1110  {
1111  subsetString += QLatin1String( " IS NULL" );
1112  }
1113  else
1114  {
1115  QString v = joinValue.toString();
1116  switch ( joinValue.type() )
1117  {
1118  case QVariant::Int:
1119  case QVariant::LongLong:
1120  case QVariant::Double:
1121  break;
1122 
1123  default:
1124  case QVariant::String:
1125  v.replace( '\'', QLatin1String( "''" ) );
1126  v.prepend( '\'' ).append( '\'' );
1127  break;
1128  }
1129  subsetString += '=' + v;
1130  }
1131 
1132  QList<int> joinedAttributeIndices;
1133 
1134  // maybe user requested just a subset of layer's attributes
1135  // so we do not have to cache everything
1136  if ( joinInfo->hasSubset() )
1137  {
1138  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1139  const QVector<int> subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayerFields, subsetNames );
1140  joinedAttributeIndices = qgis::setToList( qgis::listToSet( attributes ).intersect( qgis::listToSet( subsetIndices.toList() ) ) );
1141  }
1142  else
1143  {
1144  joinedAttributeIndices = attributes;
1145  }
1146 
1147  // we don't need the join field, it is already present in the other table
1148  joinedAttributeIndices.removeAll( joinField );
1149 
1150  // select (no geometry)
1151  QgsFeatureRequest request;
1153  request.setSubsetOfAttributes( joinedAttributeIndices );
1154  request.setFilterExpression( subsetString );
1155  request.setLimit( 1 );
1156  QgsFeatureIterator fi = joinSource->getFeatures( request );
1157 
1158  // get first feature
1159  const QList<int> sourceAttrIndexes = attributesSourceToDestLayerMap.keys();
1160  QgsFeature fet;
1161  if ( fi.nextFeature( fet ) )
1162  {
1163  const QgsAttributes attr = fet.attributes();
1164 
1165  for ( const int sourceAttrIndex : sourceAttrIndexes )
1166  {
1167  if ( sourceAttrIndex == joinField )
1168  continue;
1169 
1170  const int destAttrIndex = attributesSourceToDestLayerMap.value( sourceAttrIndex );
1171 
1172  f.setAttribute( destAttrIndex, attr.at( sourceAttrIndex ) );
1173  }
1174  }
1175  else
1176  {
1177  // no suitable join feature found, keeping empty (null) attributes
1178  }
1179 }
1180 
1181 
1182 
1183 
1185 {
1186  const QgsFeatureId featureId = mRequest.filterFid();
1187 
1188  // deleted already?
1189  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1190  return false;
1191 
1192  // has changed geometry?
1193  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1194  {
1195  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1196  return true;
1197  }
1198 
1199  // added features
1200  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1201  {
1202  if ( iter->id() == featureId )
1203  {
1204  useAddedFeature( *iter, f );
1205  return true;
1206  }
1207  }
1208 
1209  // regular features
1211  if ( fi.nextFeature( f ) )
1212  {
1213  f.setFields( mSource->mFields );
1214 
1215  if ( mSource->mHasEditBuffer )
1217 
1218  if ( mHasVirtualAttributes )
1219  addVirtualAttributes( f );
1220 
1221  return true;
1222  }
1223 
1224  return false;
1225 }
1226 
1228 {
1229  QgsAttributes attrs = f.attributes();
1230 
1231  // remove all attributes that will disappear - from higher indices to lower
1232  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1233  {
1234  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1235  }
1236 
1237  // adjust size to accommodate added attributes
1238  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1239 
1240  // update changed attributes
1241  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1242  {
1244  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1245  attrs[it.key()] = it.value();
1246  }
1247  f.setAttributes( attrs );
1248 }
1249 
1251 {
1252  if ( mSource->mChangedGeometries.contains( f.id() ) )
1254 }
1255 
1256 void QgsVectorLayerFeatureIterator::createExpressionContext()
1257 {
1258  mExpressionContext = std::make_unique< QgsExpressionContext >();
1259  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1260  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1261  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1262  mExpressionContext->setFeedback( mRequest.feedback() );
1263 }
1264 
1265 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1266 {
1267  Q_UNUSED( orderBys )
1268  return mDelegatedOrderByToProvider;
1269 }
1270 
1271 
1272 //
1273 // QgsVectorLayerSelectedFeatureSource
1274 //
1275 
1277  : mSource( layer )
1278  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1279  , mWkbType( layer->wkbType() )
1280  , mName( layer->name() )
1281  , mLayer( layer )
1282 {}
1283 
1285 {
1286  QgsFeatureRequest req( request );
1287 
1288  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1289  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1290  // allows providers to optimise the request and avoid requesting features we don't need
1291  // note that we can't do this for some request types - e.g. expression based requests, so
1292  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1293  // do ALL the filtering
1294  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1295  {
1296  req.setFilterFids( mSelectedFeatureIds );
1297  }
1298  else if ( !req.filterFids().isEmpty() )
1299  {
1300  QgsFeatureIds reqIds = mSelectedFeatureIds;
1301  reqIds.intersect( req.filterFids() );
1302  req.setFilterFids( reqIds );
1303  }
1304 
1305  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1306 }
1307 
1309 {
1310  return mSource.crs();
1311 }
1312 
1314 {
1315  return mSource.fields();
1316 }
1317 
1319 {
1320  return mWkbType;
1321 }
1322 
1324 {
1325  return mSelectedFeatureIds.count();
1326 }
1327 
1329 {
1330  return mName;
1331 }
1332 
1334 {
1335  if ( mLayer )
1336  return mLayer->createExpressionContextScope();
1337  else
1338  return nullptr;
1339 }
1340 
1342 {
1343  if ( mLayer )
1344  return mLayer->hasSpatialIndex();
1345  else
1347 }
1348 
1349 //
1350 // QgsVectorLayerSelectedFeatureIterator
1351 //
1352 
1354 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1355  : QgsAbstractFeatureIterator( request )
1356  , mSelectedFeatureIds( selectedFeatureIds )
1357 {
1358  QgsFeatureRequest sourceRequest = request;
1359  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1360  {
1361  // we can't pass the request limit to the provider here - otherwise the provider will
1362  // limit the number of returned features and may only return a bunch of matching features
1363  // which AREN'T in the selected feature set
1364  sourceRequest.setLimit( -1 );
1365  }
1366  mIterator = source.getFeatures( sourceRequest );
1367 }
1368 
1369 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1370 {
1371  return mIterator.rewind();
1372 }
1373 
1374 bool QgsVectorLayerSelectedFeatureIterator::close()
1375 {
1376  return mIterator.close();
1377 }
1378 
1379 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1380 {
1381  while ( mIterator.nextFeature( f ) )
1382  {
1383  if ( mSelectedFeatureIds.contains( f.id() ) )
1384  return true;
1385  }
1386  return false;
1387 }
1388 
@ DistanceWithin
Filter by distance to reference geometry.
@ BoundingBox
Filter using a bounding box.
@ NoFilter
No spatial filtering of features.
Helper template that cares of two things: 1.
void iteratorClosed()
to be called by from subclass in close()
Internal feature iterator to be implemented within data providers.
void geometryToDestinationCrs(QgsFeature &feature, const QgsCoordinateTransform &transform) const
Transforms feature's geometry according to the specified coordinate transform.
QgsRectangle filterRectToSourceCrs(const QgsCoordinateTransform &transform) const SIP_THROW(QgsCsException)
Returns a rectangle representing the original request's QgsFeatureRequest::filterRect().
QgsFeatureRequest mRequest
A copy of the feature request.
bool mClosed
Sets to true, as soon as the iterator is closed.
A vector of attributes.
Definition: qgsattributes.h:58
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Buffers information about expression fields for a vector layer.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
bool isClosed() const
find out whether the iterator is still valid or closed already
void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped.
bool isValid() const
Will return if this iterator is valid.
Represents a list of OrderByClauses, with the most important first and the least important last.
QSet< int > CORE_EXPORT usedAttributeIndices(const QgsFields &fields) const
Returns a set of used, validated attribute indices.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
std::function< void(const QgsFeature &) > invalidGeometryCallback() const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
@ GeometryNoCheck
No invalid geometry checking.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ GeometrySkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
InvalidGeometryCheck invalidGeometryCheck() const
Returns the invalid geometry checking behavior.
QgsExpression * filterExpression() const
Returns the filter expression (if set).
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the iterator to check if it should be ca...
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
OrderBy orderBy() const
Returns a list of order by clauses specified for this feature request.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsGeometry referenceGeometry() const
Returns the reference geometry used for spatial filtering of features.
Flags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature's geometries, or an invalid QgsCoordi...
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
QgsCoordinateTransformContext transformContext() const
Returns the transform context, for use when a destinationCrs() has been set and reprojection is requi...
std::shared_ptr< QgsGeometryEngine > referenceGeometryEngine() const
Returns the reference geometry engine used for spatial filtering of features.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
double distanceWithin() const
Returns the maximum distance from the referenceGeometry() of fetched features, if spatialFilterType()...
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
QgsFeatureRequest & disableFilter()
Disables any attribute/ID filtering.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
FilterType filterType() const
Returns the attribute/ID filter type which is currently set on this request.
const QgsFeatureIds & filterFids() const
Returns the feature IDs that should be fetched.
@ FilterFid
Filter using feature ID.
@ FilterNone
No filter is applied.
@ FilterExpression
Filter using expression.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
QgsFeatureId filterFid() const
Returns the feature ID that should be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
SpatialIndexPresence
Enumeration of spatial index presence states.
@ SpatialIndexUnknown
Spatial index presence cannot be determined, index may or may not exist.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
Definition: qgsfeature.cpp:255
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:188
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:115
QgsGeometry geometry
Definition: qgsfeature.h:67
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:214
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:223
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:320
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:163
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
QString name
Definition: qgsfield.h:60
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:384
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:371
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
@ OriginExpression
Field is calculated from an expression.
Definition: qgsfields.h:54
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:53
@ OriginUnknown
It has not been specified where the field comes from.
Definition: qgsfields.h:50
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfields.h:51
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Definition: qgsfields.cpp:189
bool exists(int i) const
Returns if a field index is valid.
Definition: qgsfields.cpp:153
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
Definition: qgsfields.cpp:197
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:107
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
This is the base class for vector data providers.
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider's data.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed.
QList< QgsField > addedAttributes() const
Returns a list of added attributes fields which are not committed.
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
void useAddedFeature(const QgsFeature &src, QgsFeature &f)
QMap< const QgsVectorLayerJoinInfo *, QgsVectorLayerFeatureIterator::FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
QgsFeatureMap::ConstIterator mFetchAddedFeaturesIt
void setInterruptionChecker(QgsFeedback *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped.
void addVirtualAttributes(QgsFeature &f)
Adds attributes that don't source from the provider but are added inside QGIS Includes.
bool close() override
end of iterating: free the resources / lock
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
void addExpressionAttribute(QgsFeature &f, int attrIndex)
Adds an expression based attribute to a feature.
QMap< int, QgsExpression * > mExpressionFieldInfo
QgsGeometryMap::ConstIterator mFetchChangedGeomIt
bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod) override
Setup the simplification of geometries to fetch using the specified simplify method.
void useChangedAttributeFeature(QgsFeatureId fid, const QgsGeometry &geom, QgsFeature &f)
std::shared_ptr< QgsGeometryEngine > mDistanceWithinEngine
bool fetchFeature(QgsFeature &feature) override
fetch next feature, return true on success
bool isValid() const override
Returns if this iterator is valid.
bool rewind() override
reset the iterator to the starting position
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
Partial snapshot of vector layer's state (only the members necessary for access to features)
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system for features retrieved from this source.
QgsChangedAttributesMap mChangedAttributeValues
std::unique_ptr< QgsAbstractFeatureSource > mProviderFeatureSource
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Gets an iterator for features matching the specified request.
QgsVectorLayerFeatureSource(const QgsVectorLayer *layer)
Constructor for QgsVectorLayerFeatureSource.
~QgsVectorLayerFeatureSource() override
QString id() const
Returns the layer id of the source layer.
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source.
std::unique_ptr< QgsVectorLayerJoinBuffer > mJoinBuffer
std::unique_ptr< QgsExpressionFieldBuffer > mExpressionFieldBuffer
bool containsJoins() const
Quick way to test if there is any join at all.
QgsVectorLayerJoinBuffer * clone() const
Create a copy of the join buffer.
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Returns a vector of indices for use in join based on field names from the layer.
Defines left outer join from our vector layer to some other vector layer.
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
QHash< QString, QgsAttributes > cachedAttributes
Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
long long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown.
SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source,...
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
QgsVectorLayerSelectedFeatureSource(QgsVectorLayer *layer)
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified layer.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QString sourceName() const override
Returns a friendly display name for the source.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:877
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:868
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
const QgsField & field
Definition: qgsfield.h:463
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
const QgsAttributeList & attributeIndexes
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
void addJoinedAttributesDirect(QgsFeature &f, const QVariant &joinValue) const
std::shared_ptr< QgsVectorLayerFeatureSource > joinSource
Feature source for join.
int targetField
Index of field (of this layer) that drives the join.
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
int indexOffset
At what position the joined fields start.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const