QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
31 #include <QThreadStorage>
32 #include <QStack>
33 
35 {
36  QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
37  const QgsVectorDataProvider *provider = layer->dataProvider();
38  if ( provider )
39  mProviderFeatureSource.reset( provider->featureSource() );
40  mFields = layer->fields();
41  mId = layer->id();
42 
43  // update layer's join caches if necessary
44  if ( layer->mJoinBuffer->containsJoins() )
45  layer->mJoinBuffer->createJoinCaches();
46 
47  mJoinBuffer.reset( layer->mJoinBuffer->clone() );
48 
49  mExpressionFieldBuffer.reset( new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer ) );
50  mCrs = layer->crs();
51 
52  mHasEditBuffer = layer->editBuffer();
53  if ( mHasEditBuffer )
54  {
55 #if 0
56  // TODO[MD]: after merge
57  if ( request.filterType() == QgsFeatureRequest::FilterFid )
58  {
59 
60  // only copy relevant parts
61  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
62  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
63 
64  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
65  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
66 
67  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
68  mDeletedFeatureIds.insert( request.filterFid() );
69 
70  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
71  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
72 
73  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
74  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
75  }
76  else
77  {
78 #endif
79  // If we are inside a transaction the iterator "sees" the current status
80  if ( provider && ! provider->transaction() )
81  {
86  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
88  }
89 #if 0
90  }
91 #endif
92  }
93 
94  std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
95  mLayerScope = *layerScope;
96 }
97 
99 
101 {
102  // return feature iterator that does not own this source
103  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
104 }
105 
107 {
108  return mFields;
109 }
110 
112 {
113  return mCrs;
114 }
115 
117 {
118  return mId;
119 }
120 
121 
124  , mFetchedFid( false )
125 
126 {
128  {
130  }
131  try
132  {
134  }
135  catch ( QgsCsException & )
136  {
137  // can't reproject mFilterRect
138  close();
139  return;
140  }
141  if ( !mFilterRect.isNull() )
142  {
143  // update request to be the unprojected filter rect
145  }
146 
147  // check whether the order by clause(s) can be delegated to the provider
148  mDelegatedOrderByToProvider = !mSource->mHasEditBuffer;
149  if ( !mRequest.orderBy().isEmpty() )
150  {
151  QSet<int> attributeIndexes;
152  const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
153  for ( int attrIndex : usedAttributeIndices )
154  {
155  if ( mSource->mFields.fieldOrigin( attrIndex ) != QgsFields::OriginProvider )
156  mDelegatedOrderByToProvider = false;
157 
158  attributeIndexes << attrIndex;
159  }
160 
161  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mDelegatedOrderByToProvider )
162  {
163  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
164  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
165  }
166  }
167 
169  {
172 
174  {
175  // ensure that all fields required for filter expressions are prepared
177  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
178  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
179  }
180  }
181 
182  prepareFields();
183 
184  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
185 
186  // by default provider's request is the same
188  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
189  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
190  // values
191  if ( mRequest.destinationCrs().isValid() )
192  {
194  }
195 
196  if ( !mDelegatedOrderByToProvider )
197  {
199  }
200 
202  {
203  // prepare list of attributes to match provider fields
204  QSet<int> providerSubset;
206  int nPendingFields = mSource->mFields.count();
207  for ( int attrIndex : subset )
208  {
209  if ( attrIndex < 0 || attrIndex >= nPendingFields )
210  continue;
211  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
212  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
213  }
214 
215  // This is done in order to be prepared to do fallback order bys
216  // and be sure we have the required columns.
217  // TODO:
218  // It would be nicer to first check if we can compile the order by
219  // and only modify the subset if we cannot.
220  if ( !mProviderRequest.orderBy().isEmpty() )
221  {
222  const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
223  for ( int attrIndex : usedAttributeIndices )
224  {
225  providerSubset << attrIndex;
226  }
227  }
228 
229  mProviderRequest.setSubsetOfAttributes( qgis::setToList( providerSubset ) );
230  }
231 
233  {
234  const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
235  const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
236  for ( const QString &field : constReferencedColumns )
237  {
238  int idx = source->mFields.lookupField( field );
239 
240  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
241  // In this case we disable the expression filter.
242  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
243  {
245  // can't limit at provider side
247  if ( needsGeom )
248  {
249  // have to get geometry from provider in order to evaluate expression on client
251  }
252  break;
253  }
254  }
255  }
256 
257  if ( mSource->mHasEditBuffer )
258  {
260  QgsFeatureIds changedIds;
261  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
262  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
263  {
264  changedIds << attIt.key();
265  }
267 
268  if ( mChangedFeaturesRequest.limit() > 0 )
269  {
270  int providerLimit = mProviderRequest.limit();
271 
272  // features may be deleted in buffer, so increase limit sent to provider
273  providerLimit += mSource->mDeletedFeatureIds.size();
274 
276  {
277  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
278  providerLimit += mSource->mChangedAttributeValues.size();
279  }
280 
282  {
283  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
284  providerLimit += mSource->mChangedGeometries.size();
285  }
286 
287  mProviderRequest.setLimit( providerLimit );
288  mChangedFeaturesRequest.setLimit( providerLimit );
289  }
290  }
291 
292  if ( request.filterType() == QgsFeatureRequest::FilterFid )
293  {
294  mFetchedFid = false;
295  }
296  else // no filter or filter by rect
297  {
299  {
300  if ( mSource->mHasEditBuffer )
301  {
303  }
304  else
305  {
307  }
308  }
309 
311  }
312 }
313 
314 
316 {
317  qDeleteAll( mExpressionFieldInfo );
318 
319  close();
320 }
321 
323 
329 class QgsThreadStackOverflowGuard
330 {
331  public:
332 
333  QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
334  : mStorage( storage )
335  , mMaxDepth( maxDepth )
336  {
337  if ( !storage.hasLocalData() )
338  {
339  storage.setLocalData( QStack<QString>() );
340  }
341 
342  storage.localData().push( stackFrameInformation );
343  }
344 
345  ~QgsThreadStackOverflowGuard()
346  {
347  mStorage.localData().pop();
348  }
349 
350  bool hasStackOverflow() const
351  {
352  if ( mStorage.localData().size() > mMaxDepth )
353  return true;
354  else
355  return false;
356  }
357 
358  QString topFrames() const
359  {
360  QStringList dumpStack;
361  const QStack<QString> &stack = mStorage.localData();
362 
363  int dumpSize = std::min( static_cast<int>( stack.size() ), 10 );
364  for ( int i = 0; i < dumpSize; ++i )
365  {
366  dumpStack += stack.at( i );
367  }
368 
369  return dumpStack.join( '\n' );
370  }
371 
372  int depth() const
373  {
374  return mStorage.localData().size();
375  }
376 
377  private:
378  QThreadStorage<QStack<QString>> &mStorage;
379  int mMaxDepth;
380 };
381 
383 
385 {
386  f.setValid( false );
387 
388  if ( mClosed )
389  return false;
390 
391  static QThreadStorage<QStack<QString>> sStack;
392 
393  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
394 
395  if ( guard.hasStackOverflow() )
396  {
397  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 );
398  return false;
399  }
400 
402  {
403  if ( mFetchedFid )
404  return false;
405  bool res = nextFeatureFid( f );
406  if ( res && postProcessFeature( f ) )
407  {
408  mFetchedFid = true;
409  return res;
410  }
411  else
412  {
413  return false;
414  }
415  }
416 
417  if ( !mFilterRect.isNull() )
418  {
419  if ( fetchNextChangedGeomFeature( f ) )
420  return true;
421 
422  // no more changed geometries
423  }
424 
426  {
428  return true;
429 
430  if ( fetchNextChangedGeomFeature( f ) )
431  return true;
432 
433  // no more changed features
434  }
435 
436  while ( fetchNextAddedFeature( f ) )
437  {
438  return true;
439  }
440  // no more added features
441 
442  if ( mProviderIterator.isClosed() )
443  {
446  {
448  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
449  }
450  }
451 
452  while ( mProviderIterator.nextFeature( f ) )
453  {
454  if ( mFetchConsidered.contains( f.id() ) )
455  continue;
456 
457  // TODO[MD]: just one resize of attributes
458  f.setFields( mSource->mFields );
459 
460  // update attributes
461  if ( mSource->mHasEditBuffer )
463 
464  if ( mHasVirtualAttributes )
466 
468  {
469  //filtering by expression, and couldn't do it on the provider side
472  {
473  //feature did not match filter
474  continue;
475  }
476  }
477 
478  // update geometry
479  // TODO[MK]: FilterRect check after updating the geometry
482 
483  if ( !postProcessFeature( f ) )
484  continue;
485 
486  return true;
487  }
488  // no more provider features
489 
490  close();
491  return false;
492 }
493 
494 
495 
497 {
498  if ( mClosed )
499  return false;
500 
502  {
503  mFetchedFid = false;
504  }
505  else
506  {
509  }
510 
511  return true;
512 }
513 
515 {
516  if ( mClosed )
517  return false;
518 
520 
521  iteratorClosed();
522 
523  mClosed = true;
524  return true;
525 }
526 
528 {
529  mProviderIterator.setInterruptionChecker( interruptionChecker );
530  mInterruptionChecker = interruptionChecker;
531 }
532 
534 {
535  return mProviderIterator.isValid();
536 }
537 
539 {
540  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
541  {
543 
544  if ( mFetchConsidered.contains( fid ) )
545  // must have changed geometry outside rectangle
546  continue;
547 
549 
550  // can't test for feature acceptance until after calling useAddedFeature
551  // since acceptFeature may rely on virtual fields
552  if ( !mRequest.acceptFeature( f ) )
553  // skip features which are not accepted by the filter
554  continue;
555 
556  if ( !postProcessFeature( f ) )
557  continue;
558 
559  return true;
560  }
561 
563  return false; // no more added features
564 }
565 
566 
568 {
569  // since QgsFeature is implicitly shared, it's more efficient to just copy the
570  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
571  // This helps potentially avoid an unnecessary detach of the feature
572  f = src;
573  f.setValid( true );
574  f.setFields( mSource->mFields );
575 
576  if ( mHasVirtualAttributes )
578 }
579 
580 
581 
583 {
584  // check if changed geometries are in rectangle
586  {
587  QgsFeatureId fid = mFetchChangedGeomIt.key();
588 
589  if ( mFetchConsidered.contains( fid ) )
590  // skip deleted features
591  continue;
592 
593  mFetchConsidered << fid;
594 
595  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
596  // skip changed geometries not in rectangle and don't check again
597  continue;
598 
600 
602  {
605  {
606  continue;
607  }
608  }
609 
610  if ( postProcessFeature( f ) )
611  {
612  // return complete feature
614  return true;
615  }
616  }
617 
618  return false; // no more changed geometries
619 }
620 
622 {
624  {
625  if ( mFetchConsidered.contains( f.id() ) )
626  // skip deleted features and those already handled by the geometry
627  continue;
628 
629  mFetchConsidered << f.id();
630 
632 
633  if ( mHasVirtualAttributes )
635 
637  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
638  {
639  return true;
640  }
641  }
642 
643  return false;
644 }
645 
646 
648 {
649  f.setId( fid );
650  f.setValid( true );
651  f.setFields( mSource->mFields );
652 
655  {
656  f.setGeometry( geom );
657  }
658 
659  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
660  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
661  {
662  // retrieve attributes from provider
663  QgsFeature tmp;
664  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
665  QgsFeatureRequest request;
667  if ( subsetAttrs )
668  {
670  }
671  QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( request );
672  if ( fi.nextFeature( tmp ) )
673  {
676  f.setAttributes( tmp.attributes() );
677  }
678  }
679 
681 }
682 
683 
684 
686 {
688 
691 }
692 
694 {
695  if ( !mSource->mFields.exists( fieldIdx ) )
696  return;
697 
698  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
699  return;
700 
701  int sourceLayerIndex;
702  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
703  Q_ASSERT( joinInfo );
704 
705  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
706  if ( !joinLayer )
707  return; // invalid join (unresolved reference to layer)
708 
709  if ( !mFetchJoinInfo.contains( joinInfo ) )
710  {
711  FetchJoinInfo info;
712  info.joinInfo = joinInfo;
713  info.joinSource = std::make_shared< QgsVectorLayerFeatureSource >( joinLayer );
714  info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
716  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
717  info.joinLayerFields = joinLayer->fields();
718 
719  // for joined fields, we always need to request the targetField from the provider too
720  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
721  mFieldsToPrepare << info.targetField;
722 
725 
726  mFetchJoinInfo.insert( joinInfo, info );
727  }
728 
729  // store field source index - we'll need it when fetching from provider
730  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
731  mFetchJoinInfo[ joinInfo ].attributesSourceToDestLayerMap[sourceLayerIndex] = fieldIdx;
732 }
733 
734 
736 {
737  static QThreadStorage<QStack<QString>> sStack;
738 
739  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
740 
741  if ( guard.hasStackOverflow() )
742  {
743  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 );
744  return;
745  }
746 
747  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
748 
749  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
750  std::unique_ptr<QgsExpression> exp = std::make_unique<QgsExpression>( exps[oi].cachedExpression );
751 
752  QgsDistanceArea da;
754  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
755  exp->setGeomCalculator( &da );
756  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
757  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
758 
759  if ( !mExpressionContext )
760  createExpressionContext();
761  exp->prepare( mExpressionContext.get() );
762  const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
763 
764  QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
765 
766  for ( int dependentFieldIdx : referencedColumns )
767  {
769  {
770  requestedAttributes += dependentFieldIdx;
771  }
772  // also need to fetch this dependent field
773  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
774  mFieldsToPrepare << dependentFieldIdx;
775  }
776 
778  {
779  mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
780  }
781 
782  if ( exp->needsGeometry() )
783  {
785  }
786 
787  mExpressionFieldInfo.insert( fieldIdx, exp.release() );
788 }
789 
791 {
792  mPreparedFields.clear();
793  mFieldsToPrepare.clear();
794  mFetchJoinInfo.clear();
795  mOrderedJoinInfoList.clear();
796 
797  mExpressionContext.reset();
798 
799  mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
802 
803  while ( !mFieldsToPrepare.isEmpty() )
804  {
805  int fieldIdx = mFieldsToPrepare.takeFirst();
806  if ( mPreparedFields.contains( fieldIdx ) )
807  continue;
808 
809  mPreparedFields << fieldIdx;
810  prepareField( fieldIdx );
811  }
812 
813  //sort joins by dependency
814  if ( !mFetchJoinInfo.empty() )
815  {
816  createOrderedJoinList();
817  }
818 }
819 
820 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
821 {
822  mOrderedJoinInfoList = mFetchJoinInfo.values();
823  if ( mOrderedJoinInfoList.size() < 2 )
824  {
825  return;
826  }
827 
828  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
829 
830  //add all provider fields without joins as resolved fields
831  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
832  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
833  {
834  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
835  {
836  resolvedFields.insert( *prepFieldIt );
837  }
838  }
839 
840  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
841 
842  //some join combinations might not have a resolution at all
843  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
844  int currentIteration = 0;
845 
846  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
847  {
848  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
849  {
850  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
851  mOrderedJoinInfoList.removeAt( i );
852  --i;
853  }
854  else
855  {
856  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
857  int joinField = mOrderedJoinInfoList.at( i ).joinField;
858 
859  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
860  for ( int n = 0; n < attributes.size(); n++ )
861  {
862  if ( n != joinField )
863  {
864  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
865  }
866  }
867  }
868 
869  ++currentIteration;
870  if ( currentIteration >= maxIterations )
871  {
872  break;
873  }
874  }
875 }
876 
877 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
878 {
879  bool result = checkGeometryValidity( feature );
880  if ( result )
882  return result;
883 }
884 
885 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
886 {
887  if ( !feature.hasGeometry() )
888  return true;
889 
890  switch ( mRequest.invalidGeometryCheck() )
891  {
893  return true;
894 
896  {
897  if ( !feature.geometry().isGeosValid() )
898  {
899  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
901  {
902  mRequest.invalidGeometryCallback()( feature );
903  }
904  return false;
905  }
906  break;
907  }
908 
910  if ( !feature.geometry().isGeosValid() )
911  {
912  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
913  close();
915  {
916  mRequest.invalidGeometryCallback()( feature );
917  }
918  return false;
919  }
920  break;
921  }
922 
923  return true;
924 }
925 
927 {
928  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
929  {
931  prepareExpression( fieldIdx );
932  break;
933 
935  if ( mSource->mJoinBuffer->containsJoins() )
936  {
937  prepareJoin( fieldIdx );
938  }
939  break;
940 
944  break;
945  }
946 }
947 
949 {
950  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
951  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
952  {
953  QVariant targetFieldValue = f.attribute( joinIt->targetField );
954  if ( !targetFieldValue.isValid() )
955  continue;
956 
957  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
958  if ( memoryCache.isEmpty() )
959  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
960  else
961  joinIt->addJoinedAttributesCached( f, targetFieldValue );
962  }
963 }
964 
966 {
967  // make sure we have space for newly added attributes
968  QgsAttributes attr = f.attributes();
969  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
970  f.setAttributes( attr );
971 
972  // possible TODO - handle combinations of expression -> join -> expression -> join?
973  // but for now, write that off as too complex and an unlikely rare, unsupported use case
974 
975  QList< int > fetchedVirtualAttributes;
976  //first, check through joins for any virtual fields we need
977  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
978  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
979  {
980  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
981  {
982  // have to calculate expression field before we can handle this join
983  addExpressionAttribute( f, joinIt->targetField );
984  fetchedVirtualAttributes << joinIt->targetField;
985  }
986  }
987 
988  if ( !mFetchJoinInfo.isEmpty() )
989  addJoinedAttributes( f );
990 
991  // add remaining expression fields
992  if ( !mExpressionFieldInfo.isEmpty() )
993  {
994  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
995  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
996  {
997  if ( fetchedVirtualAttributes.contains( it.key() ) )
998  continue;
999 
1000  addExpressionAttribute( f, it.key() );
1001  }
1002  }
1003 }
1004 
1006 {
1007  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
1008  if ( exp )
1009  {
1010  if ( !mExpressionContext )
1011  createExpressionContext();
1012 
1013  mExpressionContext->setFeature( f );
1014  QVariant val = exp->evaluate( mExpressionContext.get() );
1015  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1016  f.setAttribute( attrIndex, val );
1017  }
1018  else
1019  {
1020  f.setAttribute( attrIndex, QVariant() );
1021  }
1022 }
1023 
1025 {
1026  Q_UNUSED( simplifyMethod )
1027  return false;
1028 }
1029 
1030 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1031 {
1032  Q_UNUSED( methodType )
1033  return false;
1034 }
1035 
1036 
1038 {
1039  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1040  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1041  if ( it == memoryCache.constEnd() )
1042  return; // joined value not found -> leaving the attributes empty (null)
1043 
1044  int index = indexOffset;
1045 
1046  const QgsAttributes &featureAttributes = it.value();
1047  for ( int i = 0; i < featureAttributes.count(); ++i )
1048  {
1049  f.setAttribute( index++, featureAttributes.at( i ) );
1050  }
1051 }
1052 
1053 
1054 
1056 {
1057 #if 0 // this is not thread safe -- we cannot access the layer here as this will be called from non-main threads.
1058  // Shortcut
1059  if ( joinLayer && ! joinLayer->hasFeatures() )
1060  {
1061  return;
1062  }
1063 #endif
1064 
1065  // no memory cache, query the joined values by setting substring
1066  QString subsetString;
1067 
1068  QString joinFieldName = joinInfo->joinFieldName();
1069 
1070  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1071 
1072  if ( joinValue.isNull() )
1073  {
1074  subsetString += QLatin1String( " IS NULL" );
1075  }
1076  else
1077  {
1078  QString v = joinValue.toString();
1079  switch ( joinValue.type() )
1080  {
1081  case QVariant::Int:
1082  case QVariant::LongLong:
1083  case QVariant::Double:
1084  break;
1085 
1086  default:
1087  case QVariant::String:
1088  v.replace( '\'', QLatin1String( "''" ) );
1089  v.prepend( '\'' ).append( '\'' );
1090  break;
1091  }
1092  subsetString += '=' + v;
1093  }
1094 
1095  QList<int> joinedAttributeIndices;
1096 
1097  // maybe user requested just a subset of layer's attributes
1098  // so we do not have to cache everything
1099  if ( joinInfo->hasSubset() )
1100  {
1101  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1102  QVector<int> subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayerFields, subsetNames );
1103  joinedAttributeIndices = qgis::setToList( qgis::listToSet( attributes ).intersect( qgis::listToSet( subsetIndices.toList() ) ) );
1104  }
1105  else
1106  {
1107  joinedAttributeIndices = attributes;
1108  }
1109 
1110  // we don't need the join field, it is already present in the other table
1111  joinedAttributeIndices.removeAll( joinField );
1112 
1113  // select (no geometry)
1114  QgsFeatureRequest request;
1116  request.setSubsetOfAttributes( joinedAttributeIndices );
1117  request.setFilterExpression( subsetString );
1118  request.setLimit( 1 );
1119  QgsFeatureIterator fi = joinSource->getFeatures( request );
1120 
1121  // get first feature
1122  const QList<int> sourceAttrIndexes = attributesSourceToDestLayerMap.keys();
1123  QgsFeature fet;
1124  if ( fi.nextFeature( fet ) )
1125  {
1126  QgsAttributes attr = fet.attributes();
1127 
1128  for ( const int sourceAttrIndex : sourceAttrIndexes )
1129  {
1130  if ( sourceAttrIndex == joinField )
1131  continue;
1132 
1133  int destAttrIndex = attributesSourceToDestLayerMap.value( sourceAttrIndex );
1134 
1135  f.setAttribute( destAttrIndex, attr.at( sourceAttrIndex ) );
1136  }
1137  }
1138  else
1139  {
1140  // no suitable join feature found, keeping empty (null) attributes
1141  }
1142 }
1143 
1144 
1145 
1146 
1148 {
1149  QgsFeatureId featureId = mRequest.filterFid();
1150 
1151  // deleted already?
1152  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1153  return false;
1154 
1155  // has changed geometry?
1156  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1157  {
1158  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1159  return true;
1160  }
1161 
1162  // added features
1163  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1164  {
1165  if ( iter->id() == featureId )
1166  {
1167  useAddedFeature( *iter, f );
1168  return true;
1169  }
1170  }
1171 
1172  // regular features
1174  if ( fi.nextFeature( f ) )
1175  {
1176  f.setFields( mSource->mFields );
1177 
1178  if ( mSource->mHasEditBuffer )
1180 
1181  if ( mHasVirtualAttributes )
1182  addVirtualAttributes( f );
1183 
1184  return true;
1185  }
1186 
1187  return false;
1188 }
1189 
1191 {
1192  QgsAttributes attrs = f.attributes();
1193 
1194  // remove all attributes that will disappear - from higher indices to lower
1195  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1196  {
1197  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1198  }
1199 
1200  // adjust size to accommodate added attributes
1201  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1202 
1203  // update changed attributes
1204  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1205  {
1207  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1208  attrs[it.key()] = it.value();
1209  }
1210  f.setAttributes( attrs );
1211 }
1212 
1214 {
1215  if ( mSource->mChangedGeometries.contains( f.id() ) )
1217 }
1218 
1219 void QgsVectorLayerFeatureIterator::createExpressionContext()
1220 {
1221  mExpressionContext = std::make_unique< QgsExpressionContext >();
1222  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1223  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1224  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1225 }
1226 
1227 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1228 {
1229  Q_UNUSED( orderBys )
1230  return mDelegatedOrderByToProvider;
1231 }
1232 
1233 
1234 //
1235 // QgsVectorLayerSelectedFeatureSource
1236 //
1237 
1239  : mSource( layer )
1240  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1241  , mWkbType( layer->wkbType() )
1242  , mName( layer->name() )
1243  , mLayer( layer )
1244 {}
1245 
1247 {
1248  QgsFeatureRequest req( request );
1249 
1250  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1251  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1252  // allows providers to optimise the request and avoid requesting features we don't need
1253  // note that we can't do this for some request types - e.g. expression based requests, so
1254  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1255  // do ALL the filtering
1256  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1257  {
1258  req.setFilterFids( mSelectedFeatureIds );
1259  }
1260  else if ( !req.filterFids().isEmpty() )
1261  {
1262  QgsFeatureIds reqIds = mSelectedFeatureIds;
1263  reqIds.intersect( req.filterFids() );
1264  req.setFilterFids( reqIds );
1265  }
1266 
1267  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1268 }
1269 
1271 {
1272  return mSource.crs();
1273 }
1274 
1276 {
1277  return mSource.fields();
1278 }
1279 
1281 {
1282  return mWkbType;
1283 }
1284 
1286 {
1287  return mSelectedFeatureIds.count();
1288 }
1289 
1291 {
1292  return mName;
1293 }
1294 
1296 {
1297  if ( mLayer )
1298  return mLayer->createExpressionContextScope();
1299  else
1300  return nullptr;
1301 }
1302 
1304 {
1305  if ( mLayer )
1306  return mLayer->hasSpatialIndex();
1307  else
1309 }
1310 
1311 //
1312 // QgsVectorLayerSelectedFeatureIterator
1313 //
1314 
1316 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1317  : QgsAbstractFeatureIterator( request )
1318  , mSelectedFeatureIds( selectedFeatureIds )
1319 {
1320  QgsFeatureRequest sourceRequest = request;
1321  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1322  {
1323  // we can't pass the request limit to the provider here - otherwise the provider will
1324  // limit the number of returned features and may only return a bunch of matching features
1325  // which AREN'T in the selected feature set
1326  sourceRequest.setLimit( -1 );
1327  }
1328  mIterator = source.getFeatures( sourceRequest );
1329 }
1330 
1331 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1332 {
1333  return mIterator.rewind();
1334 }
1335 
1336 bool QgsVectorLayerSelectedFeatureIterator::close()
1337 {
1338  return mIterator.close();
1339 }
1340 
1341 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1342 {
1343  while ( mIterator.nextFeature( f ) )
1344  {
1345  if ( mSelectedFeatureIds.contains( f.id() ) )
1346  return true;
1347  }
1348  return false;
1349 }
1350 
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.
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets 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.
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...
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
QgsFeatureRequest & disableFilter()
Disables filter conditions.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
FilterType filterType() const
Returns the filter type which is currently set on this request.
const QgsFeatureIds & filterFids() const
Gets feature IDs that should be fetched.
@ FilterFid
Filter using feature ID.
@ FilterNone
No filter is applied.
@ FilterExpression
Filter using expression.
const Flags & flags() const
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
QgsFeatureId filterFid() const
Gets 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:237
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:135
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:170
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:196
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:205
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:145
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:371
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:124
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:76
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:105
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)
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:731
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:722
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 joinField
Index of field (of the joined layer) must have equal value.
int indexOffset
At what position the joined fields start.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const