QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
32 {
33  QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
35  mFields = layer->fields();
36  mId = layer->id();
37 
38  // update layer's join caches if necessary
39  if ( layer->mJoinBuffer->containsJoins() )
40  layer->mJoinBuffer->createJoinCaches();
41 
42  mJoinBuffer = layer->mJoinBuffer->clone();
43 
44  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
45  mCrs = layer->crs();
46 
47  mHasEditBuffer = layer->editBuffer();
48  if ( mHasEditBuffer )
49  {
50 #if 0
51  // TODO[MD]: after merge
52  if ( request.filterType() == QgsFeatureRequest::FilterFid )
53  {
54 
55  // only copy relevant parts
56  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
57  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
58 
59  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
60  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
61 
62  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
63  mDeletedFeatureIds.insert( request.filterFid() );
64 
65  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
66  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
67 
68  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
69  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
70  }
71  else
72  {
73 #endif
78  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
80 #if 0
81  }
82 #endif
83  }
84 
85  std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
86  mLayerScope = *layerScope;
87 }
88 
90 {
91  delete mJoinBuffer;
94 }
95 
97 {
98  // return feature iterator that does not own this source
99  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
100 }
101 
103 {
104  return mFields;
105 }
106 
108 {
109  return mCrs;
110 }
111 
113 {
114  return mId;
115 }
116 
117 
120  , mFetchedFid( false )
121 
122 {
124  {
126  }
127  try
128  {
130  }
131  catch ( QgsCsException & )
132  {
133  // can't reproject mFilterRect
134  close();
135  return;
136  }
137  if ( !mFilterRect.isNull() )
138  {
139  // update request to be the unprojected filter rect
141  }
142 
144  {
147 
149  {
150  //ensure that all fields required for filter expressions are prepared
152  attributeIndexes += mRequest.subsetOfAttributes().toSet();
153  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
154  }
155  }
156 
157  prepareFields();
158 
159  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
160 
161  // by default provider's request is the same
163  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
164  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
165  // values
166  if ( mRequest.destinationCrs().isValid() )
167  {
169  }
170 
172  {
173  // prepare list of attributes to match provider fields
174  QSet<int> providerSubset;
176  int nPendingFields = mSource->mFields.count();
177  for ( int attrIndex : subset )
178  {
179  if ( attrIndex < 0 || attrIndex >= nPendingFields )
180  continue;
181  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
182  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
183  }
184 
185  // This is done in order to be prepared to do fallback order bys
186  // and be sure we have the required columns.
187  // TODO:
188  // It would be nicer to first check if we can compile the order by
189  // and only modify the subset if we cannot.
190  if ( !mProviderRequest.orderBy().isEmpty() )
191  {
192  const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
193  for ( int attrIndex : usedAttributeIndices )
194  {
195  providerSubset << attrIndex;
196  }
197  }
198 
199  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
200  }
201 
203  {
204  const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
205  const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
206  for ( const QString &field : constReferencedColumns )
207  {
208  int idx = source->mFields.lookupField( field );
209 
210  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
211  // In this case we disable the expression filter.
212  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
213  {
215  // can't limit at provider side
217  if ( needsGeom )
218  {
219  // have to get geometry from provider in order to evaluate expression on client
221  }
222  break;
223  }
224  }
225  }
226 
227  if ( mSource->mHasEditBuffer )
228  {
230  QgsFeatureIds changedIds;
231  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
232  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
233  {
234  changedIds << attIt.key();
235  }
237 
238  if ( mChangedFeaturesRequest.limit() > 0 )
239  {
240  int providerLimit = mProviderRequest.limit();
241 
242  // features may be deleted in buffer, so increase limit sent to provider
243  providerLimit += mSource->mDeletedFeatureIds.size();
244 
246  {
247  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
248  providerLimit += mSource->mChangedAttributeValues.size();
249  }
250 
252  {
253  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
254  providerLimit += mSource->mChangedGeometries.size();
255  }
256 
257  mProviderRequest.setLimit( providerLimit );
258  mChangedFeaturesRequest.setLimit( providerLimit );
259  }
260  }
261 
262  if ( request.filterType() == QgsFeatureRequest::FilterFid )
263  {
264  mFetchedFid = false;
265  }
266  else // no filter or filter by rect
267  {
268  if ( mSource->mHasEditBuffer )
269  {
271  }
272  else
273  {
275  }
276 
278  }
279 }
280 
281 
283 {
284  qDeleteAll( mExpressionFieldInfo );
285 
286  close();
287 }
288 
290 
296 class QgsThreadStackOverflowGuard
297 {
298  public:
299 
300  QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
301  : mStorage( storage )
302  , mMaxDepth( maxDepth )
303  {
304  if ( !storage.hasLocalData() )
305  {
306  storage.setLocalData( QStack<QString>() );
307  }
308 
309  storage.localData().push( stackFrameInformation );
310  }
311 
312  ~QgsThreadStackOverflowGuard()
313  {
314  mStorage.localData().pop();
315  }
316 
317  bool hasStackOverflow() const
318  {
319  if ( mStorage.localData().size() > mMaxDepth )
320  return true;
321  else
322  return false;
323  }
324 
325  QString topFrames() const
326  {
327  QStringList dumpStack;
328  const QStack<QString> &stack = mStorage.localData();
329 
330  int dumpSize = std::min( stack.size(), 10 );
331  for ( int i = 0; i < dumpSize; ++i )
332  {
333  dumpStack += stack.at( i );
334  }
335 
336  return dumpStack.join( '\n' );
337  }
338 
339  int depth() const
340  {
341  return mStorage.localData().size();
342  }
343 
344  private:
345  QThreadStorage<QStack<QString>> &mStorage;
346  int mMaxDepth;
347 };
348 
350 
352 {
353  f.setValid( false );
354 
355  if ( mClosed )
356  return false;
357 
358  static QThreadStorage<QStack<QString>> sStack;
359 
360  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
361 
362  if ( guard.hasStackOverflow() )
363  {
364  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 );
365  return false;
366  }
367 
369  {
370  if ( mFetchedFid )
371  return false;
372  bool res = nextFeatureFid( f );
373  if ( res && postProcessFeature( f ) )
374  {
375  mFetchedFid = true;
376  return res;
377  }
378  else
379  {
380  return false;
381  }
382  }
383 
384  if ( !mFilterRect.isNull() )
385  {
386  if ( fetchNextChangedGeomFeature( f ) )
387  return true;
388 
389  // no more changed geometries
390  }
391 
393  {
395  return true;
396 
397  if ( fetchNextChangedGeomFeature( f ) )
398  return true;
399 
400  // no more changed features
401  }
402 
403  while ( fetchNextAddedFeature( f ) )
404  {
405  return true;
406  }
407  // no more added features
408 
409  if ( mProviderIterator.isClosed() )
410  {
413  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
414  }
415 
416  while ( mProviderIterator.nextFeature( f ) )
417  {
418  if ( mFetchConsidered.contains( f.id() ) )
419  continue;
420 
421  // TODO[MD]: just one resize of attributes
422  f.setFields( mSource->mFields );
423 
424  // update attributes
425  if ( mSource->mHasEditBuffer )
427 
428  if ( mHasVirtualAttributes )
430 
432  {
433  //filtering by expression, and couldn't do it on the provider side
436  {
437  //feature did not match filter
438  continue;
439  }
440  }
441 
442  // update geometry
443  // TODO[MK]: FilterRect check after updating the geometry
446 
447  if ( !postProcessFeature( f ) )
448  continue;
449 
450  return true;
451  }
452  // no more provider features
453 
454  close();
455  return false;
456 }
457 
458 
459 
461 {
462  if ( mClosed )
463  return false;
464 
466  {
467  mFetchedFid = false;
468  }
469  else
470  {
473  }
474 
475  return true;
476 }
477 
479 {
480  if ( mClosed )
481  return false;
482 
484 
485  iteratorClosed();
486 
487  mClosed = true;
488  return true;
489 }
490 
492 {
493  mProviderIterator.setInterruptionChecker( interruptionChecker );
494  mInterruptionChecker = interruptionChecker;
495 }
496 
498 {
499  return mProviderIterator.isValid();
500 }
501 
503 {
504  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
505  {
507 
508  if ( mFetchConsidered.contains( fid ) )
509  // must have changed geometry outside rectangle
510  continue;
511 
513 
514  // can't test for feature acceptance until after calling useAddedFeature
515  // since acceptFeature may rely on virtual fields
516  if ( !mRequest.acceptFeature( f ) )
517  // skip features which are not accepted by the filter
518  continue;
519 
520  if ( !postProcessFeature( f ) )
521  continue;
522 
523  return true;
524  }
525 
527  return false; // no more added features
528 }
529 
530 
532 {
533  // since QgsFeature is implicitly shared, it's more efficient to just copy the
534  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
535  // This helps potentially avoid an unnecessary detach of the feature
536  f = src;
537  f.setValid( true );
538  f.setFields( mSource->mFields );
539 
540  if ( mHasVirtualAttributes )
542 }
543 
544 
545 
547 {
548  // check if changed geometries are in rectangle
550  {
551  QgsFeatureId fid = mFetchChangedGeomIt.key();
552 
553  if ( mFetchConsidered.contains( fid ) )
554  // skip deleted features
555  continue;
556 
557  mFetchConsidered << fid;
558 
559  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
560  // skip changed geometries not in rectangle and don't check again
561  continue;
562 
564 
566  {
569  {
570  continue;
571  }
572  }
573 
574  if ( postProcessFeature( f ) )
575  {
576  // return complete feature
578  return true;
579  }
580  }
581 
582  return false; // no more changed geometries
583 }
584 
586 {
588  {
589  if ( mFetchConsidered.contains( f.id() ) )
590  // skip deleted features and those already handled by the geometry
591  continue;
592 
593  mFetchConsidered << f.id();
594 
596 
597  if ( mHasVirtualAttributes )
599 
601  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
602  {
603  return true;
604  }
605  }
606 
607  return false;
608 }
609 
610 
612 {
613  f.setId( fid );
614  f.setValid( true );
615  f.setFields( mSource->mFields );
616 
619  {
620  f.setGeometry( geom );
621  }
622 
623  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
624  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
625  {
626  // retrieve attributes from provider
627  QgsFeature tmp;
628  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
629  QgsFeatureRequest request;
631  if ( subsetAttrs )
632  {
634  }
636  if ( fi.nextFeature( tmp ) )
637  {
640  f.setAttributes( tmp.attributes() );
641  }
642  }
643 
645 }
646 
647 
648 
650 {
652 
655 }
656 
658 {
659  if ( !mSource->mFields.exists( fieldIdx ) )
660  return;
661 
662  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
663  return;
664 
665  int sourceLayerIndex;
666  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
667  Q_ASSERT( joinInfo );
668 
669  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
670  if ( !joinLayer )
671  return; // invalid join (unresolved reference to layer)
672 
673  if ( !mFetchJoinInfo.contains( joinInfo ) )
674  {
675  FetchJoinInfo info;
676  info.joinInfo = joinInfo;
677  info.joinLayer = joinLayer;
680  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
681 
682  // for joined fields, we always need to request the targetField from the provider too
683  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
684  mFieldsToPrepare << info.targetField;
685 
688 
689  mFetchJoinInfo.insert( joinInfo, info );
690  }
691 
692  // store field source index - we'll need it when fetching from provider
693  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
694 }
695 
696 
698 {
699  static QThreadStorage<QStack<QString>> sStack;
700 
701  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
702 
703  if ( guard.hasStackOverflow() )
704  {
705  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 );
706  return;
707  }
708 
709  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
710 
711  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
712  std::unique_ptr<QgsExpression> exp = qgis::make_unique<QgsExpression>( exps[oi].cachedExpression );
713 
714  QgsDistanceArea da;
716  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
717  exp->setGeomCalculator( &da );
718  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
719  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
720 
721  if ( !mExpressionContext )
722  createExpressionContext();
723  exp->prepare( mExpressionContext.get() );
724  const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
725 
726  QSet<int> requestedAttributes = mRequest.subsetOfAttributes().toSet();
727 
728  for ( int dependentFieldIdx : referencedColumns )
729  {
731  {
732  requestedAttributes += dependentFieldIdx;
733  }
734  // also need to fetch this dependent field
735  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
736  mFieldsToPrepare << dependentFieldIdx;
737  }
738 
740  {
741  mRequest.setSubsetOfAttributes( requestedAttributes.toList() );
742  }
743 
744  if ( exp->needsGeometry() )
745  {
746  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
747  }
748 
749  mExpressionFieldInfo.insert( fieldIdx, exp.release() );
750 }
751 
753 {
754  mPreparedFields.clear();
755  mFieldsToPrepare.clear();
756  mFetchJoinInfo.clear();
757  mOrderedJoinInfoList.clear();
758 
759  mExpressionContext.reset();
760 
762 
763  while ( !mFieldsToPrepare.isEmpty() )
764  {
765  int fieldIdx = mFieldsToPrepare.takeFirst();
766  if ( mPreparedFields.contains( fieldIdx ) )
767  continue;
768 
769  mPreparedFields << fieldIdx;
770  prepareField( fieldIdx );
771  }
772 
773  //sort joins by dependency
774  if ( !mFetchJoinInfo.empty() )
775  {
776  createOrderedJoinList();
777  }
778 }
779 
780 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
781 {
782  mOrderedJoinInfoList = mFetchJoinInfo.values();
783  if ( mOrderedJoinInfoList.size() < 2 )
784  {
785  return;
786  }
787 
788  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
789 
790  //add all provider fields without joins as resolved fields
791  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
792  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
793  {
794  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
795  {
796  resolvedFields.insert( *prepFieldIt );
797  }
798  }
799 
800  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
801 
802  //some join combinations might not have a resolution at all
803  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
804  int currentIteration = 0;
805 
806  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
807  {
808  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
809  {
810  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
811  mOrderedJoinInfoList.removeAt( i );
812  --i;
813  }
814  else
815  {
816  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
817  int joinField = mOrderedJoinInfoList.at( i ).joinField;
818 
819  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
820  for ( int n = 0; n < attributes.size(); n++ )
821  {
822  if ( n != joinField )
823  {
824  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
825  }
826  }
827  }
828 
829  ++currentIteration;
830  if ( currentIteration >= maxIterations )
831  {
832  break;
833  }
834  }
835 }
836 
837 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
838 {
839  bool result = checkGeometryValidity( feature );
840  if ( result )
842  return result;
843 }
844 
845 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
846 {
847  if ( !feature.hasGeometry() )
848  return true;
849 
850  switch ( mRequest.invalidGeometryCheck() )
851  {
853  return true;
854 
856  {
857  if ( !feature.geometry().isGeosValid() )
858  {
859  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
861  {
862  mRequest.invalidGeometryCallback()( feature );
863  }
864  return false;
865  }
866  break;
867  }
868 
870  if ( !feature.geometry().isGeosValid() )
871  {
872  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
873  close();
875  {
876  mRequest.invalidGeometryCallback()( feature );
877  }
878  return false;
879  }
880  break;
881  }
882 
883  return true;
884 }
885 
887 {
888  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
889  {
891  prepareExpression( fieldIdx );
892  break;
893 
896  {
897  prepareJoin( fieldIdx );
898  }
899  break;
900 
904  break;
905  }
906 }
907 
909 {
910  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
911  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
912  {
913  QVariant targetFieldValue = f.attribute( joinIt->targetField );
914  if ( !targetFieldValue.isValid() )
915  continue;
916 
917  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
918  if ( memoryCache.isEmpty() )
919  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
920  else
921  joinIt->addJoinedAttributesCached( f, targetFieldValue );
922  }
923 }
924 
926 {
927  // make sure we have space for newly added attributes
928  QgsAttributes attr = f.attributes();
929  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
930  f.setAttributes( attr );
931 
932  // possible TODO - handle combinations of expression -> join -> expression -> join?
933  // but for now, write that off as too complex and an unlikely rare, unsupported use case
934 
935  QList< int > fetchedVirtualAttributes;
936  //first, check through joins for any virtual fields we need
937  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
938  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
939  {
940  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
941  {
942  // have to calculate expression field before we can handle this join
943  addExpressionAttribute( f, joinIt->targetField );
944  fetchedVirtualAttributes << joinIt->targetField;
945  }
946  }
947 
948  if ( !mFetchJoinInfo.isEmpty() )
949  addJoinedAttributes( f );
950 
951  // add remaining expression fields
952  if ( !mExpressionFieldInfo.isEmpty() )
953  {
954  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
955  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
956  {
957  if ( fetchedVirtualAttributes.contains( it.key() ) )
958  continue;
959 
960  addExpressionAttribute( f, it.key() );
961  }
962  }
963 }
964 
966 {
967  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
968  if ( exp )
969  {
970  if ( !mExpressionContext )
971  createExpressionContext();
972 
973  mExpressionContext->setFeature( f );
974  QVariant val = exp->evaluate( mExpressionContext.get() );
975  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
976  f.setAttribute( attrIndex, val );
977  }
978  else
979  {
980  f.setAttribute( attrIndex, QVariant() );
981  }
982 }
983 
985 {
986  Q_UNUSED( simplifyMethod )
987  return false;
988 }
989 
990 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
991 {
992  Q_UNUSED( methodType )
993  return false;
994 }
995 
996 
998 {
999  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1000  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1001  if ( it == memoryCache.constEnd() )
1002  return; // joined value not found -> leaving the attributes empty (null)
1003 
1004  int index = indexOffset;
1005 
1006  const QgsAttributes &featureAttributes = it.value();
1007  for ( int i = 0; i < featureAttributes.count(); ++i )
1008  {
1009  f.setAttribute( index++, featureAttributes.at( i ) );
1010  }
1011 }
1012 
1013 
1014 
1016 {
1017  // no memory cache, query the joined values by setting substring
1018  QString subsetString;
1019 
1020  QString joinFieldName = joinInfo->joinFieldName();
1021 
1022  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1023 
1024  if ( joinValue.isNull() )
1025  {
1026  subsetString += QLatin1String( " IS NULL" );
1027  }
1028  else
1029  {
1030  QString v = joinValue.toString();
1031  switch ( joinValue.type() )
1032  {
1033  case QVariant::Int:
1034  case QVariant::LongLong:
1035  case QVariant::Double:
1036  break;
1037 
1038  default:
1039  case QVariant::String:
1040  v.replace( '\'', QLatin1String( "''" ) );
1041  v.prepend( '\'' ).append( '\'' );
1042  break;
1043  }
1044  subsetString += '=' + v;
1045  }
1046 
1047  // maybe user requested just a subset of layer's attributes
1048  // so we do not have to cache everything
1049  QVector<int> subsetIndices;
1050  if ( joinInfo->hasSubset() )
1051  {
1052  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1053  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
1054  }
1055 
1056  // select (no geometry)
1057  QgsFeatureRequest request;
1059  request.setSubsetOfAttributes( attributes );
1060  request.setFilterExpression( subsetString );
1061  request.setLimit( 1 );
1062  QgsFeatureIterator fi = joinLayer->getFeatures( request );
1063 
1064  // get first feature
1065  QgsFeature fet;
1066  if ( fi.nextFeature( fet ) )
1067  {
1068  int index = indexOffset;
1069  QgsAttributes attr = fet.attributes();
1070  if ( joinInfo->hasSubset() )
1071  {
1072  for ( int i = 0; i < subsetIndices.count(); ++i )
1073  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
1074  }
1075  else
1076  {
1077  // use all fields except for the one used for join (has same value as exiting field in target layer)
1078  for ( int i = 0; i < attr.count(); ++i )
1079  {
1080  if ( i == joinField )
1081  continue;
1082 
1083  f.setAttribute( index++, attr.at( i ) );
1084  }
1085  }
1086  }
1087  else
1088  {
1089  // no suitable join feature found, keeping empty (null) attributes
1090  }
1091 }
1092 
1093 
1094 
1095 
1097 {
1098  QgsFeatureId featureId = mRequest.filterFid();
1099 
1100  // deleted already?
1101  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1102  return false;
1103 
1104  // has changed geometry?
1105  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1106  {
1107  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1108  return true;
1109  }
1110 
1111  // added features
1112  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1113  {
1114  if ( iter->id() == featureId )
1115  {
1116  useAddedFeature( *iter, f );
1117  return true;
1118  }
1119  }
1120 
1121  // regular features
1123  if ( fi.nextFeature( f ) )
1124  {
1125  f.setFields( mSource->mFields );
1126 
1127  if ( mSource->mHasEditBuffer )
1129 
1130  if ( mHasVirtualAttributes )
1131  addVirtualAttributes( f );
1132 
1133  return true;
1134  }
1135 
1136  return false;
1137 }
1138 
1140 {
1141  QgsAttributes attrs = f.attributes();
1142 
1143  // remove all attributes that will disappear - from higher indices to lower
1144  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1145  {
1146  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1147  }
1148 
1149  // adjust size to accommodate added attributes
1150  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1151 
1152  // update changed attributes
1153  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1154  {
1156  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1157  attrs[it.key()] = it.value();
1158  }
1159  f.setAttributes( attrs );
1160 }
1161 
1163 {
1164  if ( mSource->mChangedGeometries.contains( f.id() ) )
1166 }
1167 
1168 void QgsVectorLayerFeatureIterator::createExpressionContext()
1169 {
1170  mExpressionContext = qgis::make_unique< QgsExpressionContext >();
1171  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1172  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1173  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1174 }
1175 
1176 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1177 {
1178  Q_UNUSED( orderBys )
1179  return true;
1180 }
1181 
1182 
1183 //
1184 // QgsVectorLayerSelectedFeatureSource
1185 //
1186 
1188  : mSource( layer )
1189  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1190  , mWkbType( layer->wkbType() )
1191  , mName( layer->name() )
1192  , mLayer( layer )
1193 {}
1194 
1196 {
1197  QgsFeatureRequest req( request );
1198 
1199  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1200  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1201  // allows providers to optimise the request and avoid requesting features we don't need
1202  // note that we can't do this for some request types - e.g. expression based requests, so
1203  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1204  // do ALL the filtering
1205  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1206  {
1207  req.setFilterFids( mSelectedFeatureIds );
1208  }
1209  else if ( !req.filterFids().isEmpty() )
1210  {
1211  QgsFeatureIds reqIds = mSelectedFeatureIds;
1212  reqIds.intersect( req.filterFids() );
1213  req.setFilterFids( reqIds );
1214  }
1215 
1216  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1217 }
1218 
1220 {
1221  return mSource.crs();
1222 }
1223 
1225 {
1226  return mSource.fields();
1227 }
1228 
1230 {
1231  return mWkbType;
1232 }
1233 
1235 {
1236  return mSelectedFeatureIds.count();
1237 }
1238 
1240 {
1241  return mName;
1242 }
1243 
1245 {
1246  if ( mLayer )
1247  return mLayer->createExpressionContextScope();
1248  else
1249  return nullptr;
1250 }
1251 
1252 //
1253 // QgsVectorLayerSelectedFeatureIterator
1254 //
1255 
1257 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1258  : QgsAbstractFeatureIterator( request )
1259  , mSelectedFeatureIds( selectedFeatureIds )
1260 {
1261  QgsFeatureRequest sourceRequest = request;
1262  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1263  {
1264  // we can't pass the request limit to the provider here - otherwise the provider will
1265  // limit the number of returned features and may only return a bunch of matching features
1266  // which AREN'T in the selected feature set
1267  sourceRequest.setLimit( -1 );
1268  }
1269  mIterator = source.getFeatures( sourceRequest );
1270 }
1271 
1272 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1273 {
1274  return mIterator.rewind();
1275 }
1276 
1277 bool QgsVectorLayerSelectedFeatureIterator::close()
1278 {
1279  return mIterator.close();
1280 }
1281 
1282 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1283 {
1284  while ( mIterator.nextFeature( f ) )
1285  {
1286  if ( mSelectedFeatureIds.contains( f.id() ) )
1287  return true;
1288  }
1289  return false;
1290 }
1291 
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
QList< QgsExpressionFieldBuffer::ExpressionField > expressions() const
QgsAbstractFeatureSource * mProviderFeatureSource
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
QgsFeatureId id
Definition: qgsfeature.h:64
void addJoinedAttributesDirect(QgsFeature &f, const QVariant &joinValue) const
Wrapper for iterator of features from vector data provider or vector layer.
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:566
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
void geometryToDestinationCrs(QgsFeature &feature, const QgsCoordinateTransform &transform) const
Transforms feature&#39;s geometry according to the specified coordinate transform.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
Filter using feature ID.
QgsVectorLayerJoinBuffer * mJoinBuffer
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system for features retrieved from this source.
bool containsJoins() const
Quick way to test if there is any join at all.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:50
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
void setInterruptionChecker(QgsFeedback *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped...
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:162
QString sourceName() const override
Returns a friendly display name for the source.
const Flags & flags() const
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
QString name
Definition: qgsfield.h:58
QMap< int, QgsExpression * > mExpressionFieldInfo
void addExpressionAttribute(QgsFeature &f, int attrIndex)
Adds an expression based attribute to a feature.
QgsFeatureMap::ConstIterator mFetchAddedFeaturesIt
QgsGeometryMap::ConstIterator mFetchChangedGeomIt
QgsRectangle filterRectToSourceCrs(const QgsCoordinateTransform &transform) const SIP_THROW(QgsCsException)
Returns a rectangle representing the original request&#39;s QgsFeatureRequest::filterRect().
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:51
bool exists(int i) const
Returns if a field index is valid.
Definition: qgsfields.cpp:153
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
QgsVectorLayerSelectedFeatureSource(QgsVectorLayer *layer)
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified layer...
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Gets an iterator for features matching the specified request.
QgsFeatureId filterFid() const
Gets the feature ID that should be fetched.
QVariant evaluate()
Evaluate the feature and return the result.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature&#39;s geometries, or an invalid QgsCoordi...
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Gets an iterator for features matching the specified request.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:281
FilterType filterType() const
Returns the filter type which is currently set on this request.
Container of fields for a vector layer.
Definition: qgsfields.h:42
const QgsFeatureIds & filterFids() const
Gets feature IDs that should be fetched.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:49
bool mClosed
Sets to true, as soon as the iterator is closed.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed. ...
const QgsAttributeList & attributeIndexes
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsVectorLayer * joinLayer
Resolved pointer to the joined layer.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
It has not been specified where the field comes from.
Definition: qgsfields.h:48
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int joinField
Index of field (of the joined layer) must have equal value.
QgsExpression * filterExpression() const
Returns the filter expression if set.
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider&#39;s data.
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:44
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
void iteratorClosed()
to be called by from subclass in close()
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
void useAddedFeature(const QgsFeature &src, QgsFeature &f)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
bool isGeosValid(QgsGeometry::ValidityFlags flags=nullptr) const
Checks validity of the geometry using GEOS.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet) ...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:351
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source...
QgsFeatureRequest & disableFilter()
Disables filter conditions.
Internal feature iterator to be implemented within data providers.
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod) override
Setup the simplification of geometries to fetch using the specified simplify method.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const
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).
Defines left outer join from our vector layer to some other vector layer.
void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped...
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
bool fetchFeature(QgsFeature &feature) override
fetch next feature, return true on success
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
No invalid geometry checking.
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:112
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsExpressionFieldBuffer * mExpressionFieldBuffer
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
int indexOffset
At what position the joined fields start.
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:96
void useChangedAttributeFeature(QgsFeatureId fid, const QgsGeometry &geom, QgsFeature &f)
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown...
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
QgsFeatureRequest mRequest
A copy of the feature request.
int targetField
Index of field (of this layer) that drives the join.
Buffers information about expression fields for a vector layer.
No filter is applied.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:557
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool rewind() override
reset the iterator to the starting position
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
QMap< const QgsVectorLayerJoinInfo *, QgsVectorLayerFeatureIterator::FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
This class represents a coordinate reference system (CRS).
bool close() override
end of iterating: free the resources / lock
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.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
InvalidGeometryCheck invalidGeometryCheck() const
Returns the invalid geometry checking behavior.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Class for doing transforms between two map coordinate systems.
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
QgsGeometry geometry
Definition: qgsfeature.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
QString id() const
Returns the layer id of the source layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
QgsChangedAttributesMap mChangedAttributeValues
OrderBy orderBy() const
Returns a list of order by clauses specified for this feature request.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QList< QgsField > addedAttributes() const
Returns a list of added attributes fields which are not committed.
A vector of attributes.
Definition: qgsattributes.h:57
Represents a vector layer which manages a vector based data sets.
bool isValid() const override
Returns if this iterator is valid.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
Field is calculated from an expression.
Definition: qgsfields.h:52
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
QgsCoordinateTransformContext transformContext() const
Returns the transform context, for use when a destinationCrs() has been set and reprojection is requi...
virtual bool isValid() const
Will return if this iterator is valid.
bool isClosed() const
find out whether the iterator is still valid or closed already
QgsVectorLayerFeatureSource(const QgsVectorLayer *layer)
Constructor for QgsVectorLayerFeatureSource.
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
QgsAttributes attributes
Definition: qgsfeature.h:65
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
std::function< void(const QgsFeature &) > invalidGeometryCallback() const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:86
int joinedFieldsOffset(const QgsVectorLayerJoinInfo *info, const QgsFields &fields)
Find out what is the first index of the join within fields.
QgsVectorLayerJoinBuffer * clone() const
Create a copy of the join buffer.
void addVirtualAttributes(QgsFeature &f)
Adds attributes that don&#39;t source from the provider but are added inside QGIS Includes.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Helper template that cares of two things: 1.
QSet< int > CORE_EXPORT usedAttributeIndices(const QgsFields &fields) const
Returns a set of used, validated attribute indices.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.