QGIS API Documentation  3.6.0-Noosa (5873452)
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 #include "qgsexception.h"
30 
32 {
33  QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
35  mFields = layer->fields();
36  mId = layer->id();
37 
38  // update layer's join caches if necessary
39  if ( layer->mJoinBuffer->containsJoins() )
40  layer->mJoinBuffer->createJoinCaches();
41 
42  mJoinBuffer = layer->mJoinBuffer->clone();
43 
44  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
45  mCrs = layer->crs();
46 
47  mHasEditBuffer = layer->editBuffer();
48  if ( mHasEditBuffer )
49  {
50 #if 0
51  // TODO[MD]: after merge
52  if ( request.filterType() == QgsFeatureRequest::FilterFid )
53  {
54 
55  // only copy relevant parts
56  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
57  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
58 
59  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
60  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
61 
62  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
63  mDeletedFeatureIds.insert( request.filterFid() );
64 
65  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
66  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
67 
68  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
69  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
70  }
71  else
72  {
73 #endif
78  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
80 #if 0
81  }
82 #endif
83  }
84 
85  std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
86  mLayerScope = *layerScope;
87 }
88 
90 {
91  delete mJoinBuffer;
94 }
95 
97 {
98  // return feature iterator that does not own this source
99  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
100 }
101 
103 {
104  return mFields;
105 }
106 
108 {
109  return mCrs;
110 }
111 
113 {
114  return mId;
115 }
116 
117 
120  , mFetchedFid( false )
121 
122 {
124  {
126  }
127  try
128  {
130  }
131  catch ( QgsCsException & )
132  {
133  // can't reproject mFilterRect
134  close();
135  return;
136  }
137  if ( !mFilterRect.isNull() )
138  {
139  // update request to be the unprojected filter rect
141  }
142 
144  {
147 
149  {
150  //ensure that all fields required for filter expressions are prepared
152  attributeIndexes += mRequest.subsetOfAttributes().toSet();
153  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
154  }
155  }
156 
157  prepareFields();
158 
159  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
160 
161  // by default provider's request is the same
163  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
164  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
165  // values
166  if ( mRequest.destinationCrs().isValid() )
167  {
169  }
170 
172  {
173  // prepare list of attributes to match provider fields
174  QSet<int> providerSubset;
176  int nPendingFields = mSource->mFields.count();
177  Q_FOREACH ( int attrIndex, subset )
178  {
179  if ( attrIndex < 0 || attrIndex >= nPendingFields )
180  continue;
181  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
182  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
183  }
184 
185  // This is done in order to be prepared to do fallback order bys
186  // and be sure we have the required columns.
187  // TODO:
188  // It would be nicer to first check if we can compile the order by
189  // and only modify the subset if we cannot.
190  if ( !mProviderRequest.orderBy().isEmpty() )
191  {
192  Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
193  {
194  providerSubset << mSource->mFields.lookupField( attr );
195  }
196  }
197 
198  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
199  }
200 
202  {
203  const bool needsGeom = mProviderRequest.filterExpression()->needsGeometry();
204  Q_FOREACH ( const QString &field, mProviderRequest.filterExpression()->referencedColumns() )
205  {
206  int idx = source->mFields.lookupField( field );
207 
208  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
209  // In this case we disable the expression filter.
210  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
211  {
213  // can't limit at provider side
215  if ( needsGeom )
216  {
217  // have to get geometry from provider in order to evaluate expression on client
219  }
220  break;
221  }
222  }
223  }
224 
225  if ( mSource->mHasEditBuffer )
226  {
228  QgsFeatureIds changedIds;
229  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
230  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
231  {
232  changedIds << attIt.key();
233  }
235 
236  if ( mChangedFeaturesRequest.limit() > 0 )
237  {
238  int providerLimit = mProviderRequest.limit();
239 
240  // features may be deleted in buffer, so increase limit sent to provider
241  providerLimit += mSource->mDeletedFeatureIds.size();
242 
244  {
245  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
246  providerLimit += mSource->mChangedAttributeValues.size();
247  }
248 
250  {
251  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
252  providerLimit += mSource->mChangedGeometries.size();
253  }
254 
255  mProviderRequest.setLimit( providerLimit );
256  mChangedFeaturesRequest.setLimit( providerLimit );
257  }
258  }
259 
260  if ( request.filterType() == QgsFeatureRequest::FilterFid )
261  {
262  mFetchedFid = false;
263  }
264  else // no filter or filter by rect
265  {
266  if ( mSource->mHasEditBuffer )
267  {
269  }
270  else
271  {
273  }
274 
276  }
277 }
278 
279 
281 {
282  qDeleteAll( mExpressionFieldInfo );
283 
284  close();
285 }
286 
287 
288 
290 {
291  f.setValid( false );
292 
293  if ( mClosed )
294  return false;
295 
297  {
298  if ( mFetchedFid )
299  return false;
300  bool res = nextFeatureFid( f );
301  if ( res && postProcessFeature( f ) )
302  {
303  mFetchedFid = true;
304  return res;
305  }
306  else
307  {
308  return false;
309  }
310  }
311 
312  if ( !mFilterRect.isNull() )
313  {
314  if ( fetchNextChangedGeomFeature( f ) )
315  return true;
316 
317  // no more changed geometries
318  }
319 
321  {
323  return true;
324 
325  if ( fetchNextChangedGeomFeature( f ) )
326  return true;
327 
328  // no more changed features
329  }
330 
331  while ( fetchNextAddedFeature( f ) )
332  {
333  return true;
334  }
335  // no more added features
336 
337  if ( mProviderIterator.isClosed() )
338  {
341  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
342  }
343 
344  while ( mProviderIterator.nextFeature( f ) )
345  {
346  if ( mFetchConsidered.contains( f.id() ) )
347  continue;
348 
349  // TODO[MD]: just one resize of attributes
350  f.setFields( mSource->mFields );
351 
352  // update attributes
353  if ( mSource->mHasEditBuffer )
355 
356  if ( mHasVirtualAttributes )
358 
360  {
361  //filtering by expression, and couldn't do it on the provider side
364  {
365  //feature did not match filter
366  continue;
367  }
368  }
369 
370  // update geometry
371  // TODO[MK]: FilterRect check after updating the geometry
374 
375  if ( !postProcessFeature( f ) )
376  continue;
377 
378  return true;
379  }
380  // no more provider features
381 
382  close();
383  return false;
384 }
385 
386 
387 
389 {
390  if ( mClosed )
391  return false;
392 
394  {
395  mFetchedFid = false;
396  }
397  else
398  {
401  }
402 
403  return true;
404 }
405 
407 {
408  if ( mClosed )
409  return false;
410 
412 
413  iteratorClosed();
414 
415  mClosed = true;
416  return true;
417 }
418 
420 {
421  mProviderIterator.setInterruptionChecker( interruptionChecker );
422  mInterruptionChecker = interruptionChecker;
423 }
424 
426 {
427  return mProviderIterator.isValid();
428 }
429 
431 {
432  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
433  {
435 
436  if ( mFetchConsidered.contains( fid ) )
437  // must have changed geometry outside rectangle
438  continue;
439 
441 
442  // can't test for feature acceptance until after calling useAddedFeature
443  // since acceptFeature may rely on virtual fields
444  if ( !mRequest.acceptFeature( f ) )
445  // skip features which are not accepted by the filter
446  continue;
447 
448  if ( !postProcessFeature( f ) )
449  continue;
450 
451  return true;
452  }
453 
455  return false; // no more added features
456 }
457 
458 
460 {
461  // since QgsFeature is implicitly shared, it's more efficient to just copy the
462  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
463  // This helps potentially avoid an unnecessary detach of the feature
464  f = src;
465  f.setValid( true );
466  f.setFields( mSource->mFields );
467 
468  if ( mHasVirtualAttributes )
470 }
471 
472 
473 
475 {
476  // check if changed geometries are in rectangle
478  {
479  QgsFeatureId fid = mFetchChangedGeomIt.key();
480 
481  if ( mFetchConsidered.contains( fid ) )
482  // skip deleted features
483  continue;
484 
485  mFetchConsidered << fid;
486 
487  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
488  // skip changed geometries not in rectangle and don't check again
489  continue;
490 
492 
494  {
497  {
498  continue;
499  }
500  }
501 
502  if ( postProcessFeature( f ) )
503  {
504  // return complete feature
506  return true;
507  }
508  }
509 
510  return false; // no more changed geometries
511 }
512 
514 {
516  {
517  if ( mFetchConsidered.contains( f.id() ) )
518  // skip deleted features and those already handled by the geometry
519  continue;
520 
521  mFetchConsidered << f.id();
522 
524 
525  if ( mHasVirtualAttributes )
527 
529  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
530  {
531  return true;
532  }
533  }
534 
535  return false;
536 }
537 
538 
540 {
541  f.setId( fid );
542  f.setValid( true );
543  f.setFields( mSource->mFields );
544 
547  {
548  f.setGeometry( geom );
549  }
550 
551  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
552  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
553  {
554  // retrieve attributes from provider
555  QgsFeature tmp;
556  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
557  QgsFeatureRequest request;
559  if ( subsetAttrs )
560  {
562  }
564  if ( fi.nextFeature( tmp ) )
565  {
568  f.setAttributes( tmp.attributes() );
569  }
570  }
571 
573 }
574 
575 
576 
578 {
580 
583 }
584 
586 {
587  if ( !mSource->mFields.exists( fieldIdx ) )
588  return;
589 
590  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
591  return;
592 
593  int sourceLayerIndex;
594  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
595  Q_ASSERT( joinInfo );
596 
597  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
598  if ( !joinLayer )
599  return; // invalid join (unresolved reference to layer)
600 
601  if ( !mFetchJoinInfo.contains( joinInfo ) )
602  {
603  FetchJoinInfo info;
604  info.joinInfo = joinInfo;
605  info.joinLayer = joinLayer;
608  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
609 
610  // for joined fields, we always need to request the targetField from the provider too
611  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
612  mFieldsToPrepare << info.targetField;
613 
616 
617  mFetchJoinInfo.insert( joinInfo, info );
618  }
619 
620  // store field source index - we'll need it when fetching from provider
621  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
622 }
623 
625 {
626  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
627 
628  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
629  QgsExpression *exp = new QgsExpression( exps[oi].cachedExpression );
630 
631  QgsDistanceArea da;
633  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
634  exp->setGeomCalculator( &da );
635  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
636  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
637 
638  exp->prepare( mExpressionContext.get() );
639  Q_FOREACH ( const QString &col, exp->referencedColumns() )
640  {
641  if ( mSource->fields().lookupField( col ) == fieldIdx )
642  {
643  // circular reference - expression depends on column itself
644  delete exp;
645  return;
646  }
647  }
648  mExpressionFieldInfo.insert( fieldIdx, exp );
649 
650  Q_FOREACH ( const QString &col, exp->referencedColumns() )
651  {
652  int dependentFieldIdx = mSource->mFields.lookupField( col );
654  {
655  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
656  }
657  // also need to fetch this dependent field
658  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
659  mFieldsToPrepare << dependentFieldIdx;
660  }
661 
662  if ( exp->needsGeometry() )
663  {
664  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
665  }
666 }
667 
669 {
670  mPreparedFields.clear();
671  mFieldsToPrepare.clear();
672  mFetchJoinInfo.clear();
673  mOrderedJoinInfoList.clear();
674 
675  mExpressionContext.reset( new QgsExpressionContext() );
676  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
677  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
678  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
679 
681 
682  while ( !mFieldsToPrepare.isEmpty() )
683  {
684  int fieldIdx = mFieldsToPrepare.takeFirst();
685  if ( mPreparedFields.contains( fieldIdx ) )
686  continue;
687 
688  mPreparedFields << fieldIdx;
689  prepareField( fieldIdx );
690  }
691 
692  //sort joins by dependency
693  if ( !mFetchJoinInfo.empty() )
694  {
695  createOrderedJoinList();
696  }
697 }
698 
699 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
700 {
701  mOrderedJoinInfoList = mFetchJoinInfo.values();
702  if ( mOrderedJoinInfoList.size() < 2 )
703  {
704  return;
705  }
706 
707  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
708 
709  //add all provider fields without joins as resolved fields
710  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
711  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
712  {
713  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
714  {
715  resolvedFields.insert( *prepFieldIt );
716  }
717  }
718 
719  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
720 
721  //some join combinations might not have a resolution at all
722  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
723  int currentIteration = 0;
724 
725  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
726  {
727  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
728  {
729  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
730  mOrderedJoinInfoList.removeAt( i );
731  --i;
732  }
733  else
734  {
735  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
736  int joinField = mOrderedJoinInfoList.at( i ).joinField;
737 
738  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
739  for ( int n = 0; n < attributes.size(); n++ )
740  {
741  if ( n != joinField )
742  {
743  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
744  }
745  }
746  }
747 
748  ++currentIteration;
749  if ( currentIteration >= maxIterations )
750  {
751  break;
752  }
753  }
754 }
755 
756 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
757 {
758  bool result = checkGeometryValidity( feature );
759  if ( result )
761  return result;
762 }
763 
764 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
765 {
766  if ( !feature.hasGeometry() )
767  return true;
768 
769  switch ( mRequest.invalidGeometryCheck() )
770  {
772  return true;
773 
775  {
776  if ( !feature.geometry().isGeosValid() )
777  {
778  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
780  {
781  mRequest.invalidGeometryCallback()( feature );
782  }
783  return false;
784  }
785  break;
786  }
787 
789  if ( !feature.geometry().isGeosValid() )
790  {
791  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
792  close();
794  {
795  mRequest.invalidGeometryCallback()( feature );
796  }
797  return false;
798  }
799  break;
800  }
801 
802  return true;
803 }
804 
806 {
807  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
808  {
810  prepareExpression( fieldIdx );
811  break;
812 
815  {
816  prepareJoin( fieldIdx );
817  }
818  break;
819 
823  break;
824  }
825 }
826 
828 {
829  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
830  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
831  {
832  QVariant targetFieldValue = f.attribute( joinIt->targetField );
833  if ( !targetFieldValue.isValid() )
834  continue;
835 
836  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
837  if ( memoryCache.isEmpty() )
838  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
839  else
840  joinIt->addJoinedAttributesCached( f, targetFieldValue );
841  }
842 }
843 
845 {
846  // make sure we have space for newly added attributes
847  QgsAttributes attr = f.attributes();
848  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
849  f.setAttributes( attr );
850 
851  // possible TODO - handle combinations of expression -> join -> expression -> join?
852  // but for now, write that off as too complex and an unlikely rare, unsupported use case
853 
854  QList< int > fetchedVirtualAttributes;
855  //first, check through joins for any virtual fields we need
856  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
857  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
858  {
859  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
860  {
861  // have to calculate expression field before we can handle this join
862  addExpressionAttribute( f, joinIt->targetField );
863  fetchedVirtualAttributes << joinIt->targetField;
864  }
865  }
866 
867  if ( !mFetchJoinInfo.isEmpty() )
868  addJoinedAttributes( f );
869 
870  // add remaining expression fields
871  if ( !mExpressionFieldInfo.isEmpty() )
872  {
873  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
874  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
875  {
876  if ( fetchedVirtualAttributes.contains( it.key() ) )
877  continue;
878 
879  addExpressionAttribute( f, it.key() );
880  }
881  }
882 }
883 
885 {
886  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
887  if ( exp )
888  {
889  mExpressionContext->setFeature( f );
890  QVariant val = exp->evaluate( mExpressionContext.get() );
891  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
892  f.setAttribute( attrIndex, val );
893  }
894  else
895  {
896  f.setAttribute( attrIndex, QVariant() );
897  }
898 }
899 
901 {
902  Q_UNUSED( simplifyMethod );
903  return false;
904 }
905 
906 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
907 {
908  Q_UNUSED( methodType );
909  return false;
910 }
911 
912 
914 {
915  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
916  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
917  if ( it == memoryCache.constEnd() )
918  return; // joined value not found -> leaving the attributes empty (null)
919 
920  int index = indexOffset;
921 
922  const QgsAttributes &featureAttributes = it.value();
923  for ( int i = 0; i < featureAttributes.count(); ++i )
924  {
925  f.setAttribute( index++, featureAttributes.at( i ) );
926  }
927 }
928 
929 
930 
932 {
933  // no memory cache, query the joined values by setting substring
934  QString subsetString;
935 
936  QString joinFieldName = joinInfo->joinFieldName();
937 
938  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
939 
940  if ( joinValue.isNull() )
941  {
942  subsetString += QLatin1String( " IS NULL" );
943  }
944  else
945  {
946  QString v = joinValue.toString();
947  switch ( joinValue.type() )
948  {
949  case QVariant::Int:
950  case QVariant::LongLong:
951  case QVariant::Double:
952  break;
953 
954  default:
955  case QVariant::String:
956  v.replace( '\'', QLatin1String( "''" ) );
957  v.prepend( '\'' ).append( '\'' );
958  break;
959  }
960  subsetString += '=' + v;
961  }
962 
963  // maybe user requested just a subset of layer's attributes
964  // so we do not have to cache everything
965  QVector<int> subsetIndices;
966  if ( joinInfo->hasSubset() )
967  {
968  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
969  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
970  }
971 
972  // select (no geometry)
973  QgsFeatureRequest request;
975  request.setSubsetOfAttributes( attributes );
976  request.setFilterExpression( subsetString );
977  request.setLimit( 1 );
978  QgsFeatureIterator fi = joinLayer->getFeatures( request );
979 
980  // get first feature
981  QgsFeature fet;
982  if ( fi.nextFeature( fet ) )
983  {
984  int index = indexOffset;
985  QgsAttributes attr = fet.attributes();
986  if ( joinInfo->hasSubset() )
987  {
988  for ( int i = 0; i < subsetIndices.count(); ++i )
989  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
990  }
991  else
992  {
993  // use all fields except for the one used for join (has same value as exiting field in target layer)
994  for ( int i = 0; i < attr.count(); ++i )
995  {
996  if ( i == joinField )
997  continue;
998 
999  f.setAttribute( index++, attr.at( i ) );
1000  }
1001  }
1002  }
1003  else
1004  {
1005  // no suitable join feature found, keeping empty (null) attributes
1006  }
1007 }
1008 
1009 
1010 
1011 
1013 {
1014  QgsFeatureId featureId = mRequest.filterFid();
1015 
1016  // deleted already?
1017  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1018  return false;
1019 
1020  // has changed geometry?
1021  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1022  {
1023  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1024  return true;
1025  }
1026 
1027  // added features
1028  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1029  {
1030  if ( iter->id() == featureId )
1031  {
1032  useAddedFeature( *iter, f );
1033  return true;
1034  }
1035  }
1036 
1037  // regular features
1039  if ( fi.nextFeature( f ) )
1040  {
1041  f.setFields( mSource->mFields );
1042 
1043  if ( mSource->mHasEditBuffer )
1045 
1046  if ( mHasVirtualAttributes )
1047  addVirtualAttributes( f );
1048 
1049  return true;
1050  }
1051 
1052  return false;
1053 }
1054 
1056 {
1057  QgsAttributes attrs = f.attributes();
1058 
1059  // remove all attributes that will disappear - from higher indices to lower
1060  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1061  {
1062  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1063  }
1064 
1065  // adjust size to accommodate added attributes
1066  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1067 
1068  // update changed attributes
1069  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1070  {
1072  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1073  attrs[it.key()] = it.value();
1074  }
1075  f.setAttributes( attrs );
1076 }
1077 
1079 {
1080  if ( mSource->mChangedGeometries.contains( f.id() ) )
1082 }
1083 
1084 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1085 {
1086  Q_UNUSED( orderBys );
1087  return true;
1088 }
1089 
1090 
1091 //
1092 // QgsVectorLayerSelectedFeatureSource
1093 //
1094 
1096  : mSource( layer )
1097  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1098  , mWkbType( layer->wkbType() )
1099  , mName( layer->name() )
1100  , mLayer( layer )
1101 {}
1102 
1104 {
1105  QgsFeatureRequest req( request );
1106 
1107  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1108  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1109  // allows providers to optimise the request and avoid requesting features we don't need
1110  // note that we can't do this for some request types - e.g. expression based requests, so
1111  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1112  // do ALL the filtering
1113  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1114  {
1115  req.setFilterFids( mSelectedFeatureIds );
1116  }
1117  else if ( !req.filterFids().isEmpty() )
1118  {
1119  QgsFeatureIds reqIds = mSelectedFeatureIds;
1120  reqIds.intersect( req.filterFids() );
1121  req.setFilterFids( reqIds );
1122  }
1123 
1124  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1125 }
1126 
1128 {
1129  return mSource.crs();
1130 }
1131 
1133 {
1134  return mSource.fields();
1135 }
1136 
1138 {
1139  return mWkbType;
1140 }
1141 
1143 {
1144  return mSelectedFeatureIds.count();
1145 }
1146 
1148 {
1149  return mName;
1150 }
1151 
1153 {
1154  if ( mLayer )
1155  return mLayer->createExpressionContextScope();
1156  else
1157  return nullptr;
1158 }
1159 
1160 //
1161 // QgsVectorLayerSelectedFeatureIterator
1162 //
1163 
1165 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1166  : QgsAbstractFeatureIterator( request )
1167  , mSelectedFeatureIds( selectedFeatureIds )
1168 {
1169  QgsFeatureRequest sourceRequest = request;
1170  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1171  {
1172  // we can't pass the request limit to the provider here - otherwise the provider will
1173  // limit the number of returned features and may only return a bunch of matching features
1174  // which AREN'T in the selected feature set
1175  sourceRequest.setLimit( -1 );
1176  }
1177  mIterator = source.getFeatures( sourceRequest );
1178 }
1179 
1180 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1181 {
1182  return mIterator.rewind();
1183 }
1184 
1185 bool QgsVectorLayerSelectedFeatureIterator::close()
1186 {
1187  return mIterator.close();
1188 }
1189 
1190 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1191 {
1192  while ( mIterator.nextFeature( f ) )
1193  {
1194  if ( mSelectedFeatureIds.contains( f.id() ) )
1195  return true;
1196  }
1197  return false;
1198 }
1199 
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
QList< QgsExpressionFieldBuffer::ExpressionField > expressions() const
QgsAbstractFeatureSource * mProviderFeatureSource
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature&#39;s geometries.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
QgsFeatureId id
Definition: qgsfeature.h:64
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:566
const QgsVectorLayerJoinInfo * joinInfo
Canonical source of information about the join.
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.
void geometryToDestinationCrs(QgsFeature &feature, const QgsCoordinateTransform &transform) const
Transforms feature&#39;s geometry according to the specified coordinate transform.
QgsCoordinateReferenceSystem sourceCrs() const override
Returns the coordinate reference system for features in the source.
Filter using feature ID.
QgsVectorLayerJoinBuffer * mJoinBuffer
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system for features retrieved from this source.
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:50
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
void setInterruptionChecker(QgsFeedback *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped...
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:162
QString sourceName() const override
Returns a friendly display name for the source.
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
QgsRectangle filterRectToSourceCrs(const QgsCoordinateTransform &transform) const SIP_THROW(QgsCsException)
Returns a rectangle representing the original request&#39;s QgsFeatureRequest::filterRect().
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:51
bool exists(int i) const
Returns if a field index is valid.
Definition: qgsfields.cpp:153
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request)
QgsVectorLayerSelectedFeatureSource(QgsVectorLayer *layer)
Constructor for QgsVectorLayerSelectedFeatureSource, for selected features from the specified layer...
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Gets an iterator for features matching the specified request.
QgsFeatureId filterFid() const
Gets the feature ID that should be fetched.
QVariant evaluate()
Evaluate the feature and return the result.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature&#39;s geometries, or an invalid QgsCoordi...
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Gets an iterator for features matching the specified request.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:281
FilterType filterType() const
Returns the filter type which is currently set on this request.
Container of fields for a vector layer.
Definition: qgsfields.h:42
const QgsFeatureIds & filterFids() const
Gets feature IDs that should be fetched.
QSet< int > referencedAttributeIndexes(const QgsFields &fields) const
Returns a list of field name indexes obtained from the provided fields.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
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:211
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:49
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
bool mClosed
Sets 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
Gets 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:55
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed. ...
const QgsAttributeList & attributeIndexes
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
QgsVectorLayer * joinLayer
Resolved pointer to the joined layer.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
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:48
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
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
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
virtual QgsAbstractFeatureSource * featureSource() const =0
Returns feature source object that can be used for querying provider&#39;s data.
Base class for feedback objects to be used for cancelation of something running in a worker thread...
Definition: qgsfeedback.h:44
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets 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.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
void iteratorClosed()
to be called by from subclass in close()
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
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...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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:351
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source...
QgsFeatureRequest & disableFilter()
Disables filter conditions.
Internal feature iterator to be implemented within data providers.
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...
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
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Defines left outer join from our vector layer to some other vector layer.
void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped...
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
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.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsWkbTypes::Type wkbType() const override
Returns the geometry type for features returned by this source.
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
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsExpressionFieldBuffer * mExpressionFieldBuffer
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QgsAttributeList subsetOfAttributes() const
Returns 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.
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:96
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:188
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
long featureCount() const override
Returns the number of features contained in the source, or -1 if the feature count is unknown...
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.
No filter is applied.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets feature IDs that should be fetched.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:557
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
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:430
QMap< const QgsVectorLayerJoinInfo *, QgsVectorLayerFeatureIterator::FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
This class represents a coordinate reference system (CRS).
bool close() override
end of iterating: free the resources / lock
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Returns a vector of indices for use in join based on field names from the layer.
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()).
Definition: qgsrectangle.h:436
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Class for doing transforms between two map coordinate systems.
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
QgsGeometry geometry
Definition: qgsfeature.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be null.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
QString id() const
Returns the layer id of the source layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
QgsChangedAttributesMap mChangedAttributeValues
OrderBy orderBy() const
Returns 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.
bool isValid() const override
Returns if this iterator is valid.
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:52
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
QgsCoordinateTransformContext transformContext() const
Returns the transform context, for use when a destinationCrs() has been set and reprojection is requi...
virtual bool isValid() const
Will return if this iterator is valid.
bool isClosed() const
find out whether the iterator is still valid or closed already
QgsVectorLayerFeatureSource(const QgsVectorLayer *layer)
Constructor for QgsVectorLayerFeatureSource.
QStringList * joinFieldNamesSubset() const
Gets subset of fields to be used from joined layer.
QgsAttributes attributes
Definition: qgsfeature.h:65
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()...
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:71
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)
Sets flags that affect how features will be fetched.
Helper template that cares of two things: 1.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.