QGIS API Documentation  2.99.0-Master (40f86b2)
qgsvectorlayerfeatureiterator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerfeatureiterator.cpp
3  ---------------------
4  begin : Dezember 2012
5  copyright : (C) 2012 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
18 #include "qgsgeometrysimplifier.h"
19 #include "qgssimplifymethod.h"
20 #include "qgsvectordataprovider.h"
22 #include "qgsvectorlayer.h"
24 #include "qgsexpressioncontext.h"
25 #include "qgsdistancearea.h"
26 #include "qgsproject.h"
27 
29  : mCrsId( 0 )
30 {
31  QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
33  mFields = layer->fields();
34 
35  // update layer's join caches if necessary
36  if ( layer->mJoinBuffer->containsJoins() )
37  layer->mJoinBuffer->createJoinCaches();
38 
39  mJoinBuffer = layer->mJoinBuffer->clone();
40 
41  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
42  mCrsId = layer->crs().srsid();
43 
44  mHasEditBuffer = layer->editBuffer();
45  if ( mHasEditBuffer )
46  {
47 #if 0
48  // TODO[MD]: after merge
49  if ( request.filterType() == QgsFeatureRequest::FilterFid )
50  {
51 
52  // only copy relevant parts
53  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
54  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
55 
56  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
57  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
58 
59  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
60  mDeletedFeatureIds.insert( request.filterFid() );
61 
62  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
63  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
64 
65  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
66  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
67  }
68  else
69  {
70 #endif
75  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
77 #if 0
78  }
79 #endif
80  }
81 }
82 
84 {
85  delete mJoinBuffer;
88 }
89 
91 {
92  // return feature iterator that does not own this source
93  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
94 }
95 
96 
99  , mFetchedFid( false )
100  , mInterruptionChecker( nullptr )
101 {
103  {
106 
108  {
109  //ensure that all fields required for filter expressions are prepared
110  QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
111  attributeIndexes += mRequest.subsetOfAttributes().toSet();
112  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
113  }
114  }
115 
116  prepareFields();
117 
118  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
119 
120  // by default provider's request is the same
122 
124  {
125  // prepare list of attributes to match provider fields
126  QSet<int> providerSubset;
128  int nPendingFields = mSource->mFields.count();
129  Q_FOREACH ( int attrIndex, subset )
130  {
131  if ( attrIndex < 0 || attrIndex >= nPendingFields )
132  continue;
133  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
134  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
135  }
136 
137  // This is done in order to be prepared to do fallback order bys
138  // and be sure we have the required columns.
139  // TODO:
140  // It would be nicer to first check if we can compile the order by
141  // and only modify the subset if we cannot.
142  if ( !mProviderRequest.orderBy().isEmpty() )
143  {
144  Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
145  {
146  providerSubset << mSource->mFields.lookupField( attr );
147  }
148  }
149 
150  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
151  }
152 
154  {
155  Q_FOREACH ( const QString &field, mProviderRequest.filterExpression()->referencedColumns() )
156  {
157  int idx = source->mFields.lookupField( field );
158 
159  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
160  // In this case we disable the expression filter.
161  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
162  {
164  // can't limit at provider side
166  }
167  }
168  }
169 
170  if ( mSource->mHasEditBuffer )
171  {
173  QgsFeatureIds changedIds;
174  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
175  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
176  {
177  changedIds << attIt.key();
178  }
180 
181  if ( mChangedFeaturesRequest.limit() > 0 )
182  {
183  int providerLimit = mProviderRequest.limit();
184 
185  // features may be deleted in buffer, so increase limit sent to provider
186  providerLimit += mSource->mDeletedFeatureIds.size();
187 
189  {
190  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
191  providerLimit += mSource->mChangedAttributeValues.size();
192  }
193 
195  {
196  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
197  providerLimit += mSource->mChangedGeometries.size();
198  }
199 
200  mProviderRequest.setLimit( providerLimit );
201  }
202  }
203 
204  if ( request.filterType() == QgsFeatureRequest::FilterFid )
205  {
206  mFetchedFid = false;
207  }
208  else // no filter or filter by rect
209  {
210  if ( mSource->mHasEditBuffer )
211  {
213  }
214  else
215  {
217  }
218 
220  }
221 }
222 
223 
225 {
226  qDeleteAll( mExpressionFieldInfo );
227 
228  close();
229 }
230 
231 
232 
234 {
235  f.setValid( false );
236 
237  if ( mClosed )
238  return false;
239 
241  {
242  if ( mFetchedFid )
243  return false;
244  bool res = nextFeatureFid( f );
245  mFetchedFid = true;
246  return res;
247  }
248 
249  if ( !mRequest.filterRect().isNull() )
250  {
251  if ( fetchNextChangedGeomFeature( f ) )
252  return true;
253 
254  // no more changed geometries
255  }
256 
258  {
260  return true;
261 
262  // no more changed features
263  }
264 
265  while ( fetchNextAddedFeature( f ) )
266  {
267  return true;
268  }
269  // no more added features
270 
271  if ( mProviderIterator.isClosed() )
272  {
275  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
276  }
277 
278  while ( mProviderIterator.nextFeature( f ) )
279  {
280  if ( mFetchConsidered.contains( f.id() ) )
281  continue;
282 
283  // TODO[MD]: just one resize of attributes
284  f.setFields( mSource->mFields );
285 
286  // update attributes
287  if ( mSource->mHasEditBuffer )
289 
290  if ( mHasVirtualAttributes )
292 
294  {
295  //filtering by expression, and couldn't do it on the provider side
298  {
299  //feature did not match filter
300  continue;
301  }
302  }
303 
304  // update geometry
305  // TODO[MK]: FilterRect check after updating the geometry
308 
309  return true;
310  }
311  // no more provider features
312 
313  close();
314  return false;
315 }
316 
317 
318 
320 {
321  if ( mClosed )
322  return false;
323 
325  {
326  mFetchedFid = false;
327  }
328  else
329  {
332  }
333 
334  return true;
335 }
336 
338 {
339  if ( mClosed )
340  return false;
341 
343 
344  iteratorClosed();
345 
346  mClosed = true;
347  return true;
348 }
349 
351 {
352  mProviderIterator.setInterruptionChecker( interruptionChecker );
353  mInterruptionChecker = interruptionChecker;
354 }
355 
357 {
358  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
359  {
361 
362  if ( mFetchConsidered.contains( fid ) )
363  // must have changed geometry outside rectangle
364  continue;
365 
367  // skip features which are not accepted by the filter
368  continue;
369 
371 
372  return true;
373  }
374 
376  return false; // no more added features
377 }
378 
379 
381 {
382  f.setId( src.id() );
383  f.setValid( true );
384  f.setFields( mSource->mFields );
385 
387  {
388  f.setGeometry( src.geometry() );
389  }
390 
391  // TODO[MD]: if subset set just some attributes
392 
393  f.setAttributes( src.attributes() );
394 
395  if ( mHasVirtualAttributes )
397 }
398 
399 
400 
402 {
403  // check if changed geometries are in rectangle
405  {
406  QgsFeatureId fid = mFetchChangedGeomIt.key();
407 
408  if ( mFetchConsidered.contains( fid ) )
409  // skip deleted features
410  continue;
411 
412  mFetchConsidered << fid;
413 
414  if ( !mFetchChangedGeomIt->intersects( mRequest.filterRect() ) )
415  // skip changed geometries not in rectangle and don't check again
416  continue;
417 
419 
420  // return complete feature
422  return true;
423  }
424 
425  return false; // no more changed geometries
426 }
427 
429 {
431  {
432  if ( mFetchConsidered.contains( f.id() ) )
433  // skip deleted features and those already handled by the geometry
434  continue;
435 
436  mFetchConsidered << f.id();
437 
439 
440  if ( mHasVirtualAttributes )
442 
445  {
446  return true;
447  }
448  }
449 
450  return false;
451 }
452 
453 
455 {
456  f.setId( fid );
457  f.setValid( true );
458  f.setFields( mSource->mFields );
459 
461  {
462  f.setGeometry( geom );
463  }
464 
465  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
466  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
467  {
468  // retrieve attributes from provider
469  QgsFeature tmp;
470  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
471  QgsFeatureRequest request;
473  if ( subsetAttrs )
474  {
476  }
478  if ( fi.nextFeature( tmp ) )
479  {
482  f.setAttributes( tmp.attributes() );
483  }
484  }
485 
487 }
488 
489 
490 
492 {
494 
497 }
498 
500 {
501  if ( !mSource->mFields.exists( fieldIdx ) )
502  return;
503 
504  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
505  return;
506 
507  int sourceLayerIndex;
508  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
509  Q_ASSERT( joinInfo );
510 
511  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
512  if ( !joinLayer )
513  return; // invalid join (unresolved reference to layer)
514 
515  if ( !mFetchJoinInfo.contains( joinInfo ) )
516  {
517  FetchJoinInfo info;
518  info.joinInfo = joinInfo;
519  info.joinLayer = joinLayer;
522  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
523 
524  // for joined fields, we always need to request the targetField from the provider too
525  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
526  mFieldsToPrepare << info.targetField;
527 
530 
531  mFetchJoinInfo.insert( joinInfo, info );
532  }
533 
534  // store field source index - we'll need it when fetching from provider
535  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
536 }
537 
539 {
540  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
541 
542  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
543  QgsExpression *exp = new QgsExpression( exps[oi].cachedExpression );
544 
545  QgsDistanceArea da;
546  da.setSourceCrs( mSource->mCrsId );
547  da.setEllipsoidalMode( true );
548  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
549  exp->setGeomCalculator( &da );
550  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
551  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
552 
553  exp->prepare( mExpressionContext.get() );
554  mExpressionFieldInfo.insert( fieldIdx, exp );
555 
556  Q_FOREACH ( const QString &col, exp->referencedColumns() )
557  {
558  int dependentFieldIdx = mSource->mFields.lookupField( col );
560  {
561  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
562  }
563  // also need to fetch this dependent field
564  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
565  mFieldsToPrepare << dependentFieldIdx;
566  }
567 
568  if ( exp->needsGeometry() )
569  {
570  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
571  }
572 }
573 
575 {
576  mPreparedFields.clear();
577  mFieldsToPrepare.clear();
578  mFetchJoinInfo.clear();
579  mOrderedJoinInfoList.clear();
580 
581  mExpressionContext.reset( new QgsExpressionContext() );
582  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
583  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
584  mExpressionContext->setFields( mSource->mFields );
585 
587 
588  while ( !mFieldsToPrepare.isEmpty() )
589  {
590  int fieldIdx = mFieldsToPrepare.takeFirst();
591  if ( mPreparedFields.contains( fieldIdx ) )
592  continue;
593 
594  mPreparedFields << fieldIdx;
595  prepareField( fieldIdx );
596  }
597 
598  //sort joins by dependency
599  if ( mFetchJoinInfo.size() > 0 )
600  {
601  createOrderedJoinList();
602  }
603 }
604 
605 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
606 {
607  mOrderedJoinInfoList = mFetchJoinInfo.values();
608  if ( mOrderedJoinInfoList.size() < 2 )
609  {
610  return;
611  }
612 
613  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
614 
615  //add all provider fields without joins as resolved fields
616  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
617  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
618  {
619  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
620  {
621  resolvedFields.insert( *prepFieldIt );
622  }
623  }
624 
625  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
626 
627  //some join combinations might not have a resolution at all
628  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
629  int currentIteration = 0;
630 
631  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
632  {
633  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
634  {
635  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
636  mOrderedJoinInfoList.removeAt( i );
637  --i;
638  }
639  else
640  {
641  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
642  int joinField = mOrderedJoinInfoList.at( i ).joinField;
643 
644  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
645  QgsAttributeList::const_iterator attIt = attributes.constBegin();
646  for ( ; attIt != attributes.constEnd(); ++attIt )
647  {
648  if ( *attIt != joinField )
649  {
650  resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
651  }
652  }
653  }
654 
655  ++currentIteration;
656  if ( currentIteration >= maxIterations )
657  {
658  break;
659  }
660  }
661 }
662 
664 {
665  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
666  {
668  prepareExpression( fieldIdx );
669  break;
670 
673  {
674  prepareJoin( fieldIdx );
675  }
676  break;
677 
681  break;
682  }
683 }
684 
686 {
687  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
688  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
689  {
690  QVariant targetFieldValue = f.attribute( joinIt->targetField );
691  if ( !targetFieldValue.isValid() )
692  continue;
693 
694  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
695  if ( memoryCache.isEmpty() )
696  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
697  else
698  joinIt->addJoinedAttributesCached( f, targetFieldValue );
699  }
700 }
701 
703 {
704  // make sure we have space for newly added attributes
705  QgsAttributes attr = f.attributes();
706  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
707  f.setAttributes( attr );
708 
709  // possible TODO - handle combinations of expression -> join -> expression -> join?
710  // but for now, write that off as too complex and an unlikely rare, unsupported use case
711 
712  QList< int > fetchedVirtualAttributes;
713  //first, check through joins for any virtual fields we need
714  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
715  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
716  {
717  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
718  {
719  // have to calculate expression field before we can handle this join
720  addExpressionAttribute( f, joinIt->targetField );
721  fetchedVirtualAttributes << joinIt->targetField;
722  }
723  }
724 
725  if ( !mFetchJoinInfo.isEmpty() )
726  addJoinedAttributes( f );
727 
728  // add remaining expression fields
729  if ( !mExpressionFieldInfo.isEmpty() )
730  {
731  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
732  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
733  {
734  if ( fetchedVirtualAttributes.contains( it.key() ) )
735  continue;
736 
737  addExpressionAttribute( f, it.key() );
738  }
739  }
740 }
741 
743 {
744  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
745  if ( exp )
746  {
747  mExpressionContext->setFeature( f );
748  QVariant val = exp->evaluate( mExpressionContext.get() );
749  mSource->mFields.at( attrIndex ).convertCompatible( val );
750  f.setAttribute( attrIndex, val );
751  }
752  else
753  {
754  f.setAttribute( attrIndex, QVariant() );
755  }
756 }
757 
759 {
760  Q_UNUSED( simplifyMethod );
761  return false;
762 }
763 
764 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
765 {
766  Q_UNUSED( methodType );
767  return false;
768 }
769 
770 
772 {
773  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
774  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
775  if ( it == memoryCache.constEnd() )
776  return; // joined value not found -> leaving the attributes empty (null)
777 
778  int index = indexOffset;
779 
780  const QgsAttributes &featureAttributes = it.value();
781  for ( int i = 0; i < featureAttributes.count(); ++i )
782  {
783  f.setAttribute( index++, featureAttributes.at( i ) );
784  }
785 }
786 
787 
788 
790 {
791  // no memory cache, query the joined values by setting substring
792  QString subsetString;
793 
794  QString joinFieldName = joinInfo->joinFieldName();
795 
796  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
797 
798  if ( joinValue.isNull() )
799  {
800  subsetString += QLatin1String( " IS NULL" );
801  }
802  else
803  {
804  QString v = joinValue.toString();
805  switch ( joinValue.type() )
806  {
807  case QVariant::Int:
808  case QVariant::LongLong:
809  case QVariant::Double:
810  break;
811 
812  default:
813  case QVariant::String:
814  v.replace( '\'', QLatin1String( "''" ) );
815  v.prepend( '\'' ).append( '\'' );
816  break;
817  }
818  subsetString += '=' + v;
819  }
820 
821  // maybe user requested just a subset of layer's attributes
822  // so we do not have to cache everything
823  bool hasSubset = joinInfo->joinFieldNamesSubset();
824  QVector<int> subsetIndices;
825  if ( hasSubset )
826  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
827 
828  // select (no geometry)
829  QgsFeatureRequest request;
831  request.setSubsetOfAttributes( attributes );
832  request.setFilterExpression( subsetString );
833  request.setLimit( 1 );
834  QgsFeatureIterator fi = joinLayer->getFeatures( request );
835 
836  // get first feature
837  QgsFeature fet;
838  if ( fi.nextFeature( fet ) )
839  {
840  int index = indexOffset;
841  QgsAttributes attr = fet.attributes();
842  if ( hasSubset )
843  {
844  for ( int i = 0; i < subsetIndices.count(); ++i )
845  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
846  }
847  else
848  {
849  // use all fields except for the one used for join (has same value as exiting field in target layer)
850  for ( int i = 0; i < attr.count(); ++i )
851  {
852  if ( i == joinField )
853  continue;
854 
855  f.setAttribute( index++, attr.at( i ) );
856  }
857  }
858  }
859  else
860  {
861  // no suitable join feature found, keeping empty (null) attributes
862  }
863 }
864 
865 
866 
867 
869 {
870  QgsFeatureId featureId = mRequest.filterFid();
871 
872  // deleted already?
873  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
874  return false;
875 
876  // has changed geometry?
877  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
878  {
879  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
880  return true;
881  }
882 
883  // added features
884  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
885  {
886  if ( iter->id() == featureId )
887  {
888  useAddedFeature( *iter, f );
889  return true;
890  }
891  }
892 
893  // regular features
895  if ( fi.nextFeature( f ) )
896  {
897  f.setFields( mSource->mFields );
898 
899  if ( mSource->mHasEditBuffer )
901 
902  if ( mHasVirtualAttributes )
904 
905  return true;
906  }
907 
908  return false;
909 }
910 
912 {
913  QgsAttributes attrs = f.attributes();
914 
915  // remove all attributes that will disappear - from higher indices to lower
916  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
917  {
918  attrs.remove( mSource->mDeletedAttributeIds[idx] );
919  }
920 
921  // adjust size to accommodate added attributes
922  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
923 
924  // update changed attributes
925  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
926  {
928  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
929  attrs[it.key()] = it.value();
930  }
931  f.setAttributes( attrs );
932 }
933 
935 {
936  if ( mSource->mChangedGeometries.contains( f.id() ) )
938 }
939 
940 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
941 {
942  Q_UNUSED( orderBys );
943  return true;
944 }
945 
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:289
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
QgsAbstractFeatureSource * mProviderFeatureSource
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:140
void addJoinedAttributesDirect(QgsFeature &f, const QVariant &joinValue) const
Wrapper for iterator of features from vector data provider or vector layer.
QMap< QgsFeatureId, QgsGeometry > QgsGeometryMap
Definition: qgsfeature.h:356
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
static unsigned index
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
long limit() const
Returns the maximum number of features to request, or -1 if no limit set.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
QSet< QString > CORE_EXPORT usedAttributes() const
Returns a set of used attributes.
Filter using feature ID.
QgsVectorLayerJoinBuffer * mJoinBuffer
bool containsJoins() const
Quick way to test if there is any join at all.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:47
virtual void setInterruptionChecker(QgsInterruptionChecker *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped...
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:161
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:167
const Flags & flags() const
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
QMap< int, QgsExpression * > mExpressionFieldInfo
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:45
void addExpressionAttribute(QgsFeature &f, int attrIndex)
Adds an expression based attribute to a feature.
QgsFeatureMap::ConstIterator mFetchAddedFeaturesIt
QgsGeometryMap::ConstIterator mFetchChangedGeomIt
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:48
bool exists(int i) const
Return if a field index is valid.
Definition: qgsfields.cpp:125
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:358
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureId filterFid() const
Get the feature ID that should be fetched.
QVariant evaluate()
Evaluate the feature and return the result.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:225
FilterType filterType() const
Return the filter type which is currently set on this request.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Return a list of field name indexes obtained from the provided fields.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:79
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:139
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:216
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:46
bool setEllipsoid(const QString &ellipsoid)
Sets ellipsoid by its acronym.
bool mClosed
Set to true, as soon as the iterator is closed.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
QSet< QString > referencedColumns() const
Get list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:136
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed. ...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:202
QgsVectorLayer * joinLayer
Resolved pointer to the joined layer.
const QgsRectangle & filterRect() const
Get the rectangle from which features will be taken.
int count() const
Return number of items.
Definition: qgsfields.cpp:115
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
It has not been specified where the field comes from.
Definition: qgsfields.h:45
QgsFields fields() const
Returns the list of fields of this layer.
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:135
int joinField
Index of field (of the joined layer) must have equal value.
QgsExpression * filterExpression() const
Returns the filter expression if set.
int fieldOriginIndex(int fieldIdx) const
Get field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:169
virtual QgsAbstractFeatureSource * featureSource() const =0
Return feature source object that can be used for querying provider&#39;s data.
Interface that can be optionally attached to an iterator so its nextFeature() implementaton can check...
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Set feature ID that should be fetched.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
void iteratorClosed()
to be called by from subclass in close()
int indexFromName(const QString &fieldName) const
Get the field index from the field name.
Definition: qgsfields.cpp:174
void useAddedFeature(const QgsFeature &src, QgsFeature &f)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsVectorLayer * joinLayer() const
Returns joined layer (may be null if the reference was set by layer ID and not resolved yet) ...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:316
QgsFeatureRequest & disableFilter()
Disables filter conditions.
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod) override
Setup the simplification of geometries to fetch using the specified simplify method.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const
Defines left outer join from our vector layer to some other vector layer.
virtual bool fetchFeature(QgsFeature &feature) override
fetch next feature, return true on success
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:124
QgsExpressionFieldBuffer * mExpressionFieldBuffer
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QgsAttributeList subsetOfAttributes() const
Return the subset of attributes which at least need to be fetched.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
QList< ExpressionField > expressions() const
int indexOffset
At what position the joined fields start.
void useChangedAttributeFeature(QgsFeatureId fid, const QgsGeometry &geom, QgsFeature &f)
General purpose distance and area calculator.
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:193
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
QgsFeatureMap addedFeatures() const
Returns a map of new features which are not committed.
QgsFeatureRequest mRequest
A copy of the feature request.
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
int targetField
Index of field (of this layer) that drives the join.
Buffers information about expression fields for a vector layer.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set feature IDs that should be fetched.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request) override
Get an iterator for features matching the specified request.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:353
bool prepare(const QgsExpressionContext *context)
Get the expression ready for evaluation - find out column indexes.
virtual bool rewind() override
reset the iterator to the starting position
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:359
virtual bool close() override
end of iterating: free the resources / lock
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Return a vector of indices for use in join based on field names from the layer.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:149
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
qint64 QgsFeatureId
Definition: qgsfeature.h:33
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request)=0
Get an iterator for features matching the specified request.
QMap< const QgsVectorLayerJoinInfo *, FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
long srsid() const
Returns the internal CRS ID, if available.
QgsChangedAttributesMap mChangedAttributeValues
OrderBy orderBy() const
Return a list of order by clauses specified for this feature request.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QList< QgsField > addedAttributes() const
Returns a list of added attributes fields which are not committed.
A vector of attributes.
Definition: qgsfeature.h:56
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:267
Field is calculated from an expression.
Definition: qgsfields.h:49
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
bool isClosed() const
find out whether the iterator is still valid or closed already
QgsVectorLayerFeatureSource(const QgsVectorLayer *layer)
Constructor for QgsVectorLayerFeatureSource.
QgsAttributes attributes
Definition: qgsfeature.h:141
void setInterruptionChecker(QgsInterruptionChecker *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped...
void setEllipsoidalMode(bool flag)
Sets whether coordinates must be projected to ellipsoid before measuring.
int joinedFieldsOffset(const QgsVectorLayerJoinInfo *info, const QgsFields &fields)
Find out what is the first index of the join within fields.
QgsVectorLayerJoinBuffer * clone() const
Create a copy of the join buffer.
void addVirtualAttributes(QgsFeature &f)
Adds attributes that don&#39;t source from the provider but are added inside QGIS Includes.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.
Helper template that cares of two things: 1.