QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
50 mExpressionFieldBuffer.reset( new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer ) );
51 mCrs = layer->crs();
52
53 mHasEditBuffer = layer->editBuffer();
54 if ( mHasEditBuffer )
55 {
56#if 0
57 // TODO[MD]: after merge
58 if ( request.filterType() == QgsFeatureRequest::FilterFid )
59 {
60
61 // only copy relevant parts
62 if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
63 mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
64
65 if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
66 mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
67
68 if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
69 mDeletedFeatureIds.insert( request.filterFid() );
70
71 if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
72 mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
73
74 if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
75 mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
76 }
77 else
78 {
79#endif
80 // If we are inside a transaction the iterator "sees" the current status
81 if ( provider && ! provider->transaction() )
82 {
87 mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
89 }
90#if 0
91 }
92#endif
93 }
94
95 const std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
96 mLayerScope = *layerScope;
97}
98
100
102{
103 // return feature iterator that does not own this source
104 return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
105}
106
108{
109 return mFields;
110}
111
113{
114 return mCrs;
115}
116
118{
119 return mId;
120}
121
122
125 , mFetchedFid( false )
126{
128 {
130 }
131
132 // prepare spatial filter geometries for optimal speed
133 // since the mDistanceWithin* constraint member variables are all in the DESTINATION CRS,
134 // we set all these upfront before any transformation to the source CRS is done.
135
136 switch ( mRequest.spatialFilterType() )
137 {
140 break;
141
144 {
145 // Note that regardless of whether or not we'll ultimately be able to handoff this check to the underlying provider,
146 // we still need these reference geometry constraints in the vector layer iterator as we need them to check against
147 // the features from the vector layer's edit buffer! (In other words, we cannot completely hand off responsibility for
148 // these checks to the provider and ignore them locally)
151 mDistanceWithinEngine->prepareGeometry();
153 }
154 break;
155 }
156
157 bool canDelegateLimitToProvider = true;
158 try
159 {
161 {
163 break;
164
166 // we have to disable any limit on the provider's request -- since that request may be returning features which are outside the
167 // distance tolerance, we'll have to fetch them all and then handle the limit check manually only after testing for the distance within constraint
168 canDelegateLimitToProvider = false;
169 break;
170 }
171
172 // mFilterRect is in the source CRS, so we set that now (after request transformation has been done)
174 }
175 catch ( QgsCsException & )
176 {
177 // can't reproject request filters
178 close();
179 return;
180 }
181
182 // check whether the order by clause(s) can be delegated to the provider
183 mDelegatedOrderByToProvider = !mSource->mHasEditBuffer;
184 if ( !mRequest.orderBy().isEmpty() )
185 {
186 QSet<int> attributeIndexes;
187 const auto usedAttributeIndices = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
188 for ( const int attrIndex : usedAttributeIndices )
189 {
191 mDelegatedOrderByToProvider = false;
192
193 attributeIndexes << attrIndex;
194 }
195
196 if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mDelegatedOrderByToProvider )
197 {
198 attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
199 mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
200 }
201 }
202
204 {
207
209 {
210 // ensure that all fields required for filter expressions are prepared
212 attributeIndexes += qgis::listToSet( mRequest.subsetOfAttributes() );
213 mRequest.setSubsetOfAttributes( qgis::setToList( attributeIndexes ) );
214 }
215 }
216
218
220
221 // by default provider's request is the same
223 // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
224 // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
225 // values
227 {
229 }
230
231 if ( !mDelegatedOrderByToProvider )
232 {
234 }
235
236 if ( !canDelegateLimitToProvider )
237 {
239 }
240
242 {
243 // prepare list of attributes to match provider fields
244 QSet<int> providerSubset;
246 const int nPendingFields = mSource->mFields.count();
247 for ( const int attrIndex : subset )
248 {
249 if ( attrIndex < 0 || attrIndex >= nPendingFields )
250 continue;
252 providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
253 }
254
255 // This is done in order to be prepared to do fallback order bys
256 // and be sure we have the required columns.
257 // TODO:
258 // It would be nicer to first check if we can compile the order by
259 // and only modify the subset if we cannot.
260 if ( !mProviderRequest.orderBy().isEmpty() )
261 {
262 const auto usedAttributeIndices = mProviderRequest.orderBy().usedAttributeIndices( mSource->mFields );
263 for ( const int attrIndex : usedAttributeIndices )
264 {
265 providerSubset << attrIndex;
266 }
267 }
268
269 mProviderRequest.setSubsetOfAttributes( qgis::setToList( providerSubset ) );
270 }
271
273 {
274 const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
275 const auto constReferencedColumns = mProviderRequest.filterExpression()->referencedColumns();
276 for ( const QString &field : constReferencedColumns )
277 {
278 const int idx = source->mFields.lookupField( field );
279
280 // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
281 // In this case we disable the expression filter.
282 if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
283 {
285 // can't limit at provider side
287 if ( needsGeom )
288 {
289 // have to get geometry from provider in order to evaluate expression on client
291 }
292 break;
293 }
294 }
295 }
296
297 if ( mSource->mHasEditBuffer )
298 {
300 QgsFeatureIds changedIds;
301 QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
302 for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
303 {
304 changedIds << attIt.key();
305 }
307
308 if ( mChangedFeaturesRequest.limit() > 0 )
309 {
310 int providerLimit = mProviderRequest.limit();
311
312 // features may be deleted in buffer, so increase limit sent to provider
313 providerLimit += mSource->mDeletedFeatureIds.size();
314
316 {
317 // attribute changes may mean some features no longer match expression, so increase limit sent to provider
318 providerLimit += mSource->mChangedAttributeValues.size();
319 }
320
322 {
323 // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
324 providerLimit += mSource->mChangedGeometries.size();
325 }
326
327 mProviderRequest.setLimit( providerLimit );
328 mChangedFeaturesRequest.setLimit( providerLimit );
329 }
330 }
331
332 if ( request.filterType() == QgsFeatureRequest::FilterFid )
333 {
334 mFetchedFid = false;
335 }
336 else // no filter or filter by rect
337 {
339 {
340 if ( mSource->mHasEditBuffer )
341 {
343 }
344 else
345 {
347 }
348 }
349
351 }
352}
353
354
356{
357 qDeleteAll( mExpressionFieldInfo );
358
359 close();
360}
361
363
369class QgsThreadStackOverflowGuard
370{
371 public:
372
373 QgsThreadStackOverflowGuard( QThreadStorage<QStack<QString>> &storage, const QString &stackFrameInformation, int maxDepth )
374 : mStorage( storage )
375 , mMaxDepth( maxDepth )
376 {
377 if ( !storage.hasLocalData() )
378 {
379 storage.setLocalData( QStack<QString>() );
380 }
381
382 storage.localData().push( stackFrameInformation );
383 }
384
385 ~QgsThreadStackOverflowGuard()
386 {
387 mStorage.localData().pop();
388 }
389
390 bool hasStackOverflow() const
391 {
392 if ( mStorage.localData().size() > mMaxDepth )
393 return true;
394 else
395 return false;
396 }
397
398 QString topFrames() const
399 {
400 QStringList dumpStack;
401 const QStack<QString> &stack = mStorage.localData();
402
403 const int dumpSize = std::min( static_cast<int>( stack.size() ), 10 );
404 for ( int i = 0; i < dumpSize; ++i )
405 {
406 dumpStack += stack.at( i );
407 }
408
409 return dumpStack.join( '\n' );
410 }
411
412 int depth() const
413 {
414 return mStorage.localData().size();
415 }
416
417 private:
418 QThreadStorage<QStack<QString>> &mStorage;
419 int mMaxDepth;
420};
421
423
425{
426 f.setValid( false );
427
428 if ( mClosed )
429 return false;
430
431 static QThreadStorage<QStack<QString>> sStack;
432
433 const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
434
435 if ( guard.hasStackOverflow() )
436 {
437 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 );
438 return false;
439 }
440
442 {
443 if ( mFetchedFid )
444 return false;
445 const bool res = nextFeatureFid( f );
446 if ( res && postProcessFeature( f ) )
447 {
448 mFetchedFid = true;
449 return res;
450 }
451 else
452 {
453 return false;
454 }
455 }
456
457 if ( !mFilterRect.isNull() )
458 {
460 return true;
461
462 // no more changed geometries
463 }
464
466 {
468 return true;
469
471 return true;
472
473 // no more changed features
474 }
475
476 while ( fetchNextAddedFeature( f ) )
477 {
478 return true;
479 }
480 // no more added features
481
483 {
486 {
488 mProviderIterator.setInterruptionChecker( mInterruptionChecker );
489 }
490 }
491
492 while ( mProviderIterator.nextFeature( f ) )
493 {
494 if ( mFetchConsidered.contains( f.id() ) )
495 continue;
496
497 // TODO[MD]: just one resize of attributes
499
500 // update attributes
501 if ( mSource->mHasEditBuffer )
503
506
508 {
509 //filtering by expression, and couldn't do it on the provider side
512 {
513 //feature did not match filter
514 continue;
515 }
516 }
517
518 // update geometry
519 // TODO[MK]: FilterRect check after updating the geometry
522
523 if ( !postProcessFeature( f ) )
524 continue;
525
526 return true;
527 }
528 // no more provider features
529
530 close();
531 return false;
532}
533
534
535
537{
538 if ( mClosed )
539 return false;
540
542 {
543 mFetchedFid = false;
544 }
545 else
546 {
549 }
550
551 return true;
552}
553
555{
556 if ( mClosed )
557 return false;
558
560
562
563 mClosed = true;
564 return true;
565}
566
568{
569 mProviderIterator.setInterruptionChecker( interruptionChecker );
570 mInterruptionChecker = interruptionChecker;
571}
572
574{
575 return mProviderIterator.isValid();
576}
577
579{
580 while ( mFetchAddedFeaturesIt != mSource->mAddedFeatures.constBegin() )
581 {
583 const QgsFeatureId fid = mFetchAddedFeaturesIt->id();
584
585 if ( mFetchConsidered.contains( fid ) )
586 // must have changed geometry outside rectangle
587 continue;
588
590
591 // can't test for feature acceptance until after calling useAddedFeature
592 // since acceptFeature may rely on virtual fields
593 if ( !mRequest.acceptFeature( f ) )
594 // skip features which are not accepted by the filter
595 continue;
596
597 if ( !postProcessFeature( f ) )
598 continue;
599
600 return true;
601 }
602
604 return false; // no more added features
605}
606
607
609{
610 // since QgsFeature is implicitly shared, it's more efficient to just copy the
611 // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
612 // This helps potentially avoid an unnecessary detach of the feature
613 f = src;
614 f.setValid( true );
616
619}
620
621
622
624{
625 // check if changed geometries are in rectangle
627 {
628 const QgsFeatureId fid = mFetchChangedGeomIt.key();
629
630 if ( mFetchConsidered.contains( fid ) )
631 // skip deleted features
632 continue;
633
634 mFetchConsidered << fid;
635
636 if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
637 // skip changed geometries not in rectangle and don't check again
638 continue;
639
641
643 {
646 {
647 continue;
648 }
649 }
650
651 if ( postProcessFeature( f ) )
652 {
653 // return complete feature
655 return true;
656 }
657 }
658
659 return false; // no more changed geometries
660}
661
663{
665 {
666 if ( mFetchConsidered.contains( f.id() ) )
667 continue;
668
669 mFetchConsidered << f.id();
670
672
673 // also update geometry if needed
674 const auto changedGeometryIt = mSource->mChangedGeometries.constFind( f.id() );
675 if ( changedGeometryIt != mSource->mChangedGeometries.constEnd() )
676 {
677 if ( !mFilterRect.isNull() && !changedGeometryIt->intersects( mFilterRect ) )
678 // skip changed geometries not in rectangle and don't check again
679 continue;
680
681 f.setGeometry( *changedGeometryIt );
682 }
683
686
688 if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
689 {
690 return true;
691 }
692 }
693
694 return false;
695}
696
697
699{
700 f.setId( fid );
701 f.setValid( true );
703
706 {
707 f.setGeometry( geom );
708 }
709
710 const bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
711 if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
712 {
713 // retrieve attributes from provider
714 QgsFeature tmp;
715 //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
716 QgsFeatureRequest request;
718 if ( subsetAttrs )
719 {
721 }
722 QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( request );
723 if ( fi.nextFeature( tmp ) )
724 {
727 f.setAttributes( tmp.attributes() );
728 }
729 }
730
732}
733
734
735
737{
739
742}
743
745{
746 if ( !mSource->mFields.exists( fieldIdx ) )
747 return;
748
749 if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
750 return;
751
752 int sourceLayerIndex;
753 const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
754 Q_ASSERT( joinInfo );
755
756 QgsVectorLayer *joinLayer = joinInfo->joinLayer();
757 if ( !joinLayer )
758 return; // invalid join (unresolved reference to layer)
759
760 if ( !mFetchJoinInfo.contains( joinInfo ) )
761 {
762 FetchJoinInfo info;
763 info.joinInfo = joinInfo;
764 info.joinSource = std::make_shared< QgsVectorLayerFeatureSource >( joinLayer );
765 info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
767 info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
768 info.joinLayerFields = joinLayer->fields();
769
770 // for joined fields, we always need to request the targetField from the provider too
771 if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
772 mFieldsToPrepare << info.targetField;
773
776
777 mFetchJoinInfo.insert( joinInfo, info );
778 }
779
780 // store field source index - we'll need it when fetching from provider
781 mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
782 mFetchJoinInfo[ joinInfo ].attributesSourceToDestLayerMap[sourceLayerIndex] = fieldIdx;
783}
784
785
787{
788 static QThreadStorage<QStack<QString>> sStack;
789
790 const QgsThreadStackOverflowGuard guard( sStack, mSource->id(), 4 );
791
792 if ( guard.hasStackOverflow() )
793 {
794 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 );
795 return;
796 }
797
798 const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
799
800 const int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
801 std::unique_ptr<QgsExpression> exp = std::make_unique<QgsExpression>( exps[oi].cachedExpression );
802
805 da.setEllipsoid( QgsProject::instance()->ellipsoid() );
806 exp->setGeomCalculator( &da );
807 exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
808 exp->setAreaUnits( QgsProject::instance()->areaUnits() );
809
810 if ( !mExpressionContext )
811 createExpressionContext();
812 exp->prepare( mExpressionContext.get() );
813 const QSet<int> referencedColumns = exp->referencedAttributeIndexes( mSource->fields() );
814
815 QSet<int> requestedAttributes = qgis::listToSet( mRequest.subsetOfAttributes() );
816
817 for ( const int dependentFieldIdx : referencedColumns )
818 {
820 {
821 requestedAttributes += dependentFieldIdx;
822 }
823 // also need to fetch this dependent field
824 if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
825 mFieldsToPrepare << dependentFieldIdx;
826 }
827
829 {
830 mRequest.setSubsetOfAttributes( qgis::setToList( requestedAttributes ) );
831 }
832
833 if ( exp->needsGeometry() )
834 {
836 }
837
838 mExpressionFieldInfo.insert( fieldIdx, exp.release() );
839}
840
842{
843 mPreparedFields.clear();
844 mFieldsToPrepare.clear();
845 mFetchJoinInfo.clear();
846 mOrderedJoinInfoList.clear();
847
848 mExpressionContext.reset();
849
850 mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
853
854 while ( !mFieldsToPrepare.isEmpty() )
855 {
856 const int fieldIdx = mFieldsToPrepare.takeFirst();
857 if ( mPreparedFields.contains( fieldIdx ) )
858 continue;
859
860 mPreparedFields << fieldIdx;
861 prepareField( fieldIdx );
862 }
863
864 //sort joins by dependency
865 if ( !mFetchJoinInfo.empty() )
866 {
867 createOrderedJoinList();
868 }
869}
870
871void QgsVectorLayerFeatureIterator::createOrderedJoinList()
872{
873 mOrderedJoinInfoList = mFetchJoinInfo.values();
874 if ( mOrderedJoinInfoList.size() < 2 )
875 {
876 return;
877 }
878
879 QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
880
881 //add all provider fields without joins as resolved fields
882 QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
883 for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
884 {
885 if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
886 {
887 resolvedFields.insert( *prepFieldIt );
888 }
889 }
890
891 //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
892
893 //some join combinations might not have a resolution at all
894 const int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
895 int currentIteration = 0;
896
897 for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
898 {
899 if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
900 {
901 mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
902 mOrderedJoinInfoList.removeAt( i );
903 --i;
904 }
905 else
906 {
907 const int offset = mOrderedJoinInfoList.at( i ).indexOffset;
908 const int joinField = mOrderedJoinInfoList.at( i ).joinField;
909
910 const QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
911 for ( int n = 0; n < attributes.size(); n++ )
912 {
913 if ( n != joinField )
914 {
915 resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
916 }
917 }
918 }
919
920 ++currentIteration;
921 if ( currentIteration >= maxIterations )
922 {
923 break;
924 }
925 }
926}
927
928bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
929{
930 bool result = checkGeometryValidity( feature );
931 if ( result )
933
934 if ( result && mDistanceWithinEngine && feature.hasGeometry() )
935 {
936 result = mDistanceWithinEngine->distanceWithin( feature.geometry().constGet(), mDistanceWithin );
937 }
938
939 return result;
940}
941
942bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
943{
944 if ( !feature.hasGeometry() )
945 return true;
946
947 switch ( mRequest.invalidGeometryCheck() )
948 {
950 return true;
951
953 {
954 if ( !feature.geometry().isGeosValid() )
955 {
956 QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
958 {
960 }
961 return false;
962 }
963 break;
964 }
965
967 if ( !feature.geometry().isGeosValid() )
968 {
969 QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::MessageLevel::Critical );
970 close();
972 {
974 }
975 return false;
976 }
977 break;
978 }
979
980 return true;
981}
982
984{
985 switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
986 {
988 prepareExpression( fieldIdx );
989 break;
990
992 if ( mSource->mJoinBuffer->containsJoins() )
993 {
994 prepareJoin( fieldIdx );
995 }
996 break;
997
1001 break;
1002 }
1003}
1004
1006{
1007 QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
1008 for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
1009 {
1010 const QVariant targetFieldValue = f.attribute( joinIt->targetField );
1011 if ( !targetFieldValue.isValid() )
1012 continue;
1013
1014 const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
1015 if ( memoryCache.isEmpty() )
1016 joinIt->addJoinedAttributesDirect( f, targetFieldValue );
1017 else
1018 joinIt->addJoinedAttributesCached( f, targetFieldValue );
1019 }
1020}
1021
1023{
1024 // make sure we have space for newly added attributes
1025 QgsAttributes attr = f.attributes();
1026 attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
1027 f.setAttributes( attr );
1028
1029 // possible TODO - handle combinations of expression -> join -> expression -> join?
1030 // but for now, write that off as too complex and an unlikely rare, unsupported use case
1031
1032 QList< int > fetchedVirtualAttributes;
1033 //first, check through joins for any virtual fields we need
1034 QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
1035 for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
1036 {
1037 if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
1038 {
1039 // have to calculate expression field before we can handle this join
1040 addExpressionAttribute( f, joinIt->targetField );
1041 fetchedVirtualAttributes << joinIt->targetField;
1042 }
1043 }
1044
1045 if ( !mFetchJoinInfo.isEmpty() )
1047
1048 // add remaining expression fields
1049 if ( !mExpressionFieldInfo.isEmpty() )
1050 {
1051 QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
1052 for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
1053 {
1054 if ( fetchedVirtualAttributes.contains( it.key() ) )
1055 continue;
1056
1057 addExpressionAttribute( f, it.key() );
1058 }
1059 }
1060}
1061
1063{
1064 QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
1065 if ( exp )
1066 {
1067 if ( !mExpressionContext )
1068 createExpressionContext();
1069
1070 mExpressionContext->setFeature( f );
1071 QVariant val = exp->evaluate( mExpressionContext.get() );
1072 ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
1073 f.setAttribute( attrIndex, val );
1074 }
1075 else
1076 {
1077 f.setAttribute( attrIndex, QVariant() );
1078 }
1079}
1080
1082{
1083 Q_UNUSED( simplifyMethod )
1084 return false;
1085}
1086
1087bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
1088{
1089 Q_UNUSED( methodType )
1090 return false;
1091}
1092
1093
1095{
1096 const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
1097 const QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
1098 if ( it == memoryCache.constEnd() )
1099 return; // joined value not found -> leaving the attributes empty (null)
1100
1101 int index = indexOffset;
1102
1103 const QgsAttributes &featureAttributes = it.value();
1104 for ( int i = 0; i < featureAttributes.count(); ++i )
1105 {
1106 f.setAttribute( index++, featureAttributes.at( i ) );
1107 }
1108}
1109
1110
1111
1113{
1114#if 0 // this is not thread safe -- we cannot access the layer here as this will be called from non-main threads.
1115 // Shortcut
1116 if ( joinLayer && ! joinLayer->hasFeatures() )
1117 {
1118 return;
1119 }
1120#endif
1121
1122 // no memory cache, query the joined values by setting substring
1123 QString subsetString;
1124
1125 const QString joinFieldName = joinInfo->joinFieldName();
1126
1127 subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
1128
1129 if ( QgsVariantUtils::isNull( joinValue ) )
1130 {
1131 subsetString += QLatin1String( " IS NULL" );
1132 }
1133 else
1134 {
1135 QString v = joinValue.toString();
1136 switch ( joinValue.type() )
1137 {
1138 case QVariant::Int:
1139 case QVariant::LongLong:
1140 case QVariant::Double:
1141 break;
1142
1143 default:
1144 case QVariant::String:
1145 v.replace( '\'', QLatin1String( "''" ) );
1146 v.prepend( '\'' ).append( '\'' );
1147 break;
1148 }
1149 subsetString += '=' + v;
1150 }
1151
1152 QList<int> joinedAttributeIndices;
1153
1154 // maybe user requested just a subset of layer's attributes
1155 // so we do not have to cache everything
1156 if ( joinInfo->hasSubset() )
1157 {
1158 const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
1159 const QVector<int> subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayerFields, subsetNames );
1160 joinedAttributeIndices = qgis::setToList( qgis::listToSet( attributes ).intersect( qgis::listToSet( subsetIndices.toList() ) ) );
1161 }
1162 else
1163 {
1164 joinedAttributeIndices = attributes;
1165 }
1166
1167 // we don't need the join field, it is already present in the other table
1168 joinedAttributeIndices.removeAll( joinField );
1169
1170 // select (no geometry)
1171 QgsFeatureRequest request;
1173 request.setSubsetOfAttributes( joinedAttributeIndices );
1174 request.setFilterExpression( subsetString );
1175 request.setLimit( 1 );
1176 QgsFeatureIterator fi = joinSource->getFeatures( request );
1177
1178 // get first feature
1179 const QList<int> sourceAttrIndexes = attributesSourceToDestLayerMap.keys();
1180 QgsFeature fet;
1181 if ( fi.nextFeature( fet ) )
1182 {
1183 const QgsAttributes attr = fet.attributes();
1184
1185 for ( const int sourceAttrIndex : sourceAttrIndexes )
1186 {
1187 if ( sourceAttrIndex == joinField )
1188 continue;
1189
1190 const int destAttrIndex = attributesSourceToDestLayerMap.value( sourceAttrIndex );
1191
1192 f.setAttribute( destAttrIndex, attr.at( sourceAttrIndex ) );
1193 }
1194 }
1195 else
1196 {
1197 // no suitable join feature found, keeping empty (null) attributes
1198 }
1199}
1200
1201
1202
1203
1205{
1206 const QgsFeatureId featureId = mRequest.filterFid();
1207
1208 // deleted already?
1209 if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1210 return false;
1211
1212 // has changed geometry?
1213 if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1214 {
1215 useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1216 return true;
1217 }
1218
1219 // added features
1220 for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1221 {
1222 if ( iter->id() == featureId )
1223 {
1224 useAddedFeature( *iter, f );
1225 return true;
1226 }
1227 }
1228
1229 // regular features
1231 if ( fi.nextFeature( f ) )
1232 {
1234
1235 if ( mSource->mHasEditBuffer )
1237
1240
1241 return true;
1242 }
1243
1244 return false;
1245}
1246
1248{
1249 QgsAttributes attrs = f.attributes();
1250
1251 // remove all attributes that will disappear - from higher indices to lower
1252 for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1253 {
1254 attrs.remove( mSource->mDeletedAttributeIds[idx] );
1255 }
1256
1257 // adjust size to accommodate added attributes
1258 attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1259
1260 // update changed attributes
1261 if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1262 {
1264 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1265 attrs[it.key()] = it.value();
1266 }
1267 f.setAttributes( attrs );
1268}
1269
1271{
1272 if ( mSource->mChangedGeometries.contains( f.id() ) )
1274}
1275
1276void QgsVectorLayerFeatureIterator::createExpressionContext()
1277{
1278 mExpressionContext = std::make_unique< QgsExpressionContext >();
1279 mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
1280 mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1281 mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
1282 mExpressionContext->setFeedback( mRequest.feedback() );
1283}
1284
1285bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1286{
1287 Q_UNUSED( orderBys )
1288 return mDelegatedOrderByToProvider;
1289}
1290
1291
1292//
1293// QgsVectorLayerSelectedFeatureSource
1294//
1295
1297 : mSource( layer )
1298 , mSelectedFeatureIds( layer->selectedFeatureIds() )
1299 , mWkbType( layer->wkbType() )
1300 , mName( layer->name() )
1301 , mLayer( layer )
1302{}
1303
1305{
1306 QgsFeatureRequest req( request );
1307
1308 // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1309 // we still tweak the feature request to only request selected feature ids wherever we can -- this
1310 // allows providers to optimise the request and avoid requesting features we don't need
1311 // note that we can't do this for some request types - e.g. expression based requests, so
1312 // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1313 // do ALL the filtering
1314 if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1315 {
1316 req.setFilterFids( mSelectedFeatureIds );
1317 }
1318 else if ( !req.filterFids().isEmpty() )
1319 {
1320 QgsFeatureIds reqIds = mSelectedFeatureIds;
1321 reqIds.intersect( req.filterFids() );
1322 req.setFilterFids( reqIds );
1323 }
1324
1325 return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1326}
1327
1329{
1330 return mSource.crs();
1331}
1332
1334{
1335 return mSource.fields();
1336}
1337
1339{
1340 return mWkbType;
1341}
1342
1344{
1345 return mSelectedFeatureIds.count();
1346}
1347
1349{
1350 return mName;
1351}
1352
1354{
1355 if ( mLayer )
1356 return mLayer->createExpressionContextScope();
1357 else
1358 return nullptr;
1359}
1360
1362{
1363 if ( mLayer )
1364 return mLayer->hasSpatialIndex();
1365 else
1367}
1368
1369//
1370// QgsVectorLayerSelectedFeatureIterator
1371//
1372
1374QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1375 : QgsAbstractFeatureIterator( request )
1376 , mSelectedFeatureIds( selectedFeatureIds )
1377{
1378 QgsFeatureRequest sourceRequest = request;
1379 if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1380 {
1381 // we can't pass the request limit to the provider here - otherwise the provider will
1382 // limit the number of returned features and may only return a bunch of matching features
1383 // which AREN'T in the selected feature set
1384 sourceRequest.setLimit( -1 );
1385 }
1386 mIterator = source.getFeatures( sourceRequest );
1387}
1388
1389bool QgsVectorLayerSelectedFeatureIterator::rewind()
1390{
1391 return mIterator.rewind();
1392}
1393
1394bool QgsVectorLayerSelectedFeatureIterator::close()
1395{
1396 return mIterator.close();
1397}
1398
1399bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1400{
1401 while ( mIterator.nextFeature( f ) )
1402 {
1403 if ( mSelectedFeatureIds.contains( f.id() ) )
1404 return true;
1405 }
1406 return false;
1407}
1408
@ DistanceWithin
Filter by distance to reference geometry.
@ BoundingBox
Filter using a bounding box.
@ NoFilter
No spatial filtering of features.
Helper template that cares of two things: 1.
void iteratorClosed()
to be called by from subclass in close()
Internal feature iterator to be implemented within data providers.
@ 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:60
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:412
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:376
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:349
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:110
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
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.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
QHash< QString, QgsAttributes > cachedAttributes
Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
long long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown.
SpatialIndexPresence hasSpatialIndex() const override
Returns an enum value representing the presence of a valid spatial index on the source,...
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
QgsVectorLayerSelectedFeatureSource(QgsVectorLayer *layer)
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified layer.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QString sourceName() const override
Returns a friendly display name for the source.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:42
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:917
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:908
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
const QgsField & field
Definition: qgsfield.h:463
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
const QgsAttributeList & attributeIndexes
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
void addJoinedAttributesDirect(QgsFeature &f, const QVariant &joinValue) const
std::shared_ptr< QgsVectorLayerFeatureSource > joinSource
Feature source for join.
int targetField
Index of field (of this layer) that drives the join.
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
int indexOffset
At what position the joined fields start.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const