QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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
19#include "qgssimplifymethod.h"
22#include "qgsvectorlayer.h"
25#include "qgsdistancearea.h"
26#include "qgsproject.h"
27#include "qgsmessagelog.h"
28#include "qgsexception.h"
30#include "qgsgeometryengine.h"
31
32#include <QThreadStorage>
33#include <QStack>
34
36{
37 const QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
38 const QgsVectorDataProvider *provider = layer->dataProvider();
39 if ( provider )
40 mProviderFeatureSource.reset( provider->featureSource() );
41 mFields = layer->fields();
42 mId = layer->id();
43
44 // update layer's join caches if necessary
45 if ( layer->mJoinBuffer->containsJoins() )
46 layer->mJoinBuffer->createJoinCaches();
47
48 mJoinBuffer.reset( layer->mJoinBuffer->clone() );
49 for ( const QgsVectorLayerJoinInfo &joinInfo : mJoinBuffer->vectorJoins() )
50 {
51 if ( QgsVectorLayer *joinLayer = joinInfo.joinLayer() )
52 {
53 JoinLayerSource source;
54 source.joinSource = std::make_shared< QgsVectorLayerFeatureSource >( joinLayer );
55 source.joinLayerFields = joinLayer->fields();
56 mJoinSources.insert( joinLayer->id(), source );
57 }
58 }
59
60 mExpressionFieldBuffer.reset( new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer ) );
61 mCrs = layer->crs();
62
63 mHasEditBuffer = layer->editBuffer();
64 if ( mHasEditBuffer )
65 {
66#if 0
67 // TODO[MD]: after merge
68 if ( request.filterType() == QgsFeatureRequest::FilterFid )
69 {
70
71 // only copy relevant parts
72 if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
73 mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
74
75 if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
76 mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
77
78 if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
79 mDeletedFeatureIds.insert( request.filterFid() );
80
81 if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
82 mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
83
84 if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
85 mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
86 }
87 else
88 {
89#endif
90 // If we are inside a transaction the iterator "sees" the current status
91 if ( provider && ! provider->transaction() )
92 {
97 mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
99 }
100#if 0
101 }
102#endif
103 }
104
105 const std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
106 mLayerScope = *layerScope;
107}
108
110
112{
113 // return feature iterator that does not own this source
114 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
115}
116
118{
119 return mFields;
120}
121
123{
124 return mCrs;
125}
126
128{
129 return mId;
130}
131
132
135 , mFetchedFid( false )
136{
138 {
140 }
141
142 // prepare spatial filter geometries for optimal speed
143 // since the mDistanceWithin* constraint member variables are all in the DESTINATION CRS,
144 // we set all these upfront before any transformation to the source CRS is done.
145
146 switch ( mRequest.spatialFilterType() )
147 {
150 break;
151
154 {
155 // Note that regardless of whether or not we'll ultimately be able to handoff this check to the underlying provider,
156 // we still need these reference geometry constraints in the vector layer iterator as we need them to check against
157 // the features from the vector layer's edit buffer! (In other words, we cannot completely hand off responsibility for
158 // these checks to the provider and ignore them locally)
161 mDistanceWithinEngine->prepareGeometry();
163 }
164 break;
165 }
166
167 bool canDelegateLimitToProvider = true;
168 try
169 {
171 {
173 break;
174
176 // we have to disable any limit on the provider's request -- since that request may be returning features which are outside the
177 // distance tolerance, we'll have to fetch them all and then handle the limit check manually only after testing for the distance within constraint
178 canDelegateLimitToProvider = false;
179 break;
180 }
181
182 // mFilterRect is in the source CRS, so we set that now (after request transformation has been done)
184 }
185 catch ( QgsCsException & )
186 {
187 // can't reproject request filters
188 close();
189 return;
190 }
191
192 // check whether the order by clause(s) can be delegated to the provider
193 mDelegatedOrderByToProvider = !mSource->mHasEditBuffer;
194 if ( !mRequest.orderBy().isEmpty() )
195 {
196 QSet<int> attributeIndexes;
197 const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
198 for ( const int attrIndex : usedAttributeIndices )
199 {
201 mDelegatedOrderByToProvider = false;
202
203 attributeIndexes << attrIndex;
204 }
205
206 if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mDelegatedOrderByToProvider )
207 {
208 attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
209 mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
210 }
211 }
212
214 {
217
219 {
220 // ensure that all fields required for filter expressions are prepared
222 attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
223 mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
224 }
225 }
226
228
230
231 // by default provider's request is the same
233 // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
234 // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
235 // values
237 {
239 }
240
241 if ( !mDelegatedOrderByToProvider )
242 {
244 }
245
246 if ( !canDelegateLimitToProvider )
247 {
249 }
250
252 {
253 // prepare list of attributes to match provider fields
254 QSet<int> providerSubset;
256 const int nPendingFields = mSource->mFields.count();
257 for ( const int attrIndex : subset )
258 {
259 if ( attrIndex < 0 || attrIndex >= nPendingFields )
260 continue;
262 providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
263 }
264
265 // This is done in order to be prepared to do fallback order bys
266 // and be sure we have the required columns.
267 // TODO:
268 // It would be nicer to first check if we can compile the order by
269 // and only modify the subset if we cannot.
270 if ( !mProviderRequest.orderBy().isEmpty() )
271 {
272 const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
273 for ( const int attrIndex : usedAttributeIndices )
274 {
275 providerSubset << attrIndex;
276 }
277 }
278
279 mProviderRequest.setSubsetOfAttributes( qgis::setToList( providerSubset ) );
280 }
281
283 {
284 const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
285 const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
286 for ( const QString &field : constReferencedColumns )
287 {
288 const int idx = source->mFields.lookupField( field );
289
290 // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
291 // In this case we disable the expression filter.
292 if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
293 {
295 // can't limit at provider side
297 if ( needsGeom )
298 {
299 // have to get geometry from provider in order to evaluate expression on client
301 }
302 break;
303 }
304 }
305 }
306
307 if ( mSource->mHasEditBuffer )
308 {
310 QgsFeatureIds changedIds;
311 QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
312 for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
313 {
314 changedIds << attIt.key();
315 }
317
318 if ( mChangedFeaturesRequest.limit() > 0 )
319 {
320 int providerLimit = mProviderRequest.limit();
321
322 // features may be deleted in buffer, so increase limit sent to provider
323 providerLimit += mSource->mDeletedFeatureIds.size();
324
326 {
327 // attribute changes may mean some features no longer match expression, so increase limit sent to provider
328 providerLimit += mSource->mChangedAttributeValues.size();
329 }
330
332 {
333 // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
334 providerLimit += mSource->mChangedGeometries.size();
335 }
336
337 mProviderRequest.setLimit( providerLimit );
338 mChangedFeaturesRequest.setLimit( providerLimit );
339 }
340 }
341
342 if ( request.filterType() == QgsFeatureRequest::FilterFid )
343 {
344 mFetchedFid = false;
345 }
346 else // no filter or filter by rect
347 {
349 {
350 if ( mSource->mHasEditBuffer )
351 {
353 }
354 else
355 {
357 }
358 }
359
361 }
362}
363
364
366{
367 qDeleteAll( mExpressionFieldInfo );
368
369 close();
370}
371
373
379class QgsThreadStackOverflowGuard
380{
381 public:
382
383 QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
384 : mStorage( storage )
385 , mMaxDepth( maxDepth )
386 {
387 if ( !storage.hasLocalData() )
388 {
389 storage.setLocalData( QStack<QString>() );
390 }
391
392 storage.localData().push( stackFrameInformation );
393 }
394
395 ~QgsThreadStackOverflowGuard()
396 {
397 mStorage.localData().pop();
398 }
399
400 bool hasStackOverflow() const
401 {
402 if ( mStorage.localData().size() > mMaxDepth )
403 return true;
404 else
405 return false;
406 }
407
408 QString topFrames() const
409 {
410 QStringList dumpStack;
411 const QStack<QString> &stack = mStorage.localData();
412
413 const int dumpSize = std::min( static_cast<int>( stack.size() ), 10 );
414 for ( int i = 0; i < dumpSize; ++i )
415 {
416 dumpStack += stack.at( i );
417 }
418
419 return dumpStack.join( '\n' );
420 }
421
422 int depth() const
423 {
424 return mStorage.localData().size();
425 }
426
427 private:
428 QThreadStorage<QStack<QString>> &mStorage;
429 int mMaxDepth;
430};
431
433
435{
436 f.setValid( false );
437
438 if ( mClosed )
439 return false;
440
441 static QThreadStorage<QStack<QString>> sStack;
442
443 const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
444
445 if ( guard.hasStackOverflow() )
446 {
447 QgsMessageLog::logMessage( QObject::tr( "Stack overflow, too many nested feature iterators.\nIterated layers:\n%1\n..." ).arg( guard.topFrames() ), QObject::tr( "General" ), Qgis::MessageLevel::Critical );
448 return false;
449 }
450
452 {
453 if ( mFetchedFid )
454 return false;
455 const bool res = nextFeatureFid( f );
456 if ( res && postProcessFeature( f ) )
457 {
458 mFetchedFid = true;
459 return res;
460 }
461 else
462 {
463 return false;
464 }
465 }
466
467 if ( !mFilterRect.isNull() )
468 {
470 return true;
471
472 // no more changed geometries
473 }
474
476 {
478 return true;
479
481 return true;
482
483 // no more changed features
484 }
485
486 while ( fetchNextAddedFeature( f ) )
487 {
488 return true;
489 }
490 // no more added features
491
493 {
496 {
498 mProviderIterator.setInterruptionChecker( mInterruptionChecker );
499 }
500 }
501
502 while ( mProviderIterator.nextFeature( f ) )
503 {
504 if ( mFetchConsidered.contains( f.id() ) )
505 continue;
506
507 // TODO[MD]: just one resize of attributes
509
510 // update attributes
511 if ( mSource->mHasEditBuffer )
513
516
518 {
519 //filtering by expression, and couldn't do it on the provider side
522 {
523 //feature did not match filter
524 continue;
525 }
526 }
527
528 // update geometry
529 // TODO[MK]: FilterRect check after updating the geometry
532
533 if ( !postProcessFeature( f ) )
534 continue;
535
536 return true;
537 }
538 // no more provider features
539
540 close();
541 return false;
542}
543
544
545
547{
548 if ( mClosed )
549 return false;
550
552 {
553 mFetchedFid = false;
554 }
555 else
556 {
559 }
560
561 return true;
562}
563
565{
566 if ( mClosed )
567 return false;
568
570
572
573 mClosed = true;
574 return true;
575}
576
578{
579 mProviderIterator.setInterruptionChecker( interruptionChecker );
580 mInterruptionChecker = interruptionChecker;
581}
582
584{
585 return mProviderIterator.isValid();
586}
587
589{
590 while ( mFetchAddedFeaturesIt != mSource->mAddedFeatures.constBegin() )
591 {
593 const QgsFeatureId fid = mFetchAddedFeaturesIt->id();
594
595 if ( mFetchConsidered.contains( fid ) )
596 // must have changed geometry outside rectangle
597 continue;
598
600
601 // can't test for feature acceptance until after calling useAddedFeature
602 // since acceptFeature may rely on virtual fields
603 if ( !mRequest.acceptFeature( f ) )
604 // skip features which are not accepted by the filter
605 continue;
606
607 if ( !postProcessFeature( f ) )
608 continue;
609
610 return true;
611 }
612
614 return false; // no more added features
615}
616
617
619{
620 // since QgsFeature is implicitly shared, it's more efficient to just copy the
621 // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
622 // This helps potentially avoid an unnecessary detach of the feature
623 f = src;
624 f.setValid( true );
626
629}
630
631
632
634{
635 // check if changed geometries are in rectangle
637 {
638 const QgsFeatureId fid = mFetchChangedGeomIt.key();
639
640 if ( mFetchConsidered.contains( fid ) )
641 // skip deleted features
642 continue;
643
644 mFetchConsidered << fid;
645
646 if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
647 // skip changed geometries not in rectangle and don't check again
648 continue;
649
651
653 {
656 {
657 continue;
658 }
659 }
660
661 if ( postProcessFeature( f ) )
662 {
663 // return complete feature
665 return true;
666 }
667 }
668
669 return false; // no more changed geometries
670}
671
673{
675 {
676 if ( mFetchConsidered.contains( f.id() ) )
677 continue;
678
679 mFetchConsidered << f.id();
680
682
683 // also update geometry if needed
684 const auto changedGeometryIt = mSource->mChangedGeometries.constFind( f.id() );
685 if ( changedGeometryIt != mSource->mChangedGeometries.constEnd() )
686 {
687 if ( !mFilterRect.isNull() && !changedGeometryIt->intersects( mFilterRect ) )
688 // skip changed geometries not in rectangle and don't check again
689 continue;
690
691 f.setGeometry( *changedGeometryIt );
692 }
693
696
698 if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
699 {
700 return true;
701 }
702 }
703
704 return false;
705}
706
707
709{
710 f.setId( fid );
711 f.setValid( true );
713
716 {
717 f.setGeometry( geom );
718 }
719
720 const bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
721 if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
722 {
723 // retrieve attributes from provider
724 QgsFeature tmp;
725 //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
726 QgsFeatureRequest request;
728 if ( subsetAttrs )
729 {
731 }
732 QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( request );
733 if ( fi.nextFeature( tmp ) )
734 {
737 f.setAttributes( tmp.attributes() );
738 }
739 }
740
742}
743
744
745
747{
749
752}
753
755{
756 if ( !mSource->mFields.exists( fieldIdx ) )
757 return;
758
759 if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
760 return;
761
762 int sourceLayerIndex;
763 const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
764 Q_ASSERT( joinInfo );
765
766 auto joinSourceIt = mSource->mJoinSources.constFind( joinInfo->joinLayerId() );
767 if ( joinSourceIt == mSource->mJoinSources.constEnd() )
768 return; // invalid join (unresolved reference to layer)
769
770 if ( !mFetchJoinInfo.contains( joinInfo ) )
771 {
772 FetchJoinInfo info;
773 info.joinInfo = joinInfo;
774 info.joinSource = joinSourceIt->joinSource;
775 info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
777 info.joinField = joinSourceIt->joinLayerFields.indexFromName( joinInfo->joinFieldName() );
778 info.joinLayerFields = joinSourceIt->joinLayerFields;
779
780 // for joined fields, we always need to request the targetField from the provider too
781 if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
782 mFieldsToPrepare << info.targetField;
783
786
787 mFetchJoinInfo.insert( joinInfo, info );
788 }
789
790 // store field source index - we'll need it when fetching from provider
791 mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
792 mFetchJoinInfo[ joinInfo ].attributesSourceToDestLayerMap[sourceLayerIndex] = fieldIdx;
793}
794
795
797{
798 static QThreadStorage<QStack<QString>> sStack;
799
800 const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
801
802 if ( guard.hasStackOverflow() )
803 {
804 QgsMessageLog::logMessage( QObject::tr( "Stack overflow when preparing field %1 of layer %2.\nLast frames:\n%3\n..." ).arg( mSource->fields().at( fieldIdx ).name(), mSource->id(), guard.topFrames() ), QObject::tr( "General" ), Qgis::MessageLevel::Critical );
805 return;
806 }
807
808 const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
809
810 const int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
811 std::unique_ptr<QgsExpression> exp = std::make_unique<QgsExpression>( exps[oi].cachedExpression );
812
815 da.setEllipsoid( QgsProject::instance()->ellipsoid() );
816 exp->setGeomCalculator( &da );
817 exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
818 exp->setAreaUnits( QgsProject::instance()->areaUnits() );
819
820 if ( !mExpressionContext )
821 createExpressionContext();
822 exp->prepare( mExpressionContext.get() );
823 const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
824
825 QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
826
827 for ( const int dependentFieldIdx : referencedColumns )
828 {
830 {
831 requestedAttributes += dependentFieldIdx;
832 }
833 // also need to fetch this dependent field
834 if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
835 mFieldsToPrepare << dependentFieldIdx;
836 }
837
839 {
840 mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
841 }
842
843 if ( exp->needsGeometry() )
844 {
846 }
847
848 mExpressionFieldInfo.insert( fieldIdx, exp.release() );
849}
850
852{
853 mPreparedFields.clear();
854 mFieldsToPrepare.clear();
855 mFetchJoinInfo.clear();
856 mOrderedJoinInfoList.clear();
857
858 mExpressionContext.reset();
859
860 mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
863
864 while ( !mFieldsToPrepare.isEmpty() )
865 {
866 const int fieldIdx = mFieldsToPrepare.takeFirst();
867 if ( mPreparedFields.contains( fieldIdx ) )
868 continue;
869
870 mPreparedFields << fieldIdx;
871 prepareField( fieldIdx );
872 }
873
874 //sort joins by dependency
875 if ( !mFetchJoinInfo.empty() )
876 {
877 createOrderedJoinList();
878 }
879}
880
881void QgsVectorLayerFeatureIterator::createOrderedJoinList()
882{
883 mOrderedJoinInfoList = mFetchJoinInfo.values();
884 if ( mOrderedJoinInfoList.size() < 2 )
885 {
886 return;
887 }
888
889 QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
890
891 //add all provider fields without joins as resolved fields
892 QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
893 for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
894 {
895 if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
896 {
897 resolvedFields.insert( *prepFieldIt );
898 }
899 }
900
901 //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
902
903 //some join combinations might not have a resolution at all
904 const int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
905 int currentIteration = 0;
906
907 for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
908 {
909 if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
910 {
911 mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
912 mOrderedJoinInfoList.removeAt( i );
913 --i;
914 }
915 else
916 {
917 const int offset = mOrderedJoinInfoList.at( i ).indexOffset;
918 const int joinField = mOrderedJoinInfoList.at( i ).joinField;
919
920 const QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
921 for ( int n = 0; n < attributes.size(); n++ )
922 {
923 if ( n != joinField )
924 {
925 resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
926 }
927 }
928 }
929
930 ++currentIteration;
931 if ( currentIteration >= maxIterations )
932 {
933 break;
934 }
935 }
936}
937
938bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
939{
940 bool result = checkGeometryValidity( feature );
941 if ( result )
943
944 if ( result && mDistanceWithinEngine && feature.hasGeometry() )
945 {
946 result = mDistanceWithinEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin );
947 }
948
949 return result;
950}
951
952bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
953{
954 if ( !feature.hasGeometry() )
955 return true;
956
957 switch ( mRequest.invalidGeometryCheck() )
958 {
960 return true;
961
963 {
964 if ( !feature.geometry().isGeosValid() )
965 {
966 QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
968 {
970 }
971 return false;
972 }
973 break;
974 }
975
977 if ( !feature.geometry().isGeosValid() )
978 {
979 QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
980 close();
982 {
984 }
985 return false;
986 }
987 break;
988 }
989
990 return true;
991}
992
994{
995 switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
996 {
998 prepareExpression( fieldIdx );
999 break;
1000
1002 if ( mSource->mJoinBuffer->containsJoins() )
1003 {
1004 prepareJoin( fieldIdx );
1005 }
1006 break;
1007
1011 break;
1012 }
1013}
1014
1016{
1017 QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
1018 for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
1019 {
1020 const QVariant targetFieldValue = f.attribute( joinIt->targetField );
1021 if ( !targetFieldValue.isValid() )
1022 continue;
1023
1024 const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
1025 if ( memoryCache.isEmpty() )
1026 joinIt->addJoinedAttributesDirect( f, targetFieldValue );
1027 else
1028 joinIt->addJoinedAttributesCached( f, targetFieldValue );
1029 }
1030}
1031
1033{
1034 // make sure we have space for newly added attributes
1035 QgsAttributes attr = f.attributes();
1036 attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
1037 f.setAttributes( attr );
1038
1039 // possible TODO - handle combinations of expression -> join -> expression -> join?
1040 // but for now, write that off as too complex and an unlikely rare, unsupported use case
1041
1042 QList< int > fetchedVirtualAttributes;
1043 //first, check through joins for any virtual fields we need
1044 QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
1045 for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
1046 {
1047 if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
1048 {
1049 // have to calculate expression field before we can handle this join
1050 addExpressionAttribute( f, joinIt->targetField );
1051 fetchedVirtualAttributes << joinIt->targetField;
1052 }
1053 }
1054
1055 if ( !mFetchJoinInfo.isEmpty() )
1057
1058 // add remaining expression fields
1059 if ( !mExpressionFieldInfo.isEmpty() )
1060 {
1061 QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
1062 for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
1063 {
1064 if ( fetchedVirtualAttributes.contains( it.key() ) )
1065 continue;
1066
1067 addExpressionAttribute( f, it.key() );
1068 }
1069 }
1070}
1071
1073{
1074 QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
1075 if ( exp )
1076 {
1077 if ( !mExpressionContext )
1078 createExpressionContext();
1079
1080 mExpressionContext->setFeature( f );
1081 QVariant val = exp->evaluate( mExpressionContext.get() );
1082 ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1083 f.setAttribute( attrIndex, val );
1084 }
1085 else
1086 {
1087 f.setAttribute( attrIndex, QVariant() );
1088 }
1089}
1090
1092{
1093 Q_UNUSED( simplifyMethod )
1094 return false;
1095}
1096
1097bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1098{
1099 Q_UNUSED( methodType )
1100 return false;
1101}
1102
1103
1105{
1106 const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1107 const QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1108 if ( it == memoryCache.constEnd() )
1109 return; // joined value not found -> leaving the attributes empty (null)
1110
1111 int index = indexOffset;
1112
1113 const QgsAttributes &featureAttributes = it.value();
1114 for ( int i = 0; i < featureAttributes.count(); ++i )
1115 {
1116 f.setAttribute( index++, featureAttributes.at( i ) );
1117 }
1118}
1119
1120
1121
1123{
1124#if 0 // this is not thread safe -- we cannot access the layer here as this will be called from non-main threads.
1125 // Shortcut
1126 if ( joinLayer && ! joinLayer->hasFeatures() )
1127 {
1128 return;
1129 }
1130#endif
1131
1132 // no memory cache, query the joined values by setting substring
1133 QString subsetString;
1134
1135 const QString joinFieldName = joinInfo->joinFieldName();
1136
1137 subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1138
1139 if ( QgsVariantUtils::isNull( joinValue ) )
1140 {
1141 subsetString += QLatin1String( " IS NULL" );
1142 }
1143 else
1144 {
1145 QString v = joinValue.toString();
1146 switch ( joinValue.type() )
1147 {
1148 case QVariant::Int:
1149 case QVariant::LongLong:
1150 case QVariant::Double:
1151 break;
1152
1153 default:
1154 case QVariant::String:
1155 v.replace( '\'', QLatin1String( "''" ) );
1156 v.prepend( '\'' ).append( '\'' );
1157 break;
1158 }
1159 subsetString += '=' + v;
1160 }
1161
1162 QList<int> joinedAttributeIndices;
1163
1164 // maybe user requested just a subset of layer's attributes
1165 // so we do not have to cache everything
1166 if ( joinInfo->hasSubset() )
1167 {
1168 const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo, joinLayerFields );
1169 const QVector<int> subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayerFields, subsetNames );
1170 joinedAttributeIndices = qgis::setToList( qgis::listToSet( attributes ).intersect( qgis::listToSet( subsetIndices.toList() ) ) );
1171 }
1172 else
1173 {
1174 joinedAttributeIndices = attributes;
1175 }
1176
1177 // we don't need the join field, it is already present in the other table
1178 joinedAttributeIndices.removeAll( joinField );
1179
1180 // select (no geometry)
1181 QgsFeatureRequest request;
1183 request.setSubsetOfAttributes( joinedAttributeIndices );
1184 request.setFilterExpression( subsetString );
1185 request.setLimit( 1 );
1186 QgsFeatureIterator fi = joinSource->getFeatures( request );
1187
1188 // get first feature
1189 const QList<int> sourceAttrIndexes = attributesSourceToDestLayerMap.keys();
1190 QgsFeature fet;
1191 if ( fi.nextFeature( fet ) )
1192 {
1193 const QgsAttributes attr = fet.attributes();
1194
1195 for ( const int sourceAttrIndex : sourceAttrIndexes )
1196 {
1197 if ( sourceAttrIndex == joinField )
1198 continue;
1199
1200 const int destAttrIndex = attributesSourceToDestLayerMap.value( sourceAttrIndex );
1201
1202 f.setAttribute( destAttrIndex, attr.at( sourceAttrIndex ) );
1203 }
1204 }
1205 else
1206 {
1207 // no suitable join feature found, keeping empty (null) attributes
1208 }
1209}
1210
1211
1212
1213
1215{
1216 const QgsFeatureId featureId = mRequest.filterFid();
1217
1218 // deleted already?
1219 if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1220 return false;
1221
1222 // has changed geometry?
1223 if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1224 {
1225 useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1226 return true;
1227 }
1228
1229 // added features
1230 for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1231 {
1232 if ( iter->id() == featureId )
1233 {
1234 useAddedFeature( *iter, f );
1235 return true;
1236 }
1237 }
1238
1239 // regular features
1241 if ( fi.nextFeature( f ) )
1242 {
1244
1245 if ( mSource->mHasEditBuffer )
1247
1250
1251 return true;
1252 }
1253
1254 return false;
1255}
1256
1258{
1259 QgsAttributes attrs = f.attributes();
1260
1261 // remove all attributes that will disappear - from higher indices to lower
1262 for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1263 {
1264 attrs.remove( mSource->mDeletedAttributeIds[idx] );
1265 }
1266
1267 // adjust size to accommodate added attributes
1268 attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1269
1270 // update changed attributes
1271 if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1272 {
1274 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1275 attrs[it.key()] = it.value();
1276 }
1277 f.setAttributes( attrs );
1278}
1279
1281{
1282 if ( mSource->mChangedGeometries.contains( f.id() ) )
1284}
1285
1286void QgsVectorLayerFeatureIterator::createExpressionContext()
1287{
1288 mExpressionContext = std::make_unique< QgsExpressionContext >();
1289 mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1290 mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1291 mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1292 mExpressionContext->setFeedback( mRequest.feedback() );
1293}
1294
1295bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1296{
1297 Q_UNUSED( orderBys )
1298 return mDelegatedOrderByToProvider;
1299}
1300
1301
1302//
1303// QgsVectorLayerSelectedFeatureSource
1304//
1305
1307 : mSource( layer )
1308 , mSelectedFeatureIds( layer->selectedFeatureIds() )
1309 , mWkbType( layer->wkbType() )
1310 , mName( layer->name() )
1311 , mLayer( layer )
1312{}
1313
1315{
1316 QgsFeatureRequest req( request );
1317
1318 // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1319 // we still tweak the feature request to only request selected feature ids wherever we can -- this
1320 // allows providers to optimise the request and avoid requesting features we don't need
1321 // note that we can't do this for some request types - e.g. expression based requests, so
1322 // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1323 // do ALL the filtering
1324 if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1325 {
1326 req.setFilterFids( mSelectedFeatureIds );
1327 }
1328 else if ( !req.filterFids().isEmpty() )
1329 {
1330 QgsFeatureIds reqIds = mSelectedFeatureIds;
1331 reqIds.intersect( req.filterFids() );
1332 req.setFilterFids( reqIds );
1333 }
1334
1335 return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1336}
1337
1339{
1340 return mSource.crs();
1341}
1342
1344{
1345 return mSource.fields();
1346}
1347
1349{
1350 return mWkbType;
1351}
1352
1354{
1355 return mSelectedFeatureIds.count();
1356}
1357
1359{
1360 return mName;
1361}
1362
1364{
1365 if ( mLayer )
1366 return mLayer->createExpressionContextScope();
1367 else
1368 return nullptr;
1369}
1370
1372{
1373 if ( mLayer )
1374 return mLayer->hasSpatialIndex();
1375 else
1377}
1378
1379//
1380// QgsVectorLayerSelectedFeatureIterator
1381//
1382
1384QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1385 : QgsAbstractFeatureIterator( request )
1386 , mSelectedFeatureIds( selectedFeatureIds )
1387{
1388 QgsFeatureRequest sourceRequest = request;
1389 if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1390 {
1391 // we can't pass the request limit to the provider here - otherwise the provider will
1392 // limit the number of returned features and may only return a bunch of matching features
1393 // which AREN'T in the selected feature set
1394 sourceRequest.setLimit( -1 );
1395 }
1396 mIterator = source.getFeatures( sourceRequest );
1397}
1398
1399bool QgsVectorLayerSelectedFeatureIterator::rewind()
1400{
1401 return mIterator.rewind();
1402}
1403
1404bool QgsVectorLayerSelectedFeatureIterator::close()
1405{
1406 return mIterator.close();
1407}
1408
1409bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1410{
1411 while ( mIterator.nextFeature( f ) )
1412 {
1413 if ( mSelectedFeatureIds.contains( f.id() ) )
1414 return true;
1415 }
1416 return false;
1417}
1418
@ DistanceWithin
Filter by distance to reference geometry.
@ BoundingBox
Filter using a bounding box.
@ NoFilter
No spatial filtering of features.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:155
Helper template that cares of two things: 1.
void iteratorClosed()
to be called by from subclass in close()
Internal feature iterator to be implemented within data providers.
@ Success
Request was successfully updated to the source CRS, or no changes were required.
@ DistanceWithinMustBeCheckedManually
The distance within request cannot be losslessly updated to the source CRS, and callers will need to ...
void geometryToDestinationCrs(QgsFeature &feature, const QgsCoordinateTransform &transform) const
Transforms feature's geometry according to the specified coordinate transform.
QgsFeatureRequest mRequest
A copy of the feature request.
RequestToSourceCrsResult updateRequestToSourceCrs(QgsFeatureRequest &request, const QgsCoordinateTransform &transform) const SIP_THROW(QgsCsException)
Update a QgsFeatureRequest so that spatial filters are transformed to the source's coordinate referen...
bool mClosed
Sets to true, as soon as the iterator is closed.
A vector of attributes.
Definition: qgsattributes.h:59
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Buffers information about expression fields for a vector layer.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
bool isClosed() const
find out whether the iterator is still valid or closed already
void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped.
bool isValid() const
Will return if this iterator is valid.
Represents a list of OrderByClauses, with the most important first and the least important last.
QSet< int > CORE_EXPORT usedAttributeIndices(const QgsFields &fields) const
Returns a set of used, validated attribute indices.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
@ GeometryNoCheck
No invalid geometry checking.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ GeometrySkipInvalid
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
InvalidGeometryCheck invalidGeometryCheck() const
Returns the invalid geometry checking behavior.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly by the iterator to check if it should be ca...
long long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
OrderBy orderBy() const
Returns a list of order by clauses specified for this feature request.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
std::function< void(const QgsFeature &) > invalidGeometryCallback() const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
QgsGeometry referenceGeometry() const
Returns the reference geometry used for spatial filtering of features.
Flags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & disableFilter()
Disables any attribute/ID filtering.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsExpression * filterExpression() const
Returns the filter expression (if set).
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature's geometries, or an invalid QgsCoordi...
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
QgsCoordinateTransformContext transformContext() const
Returns the transform context, for use when a destinationCrs() has been set and reprojection is requi...
std::shared_ptr< QgsGeometryEngine > referenceGeometryEngine() const
Returns the reference geometry engine used for spatial filtering of features.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
double distanceWithin() const
Returns the maximum distance from the referenceGeometry() of fetched features, if spatialFilterType()...
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
FilterType filterType() const
Returns the attribute/ID filter type which is currently set on this request.
@ FilterFid
Filter using feature ID.
@ FilterNone
No filter is applied.
@ FilterExpression
Filter using expression.
const QgsFeatureIds & filterFids() const
Returns the feature IDs that should be fetched.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets the feature ID that should be fetched.
QgsFeatureId filterFid() const
Returns the feature ID that should be fetched.
SpatialIndexPresence
Enumeration of spatial index presence states.
@ SpatialIndexUnknown
Spatial index presence cannot be determined, index may or may not exist.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
Definition: qgsfeature.cpp:265
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:160
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:198
void setId(QgsFeatureId id)
Sets the feature id for this feature.
Definition: qgsfeature.cpp:122
QgsGeometry geometry
Definition: qgsfeature.h:67
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:224
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:233
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:338
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
QString name
Definition: qgsfield.h:61
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:422
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:386
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
@ OriginExpression
Field is calculated from an expression.
Definition: qgsfields.h:54
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:53
@ OriginUnknown
It has not been specified where the field comes from.
Definition: qgsfields.h:50
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfields.h:51
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Definition: qgsfields.cpp:189
bool exists(int i) const
Returns if a field index is valid.
Definition: qgsfields.cpp:153
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
Definition: qgsfields.cpp:197
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:111
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
This is the base class for vector data providers.
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider's data.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed.
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QList< QgsField > addedAttributes() const
Returns a list of added attributes fields which are not committed.
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
void useAddedFeature(const QgsFeature &src, QgsFeature &f)
QMap< const QgsVectorLayerJoinInfo *, QgsVectorLayerFeatureIterator::FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
QgsFeatureMap::ConstIterator mFetchAddedFeaturesIt
void setInterruptionChecker(QgsFeedback *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped.
void addVirtualAttributes(QgsFeature &f)
Adds attributes that don't source from the provider but are added inside QGIS Includes.
bool close() override
end of iterating: free the resources / lock
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
void addExpressionAttribute(QgsFeature &f, int attrIndex)
Adds an expression based attribute to a feature.
QMap< int, QgsExpression * > mExpressionFieldInfo
QgsGeometryMap::ConstIterator mFetchChangedGeomIt
bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod) override
Setup the simplification of geometries to fetch using the specified simplify method.
void useChangedAttributeFeature(QgsFeatureId fid, const QgsGeometry &geom, QgsFeature &f)
std::shared_ptr< QgsGeometryEngine > mDistanceWithinEngine
bool fetchFeature(QgsFeature &feature) override
fetch next feature, return true on success
bool isValid() const override
Returns if this iterator is valid.
bool rewind() override
reset the iterator to the starting position
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
Partial snapshot of vector layer's state (only the members necessary for access to features)
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system for features retrieved from this source.
QgsChangedAttributesMap mChangedAttributeValues
std::unique_ptr< QgsAbstractFeatureSource > mProviderFeatureSource
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Gets an iterator for features matching the specified request.
QgsVectorLayerFeatureSource(const QgsVectorLayer *layer)
Constructor for QgsVectorLayerFeatureSource.
~QgsVectorLayerFeatureSource() override
QString id() const
Returns the layer id of the source layer.
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source.
std::unique_ptr< QgsVectorLayerJoinBuffer > mJoinBuffer
std::unique_ptr< QgsExpressionFieldBuffer > mExpressionFieldBuffer
QMap< QString, JoinLayerSource > mJoinSources
Contains prepared join sources by layer ID.
bool containsJoins() const
Quick way to test if there is any join at all.
QgsVectorLayerJoinBuffer * clone() const
Create a copy of the join buffer.
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Returns a vector of indices for use in join based on field names from the layer.
Defines left outer join from our vector layer to some other vector layer.
QStringList * joinFieldNamesSubset() const
Returns the subset of fields to be used from joined layer.
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QString joinLayerId() const
ID of the joined layer - may be used to resolve reference to the joined layer.
QHash< QString, QgsAttributes > cachedAttributes
Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
long long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown.
Qgis::WkbType wkbType() const override
Returns the geometry type for features returned by this source.
SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source,...
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
QgsVectorLayerSelectedFeatureSource(QgsVectorLayer *layer)
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified layer.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QString sourceName() const override
Returns a friendly display name for the source.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:42
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:915
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:906
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
const QgsField & field
Definition: qgsfield.h:501
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
const QgsAttributeList & attributeIndexes
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
void addJoinedAttributesDirect(QgsFeature &f, const QVariant &joinValue) const
std::shared_ptr< QgsVectorLayerFeatureSource > joinSource
Feature source for join.
int targetField
Index of field (of this layer) that drives the join.
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
int indexOffset
At what position the joined fields start.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const
Contains join layer source information prepared in a thread-safe way, ready for vector layer feature ...
std::shared_ptr< QgsVectorLayerFeatureSource > joinSource
Feature source for join.