QGIS API Documentation  2.99.0-Master (5169e0d)
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 #include "qgsmessagelog.h"
28 
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  mCrs = layer->crs();
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  if ( res && testFeature( f ) )
246  {
247  mFetchedFid = true;
248  return res;
249  }
250  else
251  {
252  return false;
253  }
254  }
255 
256  if ( !mRequest.filterRect().isNull() )
257  {
258  if ( fetchNextChangedGeomFeature( f ) )
259  return true;
260 
261  // no more changed geometries
262  }
263 
265  {
267  return true;
268 
269  // no more changed features
270  }
271 
272  while ( fetchNextAddedFeature( f ) )
273  {
274  return true;
275  }
276  // no more added features
277 
278  if ( mProviderIterator.isClosed() )
279  {
282  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
283  }
284 
285  while ( mProviderIterator.nextFeature( f ) )
286  {
287  if ( mFetchConsidered.contains( f.id() ) )
288  continue;
289 
290  // TODO[MD]: just one resize of attributes
291  f.setFields( mSource->mFields );
292 
293  // update attributes
294  if ( mSource->mHasEditBuffer )
296 
297  if ( mHasVirtualAttributes )
299 
301  {
302  //filtering by expression, and couldn't do it on the provider side
305  {
306  //feature did not match filter
307  continue;
308  }
309  }
310 
311  // update geometry
312  // TODO[MK]: FilterRect check after updating the geometry
315 
316  if ( !testFeature( f ) )
317  continue;
318 
319  return true;
320  }
321  // no more provider features
322 
323  close();
324  return false;
325 }
326 
327 
328 
330 {
331  if ( mClosed )
332  return false;
333 
335  {
336  mFetchedFid = false;
337  }
338  else
339  {
342  }
343 
344  return true;
345 }
346 
348 {
349  if ( mClosed )
350  return false;
351 
353 
354  iteratorClosed();
355 
356  mClosed = true;
357  return true;
358 }
359 
361 {
362  mProviderIterator.setInterruptionChecker( interruptionChecker );
363  mInterruptionChecker = interruptionChecker;
364 }
365 
367 {
368  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
369  {
371 
372  if ( mFetchConsidered.contains( fid ) )
373  // must have changed geometry outside rectangle
374  continue;
375 
377  // skip features which are not accepted by the filter
378  continue;
379 
380  if ( !testFeature( *mFetchAddedFeaturesIt ) )
381  continue;
382 
384 
385  return true;
386  }
387 
389  return false; // no more added features
390 }
391 
392 
394 {
395  f.setId( src.id() );
396  f.setValid( true );
397  f.setFields( mSource->mFields );
398 
400  {
401  f.setGeometry( src.geometry() );
402  }
403 
404  // TODO[MD]: if subset set just some attributes
405 
406  f.setAttributes( src.attributes() );
407 
408  if ( mHasVirtualAttributes )
410 }
411 
412 
413 
415 {
416  // check if changed geometries are in rectangle
418  {
419  QgsFeatureId fid = mFetchChangedGeomIt.key();
420 
421  if ( mFetchConsidered.contains( fid ) )
422  // skip deleted features
423  continue;
424 
425  mFetchConsidered << fid;
426 
427  if ( !mFetchChangedGeomIt->intersects( mRequest.filterRect() ) )
428  // skip changed geometries not in rectangle and don't check again
429  continue;
430 
432 
433  if ( testFeature( f ) )
434  {
435  // return complete feature
437  return true;
438  }
439  }
440 
441  return false; // no more changed geometries
442 }
443 
445 {
447  {
448  if ( mFetchConsidered.contains( f.id() ) )
449  // skip deleted features and those already handled by the geometry
450  continue;
451 
452  mFetchConsidered << f.id();
453 
455 
456  if ( mHasVirtualAttributes )
458 
460  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && testFeature( f ) )
461  {
462  return true;
463  }
464  }
465 
466  return false;
467 }
468 
469 
471 {
472  f.setId( fid );
473  f.setValid( true );
474  f.setFields( mSource->mFields );
475 
477  {
478  f.setGeometry( geom );
479  }
480 
481  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
482  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
483  {
484  // retrieve attributes from provider
485  QgsFeature tmp;
486  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
487  QgsFeatureRequest request;
489  if ( subsetAttrs )
490  {
492  }
494  if ( fi.nextFeature( tmp ) )
495  {
498  f.setAttributes( tmp.attributes() );
499  }
500  }
501 
503 }
504 
505 
506 
508 {
510 
513 }
514 
516 {
517  if ( !mSource->mFields.exists( fieldIdx ) )
518  return;
519 
520  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
521  return;
522 
523  int sourceLayerIndex;
524  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
525  Q_ASSERT( joinInfo );
526 
527  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
528  if ( !joinLayer )
529  return; // invalid join (unresolved reference to layer)
530 
531  if ( !mFetchJoinInfo.contains( joinInfo ) )
532  {
533  FetchJoinInfo info;
534  info.joinInfo = joinInfo;
535  info.joinLayer = joinLayer;
538  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
539 
540  // for joined fields, we always need to request the targetField from the provider too
541  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
542  mFieldsToPrepare << info.targetField;
543 
546 
547  mFetchJoinInfo.insert( joinInfo, info );
548  }
549 
550  // store field source index - we'll need it when fetching from provider
551  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
552 }
553 
555 {
556  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
557 
558  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
559  QgsExpression *exp = new QgsExpression( exps[oi].cachedExpression );
560 
561  QgsDistanceArea da;
562  da.setSourceCrs( mSource->mCrs );
563  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
564  exp->setGeomCalculator( &da );
565  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
566  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
567 
568  exp->prepare( mExpressionContext.get() );
569  mExpressionFieldInfo.insert( fieldIdx, exp );
570 
571  Q_FOREACH ( const QString &col, exp->referencedColumns() )
572  {
573  int dependentFieldIdx = mSource->mFields.lookupField( col );
575  {
576  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
577  }
578  // also need to fetch this dependent field
579  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
580  mFieldsToPrepare << dependentFieldIdx;
581  }
582 
583  if ( exp->needsGeometry() )
584  {
585  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
586  }
587 }
588 
590 {
591  mPreparedFields.clear();
592  mFieldsToPrepare.clear();
593  mFetchJoinInfo.clear();
594  mOrderedJoinInfoList.clear();
595 
596  mExpressionContext.reset( new QgsExpressionContext() );
597  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
598  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
599  mExpressionContext->setFields( mSource->mFields );
600 
602 
603  while ( !mFieldsToPrepare.isEmpty() )
604  {
605  int fieldIdx = mFieldsToPrepare.takeFirst();
606  if ( mPreparedFields.contains( fieldIdx ) )
607  continue;
608 
609  mPreparedFields << fieldIdx;
610  prepareField( fieldIdx );
611  }
612 
613  //sort joins by dependency
614  if ( mFetchJoinInfo.size() > 0 )
615  {
616  createOrderedJoinList();
617  }
618 }
619 
620 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
621 {
622  mOrderedJoinInfoList = mFetchJoinInfo.values();
623  if ( mOrderedJoinInfoList.size() < 2 )
624  {
625  return;
626  }
627 
628  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
629 
630  //add all provider fields without joins as resolved fields
631  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
632  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
633  {
634  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
635  {
636  resolvedFields.insert( *prepFieldIt );
637  }
638  }
639 
640  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
641 
642  //some join combinations might not have a resolution at all
643  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
644  int currentIteration = 0;
645 
646  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
647  {
648  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
649  {
650  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
651  mOrderedJoinInfoList.removeAt( i );
652  --i;
653  }
654  else
655  {
656  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
657  int joinField = mOrderedJoinInfoList.at( i ).joinField;
658 
659  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
660  QgsAttributeList::const_iterator attIt = attributes.constBegin();
661  for ( ; attIt != attributes.constEnd(); ++attIt )
662  {
663  if ( *attIt != joinField )
664  {
665  resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
666  }
667  }
668  }
669 
670  ++currentIteration;
671  if ( currentIteration >= maxIterations )
672  {
673  break;
674  }
675  }
676 }
677 
678 bool QgsVectorLayerFeatureIterator::testFeature( const QgsFeature &feature )
679 {
680  bool result = checkGeometryValidity( feature );
681  return result;
682 }
683 
684 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
685 {
686  if ( !feature.hasGeometry() )
687  return true;
688 
689  switch ( mRequest.invalidGeometryCheck() )
690  {
692  return true;
693 
695  {
696  if ( !feature.geometry().isGeosValid() )
697  {
698  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), QgsMessageLog::CRITICAL );
699  return false;
700  }
701  break;
702  }
703 
705  if ( !feature.geometry().isGeosValid() )
706  {
707  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), QgsMessageLog::CRITICAL );
708  close();
710  {
711  mRequest.invalidGeometryCallback()( feature );
712  }
713  return false;
714  }
715  break;
716  }
717 
718  return true;
719 }
720 
722 {
723  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
724  {
726  prepareExpression( fieldIdx );
727  break;
728 
731  {
732  prepareJoin( fieldIdx );
733  }
734  break;
735 
739  break;
740  }
741 }
742 
744 {
745  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
746  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
747  {
748  QVariant targetFieldValue = f.attribute( joinIt->targetField );
749  if ( !targetFieldValue.isValid() )
750  continue;
751 
752  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
753  if ( memoryCache.isEmpty() )
754  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
755  else
756  joinIt->addJoinedAttributesCached( f, targetFieldValue );
757  }
758 }
759 
761 {
762  // make sure we have space for newly added attributes
763  QgsAttributes attr = f.attributes();
764  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
765  f.setAttributes( attr );
766 
767  // possible TODO - handle combinations of expression -> join -> expression -> join?
768  // but for now, write that off as too complex and an unlikely rare, unsupported use case
769 
770  QList< int > fetchedVirtualAttributes;
771  //first, check through joins for any virtual fields we need
772  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
773  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
774  {
775  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
776  {
777  // have to calculate expression field before we can handle this join
778  addExpressionAttribute( f, joinIt->targetField );
779  fetchedVirtualAttributes << joinIt->targetField;
780  }
781  }
782 
783  if ( !mFetchJoinInfo.isEmpty() )
784  addJoinedAttributes( f );
785 
786  // add remaining expression fields
787  if ( !mExpressionFieldInfo.isEmpty() )
788  {
789  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
790  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
791  {
792  if ( fetchedVirtualAttributes.contains( it.key() ) )
793  continue;
794 
795  addExpressionAttribute( f, it.key() );
796  }
797  }
798 }
799 
801 {
802  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
803  if ( exp )
804  {
805  mExpressionContext->setFeature( f );
806  QVariant val = exp->evaluate( mExpressionContext.get() );
807  mSource->mFields.at( attrIndex ).convertCompatible( val );
808  f.setAttribute( attrIndex, val );
809  }
810  else
811  {
812  f.setAttribute( attrIndex, QVariant() );
813  }
814 }
815 
817 {
818  Q_UNUSED( simplifyMethod );
819  return false;
820 }
821 
822 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
823 {
824  Q_UNUSED( methodType );
825  return false;
826 }
827 
828 
830 {
831  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
832  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
833  if ( it == memoryCache.constEnd() )
834  return; // joined value not found -> leaving the attributes empty (null)
835 
836  int index = indexOffset;
837 
838  const QgsAttributes &featureAttributes = it.value();
839  for ( int i = 0; i < featureAttributes.count(); ++i )
840  {
841  f.setAttribute( index++, featureAttributes.at( i ) );
842  }
843 }
844 
845 
846 
848 {
849  // no memory cache, query the joined values by setting substring
850  QString subsetString;
851 
852  QString joinFieldName = joinInfo->joinFieldName();
853 
854  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
855 
856  if ( joinValue.isNull() )
857  {
858  subsetString += QLatin1String( " IS NULL" );
859  }
860  else
861  {
862  QString v = joinValue.toString();
863  switch ( joinValue.type() )
864  {
865  case QVariant::Int:
866  case QVariant::LongLong:
867  case QVariant::Double:
868  break;
869 
870  default:
871  case QVariant::String:
872  v.replace( '\'', QLatin1String( "''" ) );
873  v.prepend( '\'' ).append( '\'' );
874  break;
875  }
876  subsetString += '=' + v;
877  }
878 
879  // maybe user requested just a subset of layer's attributes
880  // so we do not have to cache everything
881  bool hasSubset = joinInfo->joinFieldNamesSubset();
882  QVector<int> subsetIndices;
883  if ( hasSubset )
884  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
885 
886  // select (no geometry)
887  QgsFeatureRequest request;
889  request.setSubsetOfAttributes( attributes );
890  request.setFilterExpression( subsetString );
891  request.setLimit( 1 );
892  QgsFeatureIterator fi = joinLayer->getFeatures( request );
893 
894  // get first feature
895  QgsFeature fet;
896  if ( fi.nextFeature( fet ) )
897  {
898  int index = indexOffset;
899  QgsAttributes attr = fet.attributes();
900  if ( hasSubset )
901  {
902  for ( int i = 0; i < subsetIndices.count(); ++i )
903  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
904  }
905  else
906  {
907  // use all fields except for the one used for join (has same value as exiting field in target layer)
908  for ( int i = 0; i < attr.count(); ++i )
909  {
910  if ( i == joinField )
911  continue;
912 
913  f.setAttribute( index++, attr.at( i ) );
914  }
915  }
916  }
917  else
918  {
919  // no suitable join feature found, keeping empty (null) attributes
920  }
921 }
922 
923 
924 
925 
927 {
928  QgsFeatureId featureId = mRequest.filterFid();
929 
930  // deleted already?
931  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
932  return false;
933 
934  // has changed geometry?
935  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
936  {
937  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
938  return true;
939  }
940 
941  // added features
942  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
943  {
944  if ( iter->id() == featureId )
945  {
946  useAddedFeature( *iter, f );
947  return true;
948  }
949  }
950 
951  // regular features
953  if ( fi.nextFeature( f ) )
954  {
955  f.setFields( mSource->mFields );
956 
957  if ( mSource->mHasEditBuffer )
959 
960  if ( mHasVirtualAttributes )
962 
963  return true;
964  }
965 
966  return false;
967 }
968 
970 {
971  QgsAttributes attrs = f.attributes();
972 
973  // remove all attributes that will disappear - from higher indices to lower
974  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
975  {
976  attrs.remove( mSource->mDeletedAttributeIds[idx] );
977  }
978 
979  // adjust size to accommodate added attributes
980  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
981 
982  // update changed attributes
983  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
984  {
986  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
987  attrs[it.key()] = it.value();
988  }
989  f.setAttributes( attrs );
990 }
991 
993 {
994  if ( mSource->mChangedGeometries.contains( f.id() ) )
996 }
997 
998 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
999 {
1000  Q_UNUSED( orderBys );
1001  return true;
1002 }
1003 
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:70
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:510
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:155
const Flags & flags() const
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
QMap< int, QgsExpression * > mExpressionFieldInfo
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:517
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Get an iterator for features matching the specified request.
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.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Get an iterator for features matching the specified request.
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:127
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:204
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
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 the 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:61
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:190
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.
bool isGeosValid() const
Checks validity of the geometry using GEOS.
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.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:39
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.
No invalid geometry checking.
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag)
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:112
QgsExpressionFieldBuffer * mExpressionFieldBuffer
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
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)
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:181
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.
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
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.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:503
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:360
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:137
InvalidGeometryCheck invalidGeometryCheck() const
Returns the invalid geometry checking behavior.
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.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
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:37
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
QgsCoordinateReferenceSystem mCrs
void setSourceCrs(const QgsCoordinateReferenceSystem &srcCRS)
Sets source spatial reference system.
QMap< const QgsVectorLayerJoinInfo *, FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
bool nextFeature(QgsFeature &f)
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: qgsattributes.h:57
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:255
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:71
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
std::function< void(const QgsFeature &) > invalidGeometryCallback() const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
void setInterruptionChecker(QgsInterruptionChecker *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped...
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.