QGIS API Documentation  2.99.0-Master (283d45a)
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  layer->createJoinCaches();
36  mJoinBuffer = layer->mJoinBuffer->clone();
37 
38  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
39  mCrsId = layer->crs().srsid();
40 
41  mHasEditBuffer = layer->editBuffer();
42  if ( mHasEditBuffer )
43  {
44 #if 0
45  // TODO[MD]: after merge
46  if ( request.filterType() == QgsFeatureRequest::FilterFid )
47  {
48 
49  // only copy relevant parts
50  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
51  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
52 
53  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
54  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
55 
56  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
57  mDeletedFeatureIds.insert( request.filterFid() );
58 
59  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
60  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
61 
62  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
63  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
64  }
65  else
66  {
67 #endif
72  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
74 #if 0
75  }
76 #endif
77  }
78 }
79 
81 {
82  delete mJoinBuffer;
85 }
86 
88 {
89  // return feature iterator that does not own this source
90  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
91 }
92 
93 
96  , mFetchedFid( false )
97  , mInterruptionChecker( nullptr )
98 {
100  {
103 
105  {
106  //ensure that all fields required for filter expressions are prepared
107  QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
108  attributeIndexes += mRequest.subsetOfAttributes().toSet();
109  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
110  }
111  }
112 
113  prepareFields();
114 
115  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
116 
117  // by default provider's request is the same
119 
121  {
122  // prepare list of attributes to match provider fields
123  QSet<int> providerSubset;
125  int nPendingFields = mSource->mFields.count();
126  Q_FOREACH ( int attrIndex, subset )
127  {
128  if ( attrIndex < 0 || attrIndex >= nPendingFields )
129  continue;
130  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
131  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
132  }
133 
134  // This is done in order to be prepared to do fallback order bys
135  // and be sure we have the required columns.
136  // TODO:
137  // It would be nicer to first check if we can compile the order by
138  // and only modify the subset if we cannot.
139  if ( !mProviderRequest.orderBy().isEmpty() )
140  {
141  Q_FOREACH ( const QString& attr, mProviderRequest.orderBy().usedAttributes() )
142  {
143  providerSubset << mSource->mFields.lookupField( attr );
144  }
145  }
146 
147  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
148  }
149 
151  {
152  Q_FOREACH ( const QString& field, mProviderRequest.filterExpression()->referencedColumns() )
153  {
154  int idx = source->mFields.lookupField( field );
155 
156  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
157  // In this case we disable the expression filter.
158  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
159  {
161  // can't limit at provider side
163  }
164  }
165  }
166 
167  if ( mSource->mHasEditBuffer )
168  {
170  QgsFeatureIds changedIds;
171  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
172  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
173  {
174  changedIds << attIt.key();
175  }
177 
178  if ( mChangedFeaturesRequest.limit() > 0 )
179  {
180  int providerLimit = mProviderRequest.limit();
181 
182  // features may be deleted in buffer, so increase limit sent to provider
183  providerLimit += mSource->mDeletedFeatureIds.size();
184 
186  {
187  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
188  providerLimit += mSource->mChangedAttributeValues.size();
189  }
190 
192  {
193  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
194  providerLimit += mSource->mChangedGeometries.size();
195  }
196 
197  mProviderRequest.setLimit( providerLimit );
198  }
199  }
200 
201  if ( request.filterType() == QgsFeatureRequest::FilterFid )
202  {
203  mFetchedFid = false;
204  }
205  else // no filter or filter by rect
206  {
207  if ( mSource->mHasEditBuffer )
208  {
210  }
211  else
212  {
214  }
215 
217  }
218 }
219 
220 
222 {
223  qDeleteAll( mExpressionFieldInfo );
224 
225  close();
226 }
227 
228 
229 
231 {
232  f.setValid( false );
233 
234  if ( mClosed )
235  return false;
236 
238  {
239  if ( mFetchedFid )
240  return false;
241  bool res = nextFeatureFid( f );
242  mFetchedFid = true;
243  return res;
244  }
245 
246  if ( !mRequest.filterRect().isNull() )
247  {
248  if ( fetchNextChangedGeomFeature( f ) )
249  return true;
250 
251  // no more changed geometries
252  }
253 
255  {
257  return true;
258 
259  // no more changed features
260  }
261 
262  while ( fetchNextAddedFeature( f ) )
263  {
264  return true;
265  }
266  // no more added features
267 
268  if ( mProviderIterator.isClosed() )
269  {
272  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
273  }
274 
275  while ( mProviderIterator.nextFeature( f ) )
276  {
277  if ( mFetchConsidered.contains( f.id() ) )
278  continue;
279 
280  // TODO[MD]: just one resize of attributes
281  f.setFields( mSource->mFields );
282 
283  // update attributes
284  if ( mSource->mHasEditBuffer )
286 
287  if ( mHasVirtualAttributes )
289 
291  {
292  //filtering by expression, and couldn't do it on the provider side
295  {
296  //feature did not match filter
297  continue;
298  }
299  }
300 
301  // update geometry
302  // TODO[MK]: FilterRect check after updating the geometry
305 
306  return true;
307  }
308  // no more provider features
309 
310  close();
311  return false;
312 }
313 
314 
315 
317 {
318  if ( mClosed )
319  return false;
320 
322  {
323  mFetchedFid = false;
324  }
325  else
326  {
329  }
330 
331  return true;
332 }
333 
335 {
336  if ( mClosed )
337  return false;
338 
340 
341  iteratorClosed();
342 
343  mClosed = true;
344  return true;
345 }
346 
348 {
349  mProviderIterator.setInterruptionChecker( interruptionChecker );
350  mInterruptionChecker = interruptionChecker;
351 }
352 
354 {
355  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
356  {
358 
359  if ( mFetchConsidered.contains( fid ) )
360  // must have changed geometry outside rectangle
361  continue;
362 
364  // skip features which are not accepted by the filter
365  continue;
366 
368 
369  return true;
370  }
371 
373  return false; // no more added features
374 }
375 
376 
378 {
379  f.setId( src.id() );
380  f.setValid( true );
381  f.setFields( mSource->mFields );
382 
384  {
385  f.setGeometry( src.geometry() );
386  }
387 
388  // TODO[MD]: if subset set just some attributes
389 
390  f.setAttributes( src.attributes() );
391 
392  if ( mHasVirtualAttributes )
394 }
395 
396 
397 
399 {
400  // check if changed geometries are in rectangle
402  {
403  QgsFeatureId fid = mFetchChangedGeomIt.key();
404 
405  if ( mFetchConsidered.contains( fid ) )
406  // skip deleted features
407  continue;
408 
409  mFetchConsidered << fid;
410 
411  if ( !mFetchChangedGeomIt->intersects( mRequest.filterRect() ) )
412  // skip changed geometries not in rectangle and don't check again
413  continue;
414 
416 
417  // return complete feature
419  return true;
420  }
421 
422  return false; // no more changed geometries
423 }
424 
426 {
428  {
429  if ( mFetchConsidered.contains( f.id() ) )
430  // skip deleted features and those already handled by the geometry
431  continue;
432 
433  mFetchConsidered << f.id();
434 
436 
437  if ( mHasVirtualAttributes )
439 
442  {
443  return true;
444  }
445  }
446 
447  return false;
448 }
449 
450 
452 {
453  f.setId( fid );
454  f.setValid( true );
455  f.setFields( mSource->mFields );
456 
458  {
459  f.setGeometry( geom );
460  }
461 
462  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
463  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
464  {
465  // retrieve attributes from provider
466  QgsFeature tmp;
467  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
468  QgsFeatureRequest request;
470  if ( subsetAttrs )
471  {
473  }
475  if ( fi.nextFeature( tmp ) )
476  {
479  f.setAttributes( tmp.attributes() );
480  }
481  }
482 
484 }
485 
486 
487 
489 {
491 
494 }
495 
497 {
498  if ( !mSource->mFields.exists( fieldIdx ) )
499  return;
500 
501  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
502  return;
503 
504  int sourceLayerIndex;
505  const QgsVectorJoinInfo* joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
506  Q_ASSERT( joinInfo );
507 
508  QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( joinInfo->joinLayerId ) );
509  Q_ASSERT( joinLayer );
510 
511  if ( !mFetchJoinInfo.contains( joinInfo ) )
512  {
513  FetchJoinInfo info;
514  info.joinInfo = joinInfo;
515  info.joinLayer = joinLayer;
517 
518  if ( joinInfo->targetFieldName.isEmpty() )
519  info.targetField = joinInfo->targetFieldIndex; //for compatibility with 1.x
520  else
522 
523  if ( joinInfo->joinFieldName.isEmpty() )
524  info.joinField = joinInfo->joinFieldIndex; //for compatibility with 1.x
525  else
526  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName );
527 
528  // for joined fields, we always need to request the targetField from the provider too
529  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
530  mFieldsToPrepare << info.targetField;
531 
534 
535  mFetchJoinInfo.insert( joinInfo, info );
536  }
537 
538  // store field source index - we'll need it when fetching from provider
539  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
540 }
541 
543 {
544  const QList<QgsExpressionFieldBuffer::ExpressionField>& exps = mSource->mExpressionFieldBuffer->expressions();
545 
546  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
547  QgsExpression* exp = new QgsExpression( exps[oi].cachedExpression );
548 
549  QgsDistanceArea da;
550  da.setSourceCrs( mSource->mCrsId );
551  da.setEllipsoidalMode( true );
552  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
553  exp->setGeomCalculator( &da );
554  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
555  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
556 
557  exp->prepare( mExpressionContext.data() );
558  mExpressionFieldInfo.insert( fieldIdx, exp );
559 
560  Q_FOREACH ( const QString& col, exp->referencedColumns() )
561  {
562  int dependentFieldIdx = mSource->mFields.lookupField( col );
564  {
565  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
566  }
567  // also need to fetch this dependent field
568  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
569  mFieldsToPrepare << dependentFieldIdx;
570  }
571 
572  if ( exp->needsGeometry() )
573  {
574  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
575  }
576 }
577 
579 {
580  mPreparedFields.clear();
581  mFieldsToPrepare.clear();
582  mFetchJoinInfo.clear();
583  mOrderedJoinInfoList.clear();
584 
585  mExpressionContext.reset( new QgsExpressionContext() );
586  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
587  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
588  mExpressionContext->setFields( mSource->mFields );
589 
591 
592  while ( !mFieldsToPrepare.isEmpty() )
593  {
594  int fieldIdx = mFieldsToPrepare.takeFirst();
595  if ( mPreparedFields.contains( fieldIdx ) )
596  continue;
597 
598  mPreparedFields << fieldIdx;
599  prepareField( fieldIdx );
600  }
601 
602  //sort joins by dependency
603  if ( mFetchJoinInfo.size() > 0 )
604  {
605  createOrderedJoinList();
606  }
607 }
608 
609 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
610 {
611  mOrderedJoinInfoList = mFetchJoinInfo.values();
612  if ( mOrderedJoinInfoList.size() < 2 )
613  {
614  return;
615  }
616 
617  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
618 
619  //add all provider fields without joins as resolved fields
620  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
621  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
622  {
623  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
624  {
625  resolvedFields.insert( *prepFieldIt );
626  }
627  }
628 
629  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
630 
631  //some join combinations might not have a resolution at all
632  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
633  int currentIteration = 0;
634 
635  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
636  {
637  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
638  {
639  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
640  mOrderedJoinInfoList.removeAt( i );
641  --i;
642  }
643  else
644  {
645  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
646  int joinField = mOrderedJoinInfoList.at( i ).joinField;
647 
648  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
649  QgsAttributeList::const_iterator attIt = attributes.constBegin();
650  for ( ; attIt != attributes.constEnd(); ++attIt )
651  {
652  if ( *attIt != joinField )
653  {
654  resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
655  }
656  }
657  }
658 
659  ++currentIteration;
660  if ( currentIteration >= maxIterations )
661  {
662  break;
663  }
664  }
665 }
666 
668 {
669  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
670  {
672  prepareExpression( fieldIdx );
673  break;
674 
677  {
678  prepareJoin( fieldIdx );
679  }
680  break;
681 
685  break;
686  }
687 }
688 
690 {
691  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
692  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
693  {
694  QVariant targetFieldValue = f.attribute( joinIt->targetField );
695  if ( !targetFieldValue.isValid() )
696  continue;
697 
698  const QHash< QString, QgsAttributes>& memoryCache = joinIt->joinInfo->cachedAttributes;
699  if ( memoryCache.isEmpty() )
700  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
701  else
702  joinIt->addJoinedAttributesCached( f, targetFieldValue );
703  }
704 }
705 
707 {
708  // make sure we have space for newly added attributes
709  QgsAttributes attr = f.attributes();
710  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
711  f.setAttributes( attr );
712 
713  // possible TODO - handle combinations of expression -> join -> expression -> join?
714  // but for now, write that off as too complex and an unlikely rare, unsupported use case
715 
716  QList< int > fetchedVirtualAttributes;
717  //first, check through joins for any virtual fields we need
718  QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
719  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
720  {
721  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
722  {
723  // have to calculate expression field before we can handle this join
724  addExpressionAttribute( f, joinIt->targetField );
725  fetchedVirtualAttributes << joinIt->targetField;
726  }
727  }
728 
729  if ( !mFetchJoinInfo.isEmpty() )
730  addJoinedAttributes( f );
731 
732  // add remaining expression fields
733  if ( !mExpressionFieldInfo.isEmpty() )
734  {
735  QMap<int, QgsExpression*>::ConstIterator it = mExpressionFieldInfo.constBegin();
736  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
737  {
738  if ( fetchedVirtualAttributes.contains( it.key() ) )
739  continue;
740 
741  addExpressionAttribute( f, it.key() );
742  }
743  }
744 }
745 
747 {
748  QgsExpression* exp = mExpressionFieldInfo.value( attrIndex );
749  mExpressionContext->setFeature( f );
750  QVariant val = exp->evaluate( mExpressionContext.data() );
751  mSource->mFields.at( attrIndex ).convertCompatible( val );
752  f.setAttribute( attrIndex, val );
753 }
754 
756 {
757  Q_UNUSED( simplifyMethod );
758  return false;
759 }
760 
761 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
762 {
763  Q_UNUSED( methodType );
764  return false;
765 }
766 
767 
769 {
770  const QHash<QString, QgsAttributes>& memoryCache = joinInfo->cachedAttributes;
771  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
772  if ( it == memoryCache.constEnd() )
773  return; // joined value not found -> leaving the attributes empty (null)
774 
775  int index = indexOffset;
776 
777  const QgsAttributes& featureAttributes = it.value();
778  for ( int i = 0; i < featureAttributes.count(); ++i )
779  {
780  f.setAttribute( index++, featureAttributes.at( i ) );
781  }
782 }
783 
784 
785 
787 {
788  // no memory cache, query the joined values by setting substring
789  QString subsetString;
790 
791  QString joinFieldName;
792  if ( joinInfo->joinFieldName.isEmpty() && joinInfo->joinFieldIndex >= 0 && joinInfo->joinFieldIndex < joinLayer->fields().count() )
793  joinFieldName = joinLayer->fields().field( joinInfo->joinFieldIndex ).name(); // for compatibility with 1.x
794  else
795  joinFieldName = joinInfo->joinFieldName;
796 
797  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
798 
799  if ( joinValue.isNull() )
800  {
801  subsetString += QLatin1String( " IS NULL" );
802  }
803  else
804  {
805  QString v = joinValue.toString();
806  switch ( joinValue.type() )
807  {
808  case QVariant::Int:
809  case QVariant::LongLong:
810  case QVariant::Double:
811  break;
812 
813  default:
814  case QVariant::String:
815  v.replace( '\'', QLatin1String( "''" ) );
816  v.prepend( '\'' ).append( '\'' );
817  break;
818  }
819  subsetString += '=' + v;
820  }
821 
822  // maybe user requested just a subset of layer's attributes
823  // so we do not have to cache everything
824  bool hasSubset = joinInfo->joinFieldNamesSubset();
825  QVector<int> subsetIndices;
826  if ( hasSubset )
827  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
828 
829  // select (no geometry)
830  QgsFeatureRequest request;
832  request.setSubsetOfAttributes( attributes );
833  request.setFilterExpression( subsetString );
834  request.setLimit( 1 );
835  QgsFeatureIterator fi = joinLayer->getFeatures( request );
836 
837  // get first feature
838  QgsFeature fet;
839  if ( fi.nextFeature( fet ) )
840  {
841  int index = indexOffset;
842  QgsAttributes attr = fet.attributes();
843  if ( hasSubset )
844  {
845  for ( int i = 0; i < subsetIndices.count(); ++i )
846  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
847  }
848  else
849  {
850  // use all fields except for the one used for join (has same value as exiting field in target layer)
851  for ( int i = 0; i < attr.count(); ++i )
852  {
853  if ( i == joinField )
854  continue;
855 
856  f.setAttribute( index++, attr.at( i ) );
857  }
858  }
859  }
860  else
861  {
862  // no suitable join feature found, keeping empty (null) attributes
863  }
864 }
865 
866 
867 
868 
870 {
871  QgsFeatureId featureId = mRequest.filterFid();
872 
873  // deleted already?
874  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
875  return false;
876 
877  // has changed geometry?
878  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
879  {
880  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
881  return true;
882  }
883 
884  // added features
885  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
886  {
887  if ( iter->id() == featureId )
888  {
889  useAddedFeature( *iter, f );
890  return true;
891  }
892  }
893 
894  // regular features
896  if ( fi.nextFeature( f ) )
897  {
898  f.setFields( mSource->mFields );
899 
900  if ( mSource->mHasEditBuffer )
902 
903  if ( mHasVirtualAttributes )
905 
906  return true;
907  }
908 
909  return false;
910 }
911 
913 {
914  QgsAttributes attrs = f.attributes();
915 
916  // remove all attributes that will disappear - from higher indices to lower
917  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
918  {
919  attrs.remove( mSource->mDeletedAttributeIds[idx] );
920  }
921 
922  // adjust size to accommodate added attributes
923  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
924 
925  // update changed attributes
926  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
927  {
929  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
930  attrs[it.key()] = it.value();
931  }
932  f.setAttributes( attrs );
933 }
934 
936 {
937  if ( mSource->mChangedGeometries.contains( f.id() ) )
939 }
940 
941 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause>& orderBys )
942 {
943  Q_UNUSED( orderBys );
944  return true;
945 }
946 
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:346
static unsigned index
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.
QString joinFieldName
Join field in the source layer.
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
QString targetFieldName
Join field in the target layer.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:164
const Flags & flags() const
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:45
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
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:348
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.
int joinFieldIndex
Join field index in the source layer. For backward compatibility with 1.x (x>=7)
const QgsVectorJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
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:138
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:213
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QMap< int, QgsExpression * > mExpressionFieldInfo
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.
int targetFieldIndex
Join field index in the target layer. For backward compatibility with 1.x (x>=7)
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:199
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
void createJoinCaches() const
Caches joined attributes if required (and not already done)
QMap< const QgsVectorJoinInfo *, FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
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 joinedFieldsOffset(const QgsVectorJoinInfo *info, const QgsFields &fields)
Find out what is the first index of the join within fields.
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 optionaly 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...
QgsAttributeList allAttributesList() const
Utility function to get list of attribute indexes.
Definition: qgsfields.cpp:316
const QgsVectorJoinInfo * joinInfo
Cannonical source of information about the join.
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
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.
Obsolete, will be ignored. If a filterRect is set it will be used anyway. Filter using a rectangle...
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:190
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:343
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:350
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:147
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
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.
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:262
Field is calculated from an expression.
Definition: qgsfields.h:49
QString joinLayerId
Source layer.
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.
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.