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