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