QGIS API Documentation  3.23.0-Master (eb871beae0)
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  // skip deleted features and those already handled by the geometry
648  continue;
649 
650  mFetchConsidered << f.id();
651 
653 
654  if ( mHasVirtualAttributes )
656 
658  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
659  {
660  return true;
661  }
662  }
663 
664  return false;
665 }
666 
667 
669 {
670  f.setId( fid );
671  f.setValid( true );
672  f.setFields( mSource->mFields );
673 
676  {
677  f.setGeometry( geom );
678  }
679 
680  const bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
681  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
682  {
683  // retrieve attributes from provider
684  QgsFeature tmp;
685  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
686  QgsFeatureRequest request;
688  if ( subsetAttrs )
689  {
691  }
692  QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( request );
693  if ( fi.nextFeature( tmp ) )
694  {
697  f.setAttributes( tmp.attributes() );
698  }
699  }
700 
702 }
703 
704 
705 
707 {
709 
712 }
713 
715 {
716  if ( !mSource->mFields.exists( fieldIdx ) )
717  return;
718 
719  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
720  return;
721 
722  int sourceLayerIndex;
723  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
724  Q_ASSERT( joinInfo );
725 
726  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
727  if ( !joinLayer )
728  return; // invalid join (unresolved reference to layer)
729 
730  if ( !mFetchJoinInfo.contains( joinInfo ) )
731  {
732  FetchJoinInfo info;
733  info.joinInfo = joinInfo;
734  info.joinSource = std::make_shared< QgsVectorLayerFeatureSource >( joinLayer );
735  info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
737  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
738  info.joinLayerFields = joinLayer->fields();
739 
740  // for joined fields, we always need to request the targetField from the provider too
741  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
742  mFieldsToPrepare << info.targetField;
743 
746 
747  mFetchJoinInfo.insert( joinInfo, info );
748  }
749 
750  // store field source index - we'll need it when fetching from provider
751  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
752  mFetchJoinInfo[ joinInfo ].attributesSourceToDestLayerMap[sourceLayerIndex] = fieldIdx;
753 }
754 
755 
757 {
758  static QThreadStorage<QStack<QString>> sStack;
759 
760  const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
761 
762  if ( guard.hasStackOverflow() )
763  {
764  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 );
765  return;
766  }
767 
768  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
769 
770  const int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
771  std::unique_ptr<QgsExpression> exp = std::make_unique<QgsExpression>( exps[oi].cachedExpression );
772 
773  QgsDistanceArea da;
775  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
776  exp->setGeomCalculator( &da );
777  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
778  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
779 
780  if ( !mExpressionContext )
781  createExpressionContext();
782  exp->prepare( mExpressionContext.get() );
783  const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
784 
785  QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
786 
787  for ( const int dependentFieldIdx : referencedColumns )
788  {
790  {
791  requestedAttributes += dependentFieldIdx;
792  }
793  // also need to fetch this dependent field
794  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
795  mFieldsToPrepare << dependentFieldIdx;
796  }
797 
799  {
800  mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
801  }
802 
803  if ( exp->needsGeometry() )
804  {
806  }
807 
808  mExpressionFieldInfo.insert( fieldIdx, exp.release() );
809 }
810 
812 {
813  mPreparedFields.clear();
814  mFieldsToPrepare.clear();
815  mFetchJoinInfo.clear();
816  mOrderedJoinInfoList.clear();
817 
818  mExpressionContext.reset();
819 
820  mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
823 
824  while ( !mFieldsToPrepare.isEmpty() )
825  {
826  const int fieldIdx = mFieldsToPrepare.takeFirst();
827  if ( mPreparedFields.contains( fieldIdx ) )
828  continue;
829 
830  mPreparedFields << fieldIdx;
831  prepareField( fieldIdx );
832  }
833 
834  //sort joins by dependency
835  if ( !mFetchJoinInfo.empty() )
836  {
837  createOrderedJoinList();
838  }
839 }
840 
841 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
842 {
843  mOrderedJoinInfoList = mFetchJoinInfo.values();
844  if ( mOrderedJoinInfoList.size() < 2 )
845  {
846  return;
847  }
848 
849  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
850 
851  //add all provider fields without joins as resolved fields
852  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
853  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
854  {
855  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
856  {
857  resolvedFields.insert( *prepFieldIt );
858  }
859  }
860 
861  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
862 
863  //some join combinations might not have a resolution at all
864  const int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
865  int currentIteration = 0;
866 
867  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
868  {
869  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
870  {
871  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
872  mOrderedJoinInfoList.removeAt( i );
873  --i;
874  }
875  else
876  {
877  const int offset = mOrderedJoinInfoList.at( i ).indexOffset;
878  const int joinField = mOrderedJoinInfoList.at( i ).joinField;
879 
880  const QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
881  for ( int n = 0; n < attributes.size(); n++ )
882  {
883  if ( n != joinField )
884  {
885  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
886  }
887  }
888  }
889 
890  ++currentIteration;
891  if ( currentIteration >= maxIterations )
892  {
893  break;
894  }
895  }
896 }
897 
898 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
899 {
900  bool result = checkGeometryValidity( feature );
901  if ( result )
903 
904  if ( result && mDistanceWithinEngine && feature.hasGeometry() )
905  {
906  result = mDistanceWithinEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin );
907  }
908 
909  return result;
910 }
911 
912 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
913 {
914  if ( !feature.hasGeometry() )
915  return true;
916 
917  switch ( mRequest.invalidGeometryCheck() )
918  {
920  return true;
921 
923  {
924  if ( !feature.geometry().isGeosValid() )
925  {
926  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
928  {
929  mRequest.invalidGeometryCallback()( feature );
930  }
931  return false;
932  }
933  break;
934  }
935 
937  if ( !feature.geometry().isGeosValid() )
938  {
939  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
940  close();
942  {
943  mRequest.invalidGeometryCallback()( feature );
944  }
945  return false;
946  }
947  break;
948  }
949 
950  return true;
951 }
952 
954 {
955  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
956  {
958  prepareExpression( fieldIdx );
959  break;
960 
962  if ( mSource->mJoinBuffer->containsJoins() )
963  {
964  prepareJoin( fieldIdx );
965  }
966  break;
967 
971  break;
972  }
973 }
974 
976 {
977  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
978  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
979  {
980  const QVariant targetFieldValue = f.attribute( joinIt->targetField );
981  if ( !targetFieldValue.isValid() )
982  continue;
983 
984  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
985  if ( memoryCache.isEmpty() )
986  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
987  else
988  joinIt->addJoinedAttributesCached( f, targetFieldValue );
989  }
990 }
991 
993 {
994  // make sure we have space for newly added attributes
995  QgsAttributes attr = f.attributes();
996  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
997  f.setAttributes( attr );
998 
999  // possible TODO - handle combinations of expression -> join -> expression -> join?
1000  // but for now, write that off as too complex and an unlikely rare, unsupported use case
1001 
1002  QList< int > fetchedVirtualAttributes;
1003  //first, check through joins for any virtual fields we need
1004  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
1005  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
1006  {
1007  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
1008  {
1009  // have to calculate expression field before we can handle this join
1010  addExpressionAttribute( f, joinIt->targetField );
1011  fetchedVirtualAttributes << joinIt->targetField;
1012  }
1013  }
1014 
1015  if ( !mFetchJoinInfo.isEmpty() )
1016  addJoinedAttributes( f );
1017 
1018  // add remaining expression fields
1019  if ( !mExpressionFieldInfo.isEmpty() )
1020  {
1021  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
1022  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
1023  {
1024  if ( fetchedVirtualAttributes.contains( it.key() ) )
1025  continue;
1026 
1027  addExpressionAttribute( f, it.key() );
1028  }
1029  }
1030 }
1031 
1033 {
1034  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
1035  if ( exp )
1036  {
1037  if ( !mExpressionContext )
1038  createExpressionContext();
1039 
1040  mExpressionContext->setFeature( f );
1041  QVariant val = exp->evaluate( mExpressionContext.get() );
1042  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1043  f.setAttribute( attrIndex, val );
1044  }
1045  else
1046  {
1047  f.setAttribute( attrIndex, QVariant() );
1048  }
1049 }
1050 
1052 {
1053  Q_UNUSED( simplifyMethod )
1054  return false;
1055 }
1056 
1057 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1058 {
1059  Q_UNUSED( methodType )
1060  return false;
1061 }
1062 
1063 
1065 {
1066  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1067  const QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1068  if ( it == memoryCache.constEnd() )
1069  return; // joined value not found -> leaving the attributes empty (null)
1070 
1071  int index = indexOffset;
1072 
1073  const QgsAttributes &featureAttributes = it.value();
1074  for ( int i = 0; i < featureAttributes.count(); ++i )
1075  {
1076  f.setAttribute( index++, featureAttributes.at( i ) );
1077  }
1078 }
1079 
1080 
1081 
1083 {
1084 #if 0 // this is not thread safe -- we cannot access the layer here as this will be called from non-main threads.
1085  // Shortcut
1086  if ( joinLayer && ! joinLayer->hasFeatures() )
1087  {
1088  return;
1089  }
1090 #endif
1091 
1092  // no memory cache, query the joined values by setting substring
1093  QString subsetString;
1094 
1095  const QString joinFieldName = joinInfo->joinFieldName();
1096 
1097  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1098 
1099  if ( joinValue.isNull() )
1100  {
1101  subsetString += QLatin1String( " IS NULL" );
1102  }
1103  else
1104  {
1105  QString v = joinValue.toString();
1106  switch ( joinValue.type() )
1107  {
1108  case QVariant::Int:
1109  case QVariant::LongLong:
1110  case QVariant::Double:
1111  break;
1112 
1113  default:
1114  case QVariant::String:
1115  v.replace( '\'', QLatin1String( "''" ) );
1116  v.prepend( '\'' ).append( '\'' );
1117  break;
1118  }
1119  subsetString += '=' + v;
1120  }
1121 
1122  QList<int> joinedAttributeIndices;
1123 
1124  // maybe user requested just a subset of layer's attributes
1125  // so we do not have to cache everything
1126  if ( joinInfo->hasSubset() )
1127  {
1128  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1129  const QVector<int> subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayerFields, subsetNames );
1130  joinedAttributeIndices = qgis::setToList( qgis::listToSet( attributes ).intersect( qgis::listToSet( subsetIndices.toList() ) ) );
1131  }
1132  else
1133  {
1134  joinedAttributeIndices = attributes;
1135  }
1136 
1137  // we don't need the join field, it is already present in the other table
1138  joinedAttributeIndices.removeAll( joinField );
1139 
1140  // select (no geometry)
1141  QgsFeatureRequest request;
1143  request.setSubsetOfAttributes( joinedAttributeIndices );
1144  request.setFilterExpression( subsetString );
1145  request.setLimit( 1 );
1146  QgsFeatureIterator fi = joinSource->getFeatures( request );
1147 
1148  // get first feature
1149  const QList<int> sourceAttrIndexes = attributesSourceToDestLayerMap.keys();
1150  QgsFeature fet;
1151  if ( fi.nextFeature( fet ) )
1152  {
1153  const QgsAttributes attr = fet.attributes();
1154 
1155  for ( const int sourceAttrIndex : sourceAttrIndexes )
1156  {
1157  if ( sourceAttrIndex == joinField )
1158  continue;
1159 
1160  const int destAttrIndex = attributesSourceToDestLayerMap.value( sourceAttrIndex );
1161 
1162  f.setAttribute( destAttrIndex, attr.at( sourceAttrIndex ) );
1163  }
1164  }
1165  else
1166  {
1167  // no suitable join feature found, keeping empty (null) attributes
1168  }
1169 }
1170 
1171 
1172 
1173 
1175 {
1176  const QgsFeatureId featureId = mRequest.filterFid();
1177 
1178  // deleted already?
1179  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1180  return false;
1181 
1182  // has changed geometry?
1183  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1184  {
1185  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1186  return true;
1187  }
1188 
1189  // added features
1190  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1191  {
1192  if ( iter->id() == featureId )
1193  {
1194  useAddedFeature( *iter, f );
1195  return true;
1196  }
1197  }
1198 
1199  // regular features
1201  if ( fi.nextFeature( f ) )
1202  {
1203  f.setFields( mSource->mFields );
1204 
1205  if ( mSource->mHasEditBuffer )
1207 
1208  if ( mHasVirtualAttributes )
1209  addVirtualAttributes( f );
1210 
1211  return true;
1212  }
1213 
1214  return false;
1215 }
1216 
1218 {
1219  QgsAttributes attrs = f.attributes();
1220 
1221  // remove all attributes that will disappear - from higher indices to lower
1222  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1223  {
1224  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1225  }
1226 
1227  // adjust size to accommodate added attributes
1228  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1229 
1230  // update changed attributes
1231  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1232  {
1234  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1235  attrs[it.key()] = it.value();
1236  }
1237  f.setAttributes( attrs );
1238 }
1239 
1241 {
1242  if ( mSource->mChangedGeometries.contains( f.id() ) )
1244 }
1245 
1246 void QgsVectorLayerFeatureIterator::createExpressionContext()
1247 {
1248  mExpressionContext = std::make_unique< QgsExpressionContext >();
1249  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1250  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1251  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1252  mExpressionContext->setFeedback( mRequest.feedback() );
1253 }
1254 
1255 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1256 {
1257  Q_UNUSED( orderBys )
1258  return mDelegatedOrderByToProvider;
1259 }
1260 
1261 
1262 //
1263 // QgsVectorLayerSelectedFeatureSource
1264 //
1265 
1267  : mSource( layer )
1268  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1269  , mWkbType( layer->wkbType() )
1270  , mName( layer->name() )
1271  , mLayer( layer )
1272 {}
1273 
1275 {
1276  QgsFeatureRequest req( request );
1277 
1278  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1279  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1280  // allows providers to optimise the request and avoid requesting features we don't need
1281  // note that we can't do this for some request types - e.g. expression based requests, so
1282  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1283  // do ALL the filtering
1284  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1285  {
1286  req.setFilterFids( mSelectedFeatureIds );
1287  }
1288  else if ( !req.filterFids().isEmpty() )
1289  {
1290  QgsFeatureIds reqIds = mSelectedFeatureIds;
1291  reqIds.intersect( req.filterFids() );
1292  req.setFilterFids( reqIds );
1293  }
1294 
1295  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1296 }
1297 
1299 {
1300  return mSource.crs();
1301 }
1302 
1304 {
1305  return mSource.fields();
1306 }
1307 
1309 {
1310  return mWkbType;
1311 }
1312 
1314 {
1315  return mSelectedFeatureIds.count();
1316 }
1317 
1319 {
1320  return mName;
1321 }
1322 
1324 {
1325  if ( mLayer )
1326  return mLayer->createExpressionContextScope();
1327  else
1328  return nullptr;
1329 }
1330 
1332 {
1333  if ( mLayer )
1334  return mLayer->hasSpatialIndex();
1335  else
1337 }
1338 
1339 //
1340 // QgsVectorLayerSelectedFeatureIterator
1341 //
1342 
1344 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1345  : QgsAbstractFeatureIterator( request )
1346  , mSelectedFeatureIds( selectedFeatureIds )
1347 {
1348  QgsFeatureRequest sourceRequest = request;
1349  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1350  {
1351  // we can't pass the request limit to the provider here - otherwise the provider will
1352  // limit the number of returned features and may only return a bunch of matching features
1353  // which AREN'T in the selected feature set
1354  sourceRequest.setLimit( -1 );
1355  }
1356  mIterator = source.getFeatures( sourceRequest );
1357 }
1358 
1359 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1360 {
1361  return mIterator.rewind();
1362 }
1363 
1364 bool QgsVectorLayerSelectedFeatureIterator::close()
1365 {
1366  return mIterator.close();
1367 }
1368 
1369 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1370 {
1371  while ( mIterator.nextFeature( f ) )
1372  {
1373  if ( mSelectedFeatureIds.contains( f.id() ) )
1374  return true;
1375  }
1376  return false;
1377 }
1378 
@ 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: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:402
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:468
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:829
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:820
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