QGIS API Documentation  3.17.0-Master (a035f434f4)
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 
143  // check whether the order by clause(s) can be delegated to the provider
144  mDelegatedOrderByToProvider = !mSource->mHasEditBuffer;
145  if ( !mRequest.orderBy().isEmpty() )
146  {
147  QSet<int> attributeIndexes;
148  const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
149  for ( int attrIndex : usedAttributeIndices )
150  {
151  if ( mSource->mFields.fieldOrigin( attrIndex ) != QgsFields::OriginProvider )
152  mDelegatedOrderByToProvider = false;
153 
154  attributeIndexes << attrIndex;
155  }
156 
157  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mDelegatedOrderByToProvider )
158  {
159  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
160  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
161  }
162  }
163 
165  {
168 
170  {
171  // ensure that all fields required for filter expressions are prepared
173  attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
174  mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
175  }
176  }
177 
178  prepareFields();
179 
180  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
181 
182  // by default provider's request is the same
184  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
185  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
186  // values
187  if ( mRequest.destinationCrs().isValid() )
188  {
190  }
191 
192  if ( !mDelegatedOrderByToProvider )
193  {
195  }
196 
198  {
199  // prepare list of attributes to match provider fields
200  QSet<int> providerSubset;
202  int nPendingFields = mSource->mFields.count();
203  for ( int attrIndex : subset )
204  {
205  if ( attrIndex < 0 || attrIndex >= nPendingFields )
206  continue;
207  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
208  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
209  }
210 
211  // This is done in order to be prepared to do fallback order bys
212  // and be sure we have the required columns.
213  // TODO:
214  // It would be nicer to first check if we can compile the order by
215  // and only modify the subset if we cannot.
216  if ( !mProviderRequest.orderBy().isEmpty() )
217  {
218  const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
219  for ( int attrIndex : usedAttributeIndices )
220  {
221  providerSubset << attrIndex;
222  }
223  }
224 
225  mProviderRequest.setSubsetOfAttributes( qgis::setToList( providerSubset ) );
226  }
227 
229  {
230  const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
231  const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
232  for ( const QString &field : constReferencedColumns )
233  {
234  int idx = source->mFields.lookupField( field );
235 
236  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
237  // In this case we disable the expression filter.
238  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
239  {
241  // can't limit at provider side
243  if ( needsGeom )
244  {
245  // have to get geometry from provider in order to evaluate expression on client
247  }
248  break;
249  }
250  }
251  }
252 
253  if ( mSource->mHasEditBuffer )
254  {
256  QgsFeatureIds changedIds;
257  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
258  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
259  {
260  changedIds << attIt.key();
261  }
263 
264  if ( mChangedFeaturesRequest.limit() > 0 )
265  {
266  int providerLimit = mProviderRequest.limit();
267 
268  // features may be deleted in buffer, so increase limit sent to provider
269  providerLimit += mSource->mDeletedFeatureIds.size();
270 
272  {
273  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
274  providerLimit += mSource->mChangedAttributeValues.size();
275  }
276 
278  {
279  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
280  providerLimit += mSource->mChangedGeometries.size();
281  }
282 
283  mProviderRequest.setLimit( providerLimit );
284  mChangedFeaturesRequest.setLimit( providerLimit );
285  }
286  }
287 
288  if ( request.filterType() == QgsFeatureRequest::FilterFid )
289  {
290  mFetchedFid = false;
291  }
292  else // no filter or filter by rect
293  {
294  if ( mSource->mHasEditBuffer )
295  {
297  }
298  else
299  {
301  }
302 
304  }
305 }
306 
307 
309 {
310  qDeleteAll( mExpressionFieldInfo );
311 
312  close();
313 }
314 
316 
322 class QgsThreadStackOverflowGuard
323 {
324  public:
325 
326  QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
327  : mStorage( storage )
328  , mMaxDepth( maxDepth )
329  {
330  if ( !storage.hasLocalData() )
331  {
332  storage.setLocalData( QStack<QString>() );
333  }
334 
335  storage.localData().push( stackFrameInformation );
336  }
337 
338  ~QgsThreadStackOverflowGuard()
339  {
340  mStorage.localData().pop();
341  }
342 
343  bool hasStackOverflow() const
344  {
345  if ( mStorage.localData().size() > mMaxDepth )
346  return true;
347  else
348  return false;
349  }
350 
351  QString topFrames() const
352  {
353  QStringList dumpStack;
354  const QStack<QString> &stack = mStorage.localData();
355 
356  int dumpSize = std::min( stack.size(), 10 );
357  for ( int i = 0; i < dumpSize; ++i )
358  {
359  dumpStack += stack.at( i );
360  }
361 
362  return dumpStack.join( '\n' );
363  }
364 
365  int depth() const
366  {
367  return mStorage.localData().size();
368  }
369 
370  private:
371  QThreadStorage<QStack<QString>> &mStorage;
372  int mMaxDepth;
373 };
374 
376 
378 {
379  f.setValid( false );
380 
381  if ( mClosed )
382  return false;
383 
384  static QThreadStorage<QStack<QString>> sStack;
385 
386  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
387 
388  if ( guard.hasStackOverflow() )
389  {
390  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 );
391  return false;
392  }
393 
395  {
396  if ( mFetchedFid )
397  return false;
398  bool res = nextFeatureFid( f );
399  if ( res && postProcessFeature( f ) )
400  {
401  mFetchedFid = true;
402  return res;
403  }
404  else
405  {
406  return false;
407  }
408  }
409 
410  if ( !mFilterRect.isNull() )
411  {
412  if ( fetchNextChangedGeomFeature( f ) )
413  return true;
414 
415  // no more changed geometries
416  }
417 
419  {
421  return true;
422 
423  if ( fetchNextChangedGeomFeature( f ) )
424  return true;
425 
426  // no more changed features
427  }
428 
429  while ( fetchNextAddedFeature( f ) )
430  {
431  return true;
432  }
433  // no more added features
434 
435  if ( mProviderIterator.isClosed() )
436  {
439  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
440  }
441 
442  while ( mProviderIterator.nextFeature( f ) )
443  {
444  if ( mFetchConsidered.contains( f.id() ) )
445  continue;
446 
447  // TODO[MD]: just one resize of attributes
448  f.setFields( mSource->mFields );
449 
450  // update attributes
451  if ( mSource->mHasEditBuffer )
453 
454  if ( mHasVirtualAttributes )
456 
458  {
459  //filtering by expression, and couldn't do it on the provider side
462  {
463  //feature did not match filter
464  continue;
465  }
466  }
467 
468  // update geometry
469  // TODO[MK]: FilterRect check after updating the geometry
472 
473  if ( !postProcessFeature( f ) )
474  continue;
475 
476  return true;
477  }
478  // no more provider features
479 
480  close();
481  return false;
482 }
483 
484 
485 
487 {
488  if ( mClosed )
489  return false;
490 
492  {
493  mFetchedFid = false;
494  }
495  else
496  {
499  }
500 
501  return true;
502 }
503 
505 {
506  if ( mClosed )
507  return false;
508 
510 
511  iteratorClosed();
512 
513  mClosed = true;
514  return true;
515 }
516 
518 {
519  mProviderIterator.setInterruptionChecker( interruptionChecker );
520  mInterruptionChecker = interruptionChecker;
521 }
522 
524 {
525  return mProviderIterator.isValid();
526 }
527 
529 {
530  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
531  {
533 
534  if ( mFetchConsidered.contains( fid ) )
535  // must have changed geometry outside rectangle
536  continue;
537 
539 
540  // can't test for feature acceptance until after calling useAddedFeature
541  // since acceptFeature may rely on virtual fields
542  if ( !mRequest.acceptFeature( f ) )
543  // skip features which are not accepted by the filter
544  continue;
545 
546  if ( !postProcessFeature( f ) )
547  continue;
548 
549  return true;
550  }
551 
553  return false; // no more added features
554 }
555 
556 
558 {
559  // since QgsFeature is implicitly shared, it's more efficient to just copy the
560  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
561  // This helps potentially avoid an unnecessary detach of the feature
562  f = src;
563  f.setValid( true );
564  f.setFields( mSource->mFields );
565 
566  if ( mHasVirtualAttributes )
568 }
569 
570 
571 
573 {
574  // check if changed geometries are in rectangle
576  {
577  QgsFeatureId fid = mFetchChangedGeomIt.key();
578 
579  if ( mFetchConsidered.contains( fid ) )
580  // skip deleted features
581  continue;
582 
583  mFetchConsidered << fid;
584 
585  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
586  // skip changed geometries not in rectangle and don't check again
587  continue;
588 
590 
592  {
595  {
596  continue;
597  }
598  }
599 
600  if ( postProcessFeature( f ) )
601  {
602  // return complete feature
604  return true;
605  }
606  }
607 
608  return false; // no more changed geometries
609 }
610 
612 {
614  {
615  if ( mFetchConsidered.contains( f.id() ) )
616  // skip deleted features and those already handled by the geometry
617  continue;
618 
619  mFetchConsidered << f.id();
620 
622 
623  if ( mHasVirtualAttributes )
625 
627  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
628  {
629  return true;
630  }
631  }
632 
633  return false;
634 }
635 
636 
638 {
639  f.setId( fid );
640  f.setValid( true );
641  f.setFields( mSource->mFields );
642 
645  {
646  f.setGeometry( geom );
647  }
648 
649  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
650  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
651  {
652  // retrieve attributes from provider
653  QgsFeature tmp;
654  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
655  QgsFeatureRequest request;
657  if ( subsetAttrs )
658  {
660  }
662  if ( fi.nextFeature( tmp ) )
663  {
666  f.setAttributes( tmp.attributes() );
667  }
668  }
669 
671 }
672 
673 
674 
676 {
678 
681 }
682 
684 {
685  if ( !mSource->mFields.exists( fieldIdx ) )
686  return;
687 
688  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
689  return;
690 
691  int sourceLayerIndex;
692  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
693  Q_ASSERT( joinInfo );
694 
695  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
696  if ( !joinLayer )
697  return; // invalid join (unresolved reference to layer)
698 
699  if ( !mFetchJoinInfo.contains( joinInfo ) )
700  {
701  FetchJoinInfo info;
702  info.joinInfo = joinInfo;
703  info.joinLayer = joinLayer;
706  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
707 
708  // for joined fields, we always need to request the targetField from the provider too
709  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
710  mFieldsToPrepare << info.targetField;
711 
714 
715  mFetchJoinInfo.insert( joinInfo, info );
716  }
717 
718  // store field source index - we'll need it when fetching from provider
719  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
720 }
721 
722 
724 {
725  static QThreadStorage<QStack<QString>> sStack;
726 
727  QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
728 
729  if ( guard.hasStackOverflow() )
730  {
731  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 );
732  return;
733  }
734 
735  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
736 
737  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
738  std::unique_ptr<QgsExpression> exp = qgis::make_unique<QgsExpression>( exps[oi].cachedExpression );
739 
740  QgsDistanceArea da;
742  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
743  exp->setGeomCalculator( &da );
744  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
745  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
746 
747  if ( !mExpressionContext )
748  createExpressionContext();
749  exp->prepare( mExpressionContext.get() );
750  const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
751 
752  QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
753 
754  for ( int dependentFieldIdx : referencedColumns )
755  {
757  {
758  requestedAttributes += dependentFieldIdx;
759  }
760  // also need to fetch this dependent field
761  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
762  mFieldsToPrepare << dependentFieldIdx;
763  }
764 
766  {
767  mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
768  }
769 
770  if ( exp->needsGeometry() )
771  {
772  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
773  }
774 
775  mExpressionFieldInfo.insert( fieldIdx, exp.release() );
776 }
777 
779 {
780  mPreparedFields.clear();
781  mFieldsToPrepare.clear();
782  mFetchJoinInfo.clear();
783  mOrderedJoinInfoList.clear();
784 
785  mExpressionContext.reset();
786 
788 
789  while ( !mFieldsToPrepare.isEmpty() )
790  {
791  int fieldIdx = mFieldsToPrepare.takeFirst();
792  if ( mPreparedFields.contains( fieldIdx ) )
793  continue;
794 
795  mPreparedFields << fieldIdx;
796  prepareField( fieldIdx );
797  }
798 
799  //sort joins by dependency
800  if ( !mFetchJoinInfo.empty() )
801  {
802  createOrderedJoinList();
803  }
804 }
805 
806 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
807 {
808  mOrderedJoinInfoList = mFetchJoinInfo.values();
809  if ( mOrderedJoinInfoList.size() < 2 )
810  {
811  return;
812  }
813 
814  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
815 
816  //add all provider fields without joins as resolved fields
817  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
818  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
819  {
820  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
821  {
822  resolvedFields.insert( *prepFieldIt );
823  }
824  }
825 
826  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
827 
828  //some join combinations might not have a resolution at all
829  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
830  int currentIteration = 0;
831 
832  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
833  {
834  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
835  {
836  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
837  mOrderedJoinInfoList.removeAt( i );
838  --i;
839  }
840  else
841  {
842  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
843  int joinField = mOrderedJoinInfoList.at( i ).joinField;
844 
845  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
846  for ( int n = 0; n < attributes.size(); n++ )
847  {
848  if ( n != joinField )
849  {
850  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
851  }
852  }
853  }
854 
855  ++currentIteration;
856  if ( currentIteration >= maxIterations )
857  {
858  break;
859  }
860  }
861 }
862 
863 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
864 {
865  bool result = checkGeometryValidity( feature );
866  if ( result )
868  return result;
869 }
870 
871 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
872 {
873  if ( !feature.hasGeometry() )
874  return true;
875 
876  switch ( mRequest.invalidGeometryCheck() )
877  {
879  return true;
880 
882  {
883  if ( !feature.geometry().isGeosValid() )
884  {
885  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
887  {
888  mRequest.invalidGeometryCallback()( feature );
889  }
890  return false;
891  }
892  break;
893  }
894 
896  if ( !feature.geometry().isGeosValid() )
897  {
898  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
899  close();
901  {
902  mRequest.invalidGeometryCallback()( feature );
903  }
904  return false;
905  }
906  break;
907  }
908 
909  return true;
910 }
911 
913 {
914  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
915  {
917  prepareExpression( fieldIdx );
918  break;
919 
922  {
923  prepareJoin( fieldIdx );
924  }
925  break;
926 
930  break;
931  }
932 }
933 
935 {
936  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
937  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
938  {
939  QVariant targetFieldValue = f.attribute( joinIt->targetField );
940  if ( !targetFieldValue.isValid() )
941  continue;
942 
943  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
944  if ( memoryCache.isEmpty() )
945  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
946  else
947  joinIt->addJoinedAttributesCached( f, targetFieldValue );
948  }
949 }
950 
952 {
953  // make sure we have space for newly added attributes
954  QgsAttributes attr = f.attributes();
955  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
956  f.setAttributes( attr );
957 
958  // possible TODO - handle combinations of expression -> join -> expression -> join?
959  // but for now, write that off as too complex and an unlikely rare, unsupported use case
960 
961  QList< int > fetchedVirtualAttributes;
962  //first, check through joins for any virtual fields we need
963  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
964  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
965  {
966  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
967  {
968  // have to calculate expression field before we can handle this join
969  addExpressionAttribute( f, joinIt->targetField );
970  fetchedVirtualAttributes << joinIt->targetField;
971  }
972  }
973 
974  if ( !mFetchJoinInfo.isEmpty() )
975  addJoinedAttributes( f );
976 
977  // add remaining expression fields
978  if ( !mExpressionFieldInfo.isEmpty() )
979  {
980  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
981  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
982  {
983  if ( fetchedVirtualAttributes.contains( it.key() ) )
984  continue;
985 
986  addExpressionAttribute( f, it.key() );
987  }
988  }
989 }
990 
992 {
993  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
994  if ( exp )
995  {
996  if ( !mExpressionContext )
997  createExpressionContext();
998 
999  mExpressionContext->setFeature( f );
1000  QVariant val = exp->evaluate( mExpressionContext.get() );
1001  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1002  f.setAttribute( attrIndex, val );
1003  }
1004  else
1005  {
1006  f.setAttribute( attrIndex, QVariant() );
1007  }
1008 }
1009 
1011 {
1012  Q_UNUSED( simplifyMethod )
1013  return false;
1014 }
1015 
1016 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1017 {
1018  Q_UNUSED( methodType )
1019  return false;
1020 }
1021 
1022 
1024 {
1025  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1026  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1027  if ( it == memoryCache.constEnd() )
1028  return; // joined value not found -> leaving the attributes empty (null)
1029 
1030  int index = indexOffset;
1031 
1032  const QgsAttributes &featureAttributes = it.value();
1033  for ( int i = 0; i < featureAttributes.count(); ++i )
1034  {
1035  f.setAttribute( index++, featureAttributes.at( i ) );
1036  }
1037 }
1038 
1039 
1040 
1042 {
1043  // Shortcut
1044  if ( joinLayer && ! joinLayer->hasFeatures() )
1045  {
1046  return;
1047  }
1048 
1049  // no memory cache, query the joined values by setting substring
1050  QString subsetString;
1051 
1052  QString joinFieldName = joinInfo->joinFieldName();
1053 
1054  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1055 
1056  if ( joinValue.isNull() )
1057  {
1058  subsetString += QLatin1String( " IS NULL" );
1059  }
1060  else
1061  {
1062  QString v = joinValue.toString();
1063  switch ( joinValue.type() )
1064  {
1065  case QVariant::Int:
1066  case QVariant::LongLong:
1067  case QVariant::Double:
1068  break;
1069 
1070  default:
1071  case QVariant::String:
1072  v.replace( '\'', QLatin1String( "''" ) );
1073  v.prepend( '\'' ).append( '\'' );
1074  break;
1075  }
1076  subsetString += '=' + v;
1077  }
1078 
1079  // maybe user requested just a subset of layer's attributes
1080  // so we do not have to cache everything
1081  QVector<int> subsetIndices;
1082  if ( joinInfo->hasSubset() )
1083  {
1084  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1085  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
1086  }
1087 
1088  // select (no geometry)
1089  QgsFeatureRequest request;
1091  request.setSubsetOfAttributes( attributes );
1092  request.setFilterExpression( subsetString );
1093  request.setLimit( 1 );
1094  QgsFeatureIterator fi = joinLayer->getFeatures( request );
1095 
1096  // get first feature
1097  QgsFeature fet;
1098  if ( fi.nextFeature( fet ) )
1099  {
1100  int index = indexOffset;
1101  QgsAttributes attr = fet.attributes();
1102  if ( joinInfo->hasSubset() )
1103  {
1104  for ( int i = 0; i < subsetIndices.count(); ++i )
1105  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
1106  }
1107  else
1108  {
1109  // use all fields except for the one used for join (has same value as exiting field in target layer)
1110  for ( int i = 0; i < attr.count(); ++i )
1111  {
1112  if ( i == joinField )
1113  continue;
1114 
1115  f.setAttribute( index++, attr.at( i ) );
1116  }
1117  }
1118  }
1119  else
1120  {
1121  // no suitable join feature found, keeping empty (null) attributes
1122  }
1123 }
1124 
1125 
1126 
1127 
1129 {
1130  QgsFeatureId featureId = mRequest.filterFid();
1131 
1132  // deleted already?
1133  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1134  return false;
1135 
1136  // has changed geometry?
1137  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1138  {
1139  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1140  return true;
1141  }
1142 
1143  // added features
1144  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1145  {
1146  if ( iter->id() == featureId )
1147  {
1148  useAddedFeature( *iter, f );
1149  return true;
1150  }
1151  }
1152 
1153  // regular features
1155  if ( fi.nextFeature( f ) )
1156  {
1157  f.setFields( mSource->mFields );
1158 
1159  if ( mSource->mHasEditBuffer )
1161 
1162  if ( mHasVirtualAttributes )
1163  addVirtualAttributes( f );
1164 
1165  return true;
1166  }
1167 
1168  return false;
1169 }
1170 
1172 {
1173  QgsAttributes attrs = f.attributes();
1174 
1175  // remove all attributes that will disappear - from higher indices to lower
1176  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1177  {
1178  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1179  }
1180 
1181  // adjust size to accommodate added attributes
1182  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1183 
1184  // update changed attributes
1185  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1186  {
1188  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1189  attrs[it.key()] = it.value();
1190  }
1191  f.setAttributes( attrs );
1192 }
1193 
1195 {
1196  if ( mSource->mChangedGeometries.contains( f.id() ) )
1198 }
1199 
1200 void QgsVectorLayerFeatureIterator::createExpressionContext()
1201 {
1202  mExpressionContext = qgis::make_unique< QgsExpressionContext >();
1203  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1204  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1205  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1206 }
1207 
1208 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1209 {
1210  Q_UNUSED( orderBys )
1211  return mDelegatedOrderByToProvider;
1212 }
1213 
1214 
1215 //
1216 // QgsVectorLayerSelectedFeatureSource
1217 //
1218 
1220  : mSource( layer )
1221  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1222  , mWkbType( layer->wkbType() )
1223  , mName( layer->name() )
1224  , mLayer( layer )
1225 {}
1226 
1228 {
1229  QgsFeatureRequest req( request );
1230 
1231  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1232  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1233  // allows providers to optimise the request and avoid requesting features we don't need
1234  // note that we can't do this for some request types - e.g. expression based requests, so
1235  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1236  // do ALL the filtering
1237  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1238  {
1239  req.setFilterFids( mSelectedFeatureIds );
1240  }
1241  else if ( !req.filterFids().isEmpty() )
1242  {
1243  QgsFeatureIds reqIds = mSelectedFeatureIds;
1244  reqIds.intersect( req.filterFids() );
1245  req.setFilterFids( reqIds );
1246  }
1247 
1248  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1249 }
1250 
1252 {
1253  return mSource.crs();
1254 }
1255 
1257 {
1258  return mSource.fields();
1259 }
1260 
1262 {
1263  return mWkbType;
1264 }
1265 
1267 {
1268  return mSelectedFeatureIds.count();
1269 }
1270 
1272 {
1273  return mName;
1274 }
1275 
1277 {
1278  if ( mLayer )
1279  return mLayer->createExpressionContextScope();
1280  else
1281  return nullptr;
1282 }
1283 
1285 {
1286  if ( mLayer )
1287  return mLayer->hasSpatialIndex();
1288  else
1290 }
1291 
1292 //
1293 // QgsVectorLayerSelectedFeatureIterator
1294 //
1295 
1297 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1298  : QgsAbstractFeatureIterator( request )
1299  , mSelectedFeatureIds( selectedFeatureIds )
1300 {
1301  QgsFeatureRequest sourceRequest = request;
1302  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1303  {
1304  // we can't pass the request limit to the provider here - otherwise the provider will
1305  // limit the number of returned features and may only return a bunch of matching features
1306  // which AREN'T in the selected feature set
1307  sourceRequest.setLimit( -1 );
1308  }
1309  mIterator = source.getFeatures( sourceRequest );
1310 }
1311 
1312 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1313 {
1314  return mIterator.rewind();
1315 }
1316 
1317 bool QgsVectorLayerSelectedFeatureIterator::close()
1318 {
1319  return mIterator.close();
1320 }
1321 
1322 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1323 {
1324  while ( mIterator.nextFeature( f ) )
1325  {
1326  if ( mSelectedFeatureIds.contains( f.id() ) )
1327  return true;
1328  }
1329  return false;
1330 }
1331 
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:344
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:578
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:52
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
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:164
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:59
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:53
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
64 bit feature ids negative numbers are used for uncommitted/newly added features ...
Definition: qgsfeatureid.h:28
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.
FilterType filterType() const
Returns the filter type which is currently set on this request.
Container of fields for a vector layer.
Definition: qgsfields.h:44
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:123
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:129
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:213
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:51
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:199
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:50
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:43
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
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:69
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.
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:371
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:114
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:101
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:190
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:569
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:469
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:139
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:447
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...
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:371
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source, if it can be determined.
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
SpatialIndexPresence
Enumeration of spatial index presence states.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
QgsGeometry geometry
Definition: qgsfeature.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
Spatial index presence cannot be determined, index may or may not exist.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
QList< int > QgsAttributeList
Definition: qgsfield.h:26
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:264
Field is calculated from an expression.
Definition: qgsfields.h:54
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...
const QgsField & field
Definition: qgsfield.h:471
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:90
Represents a list of OrderByClauses, with the most important first and the least important last...
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.