QGIS API Documentation  3.4.3-Madeira (2f64a3c)
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"
29 
31 {
32  QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
34  mFields = layer->fields();
35  mId = layer->id();
36 
37  // update layer's join caches if necessary
38  if ( layer->mJoinBuffer->containsJoins() )
39  layer->mJoinBuffer->createJoinCaches();
40 
41  mJoinBuffer = layer->mJoinBuffer->clone();
42 
43  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
44  mCrs = layer->crs();
45 
46  mHasEditBuffer = layer->editBuffer();
47  if ( mHasEditBuffer )
48  {
49 #if 0
50  // TODO[MD]: after merge
51  if ( request.filterType() == QgsFeatureRequest::FilterFid )
52  {
53 
54  // only copy relevant parts
55  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
56  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
57 
58  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
59  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
60 
61  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
62  mDeletedFeatureIds.insert( request.filterFid() );
63 
64  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
65  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
66 
67  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
68  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
69  }
70  else
71  {
72 #endif
77  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
79 #if 0
80  }
81 #endif
82  }
83 
84  std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
85  mLayerScope = *layerScope;
86 }
87 
89 {
90  delete mJoinBuffer;
93 }
94 
96 {
97  // return feature iterator that does not own this source
98  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
99 }
100 
102 {
103  return mFields;
104 }
105 
107 {
108  return mCrs;
109 }
110 
112 {
113  return mId;
114 }
115 
116 
119  , mFetchedFid( false )
120 
121 {
123  {
125  }
126  try
127  {
129  }
130  catch ( QgsCsException & )
131  {
132  // can't reproject mFilterRect
133  close();
134  return;
135  }
136  if ( !mFilterRect.isNull() )
137  {
138  // update request to be the unprojected filter rect
140  }
141 
143  {
146 
148  {
149  //ensure that all fields required for filter expressions are prepared
151  attributeIndexes += mRequest.subsetOfAttributes().toSet();
152  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
153  }
154  }
155 
156  prepareFields();
157 
158  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
159 
160  // by default provider's request is the same
162  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
163  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
164  // values
165  if ( mRequest.destinationCrs().isValid() )
166  {
168  }
169 
171  {
172  // prepare list of attributes to match provider fields
173  QSet<int> providerSubset;
175  int nPendingFields = mSource->mFields.count();
176  Q_FOREACH ( int attrIndex, subset )
177  {
178  if ( attrIndex < 0 || attrIndex >= nPendingFields )
179  continue;
180  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
181  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
182  }
183 
184  // This is done in order to be prepared to do fallback order bys
185  // and be sure we have the required columns.
186  // TODO:
187  // It would be nicer to first check if we can compile the order by
188  // and only modify the subset if we cannot.
189  if ( !mProviderRequest.orderBy().isEmpty() )
190  {
191  Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
192  {
193  providerSubset << mSource->mFields.lookupField( attr );
194  }
195  }
196 
197  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
198  }
199 
201  {
202  Q_FOREACH ( const QString &field, mProviderRequest.filterExpression()->referencedColumns() )
203  {
204  int idx = source->mFields.lookupField( field );
205 
206  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
207  // In this case we disable the expression filter.
208  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
209  {
211  // can't limit at provider side
213  }
214  }
215  }
216 
217  if ( mSource->mHasEditBuffer )
218  {
220  QgsFeatureIds changedIds;
221  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
222  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
223  {
224  changedIds << attIt.key();
225  }
227 
228  if ( mChangedFeaturesRequest.limit() > 0 )
229  {
230  int providerLimit = mProviderRequest.limit();
231 
232  // features may be deleted in buffer, so increase limit sent to provider
233  providerLimit += mSource->mDeletedFeatureIds.size();
234 
236  {
237  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
238  providerLimit += mSource->mChangedAttributeValues.size();
239  }
240 
242  {
243  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
244  providerLimit += mSource->mChangedGeometries.size();
245  }
246 
247  mProviderRequest.setLimit( providerLimit );
248  mChangedFeaturesRequest.setLimit( providerLimit );
249  }
250  }
251 
252  if ( request.filterType() == QgsFeatureRequest::FilterFid )
253  {
254  mFetchedFid = false;
255  }
256  else // no filter or filter by rect
257  {
258  if ( mSource->mHasEditBuffer )
259  {
261  }
262  else
263  {
265  }
266 
268  }
269 }
270 
271 
273 {
274  qDeleteAll( mExpressionFieldInfo );
275 
276  close();
277 }
278 
279 
280 
282 {
283  f.setValid( false );
284 
285  if ( mClosed )
286  return false;
287 
289  {
290  if ( mFetchedFid )
291  return false;
292  bool res = nextFeatureFid( f );
293  if ( res && postProcessFeature( f ) )
294  {
295  mFetchedFid = true;
296  return res;
297  }
298  else
299  {
300  return false;
301  }
302  }
303 
304  if ( !mFilterRect.isNull() )
305  {
306  if ( fetchNextChangedGeomFeature( f ) )
307  return true;
308 
309  // no more changed geometries
310  }
311 
313  {
315  return true;
316 
317  if ( fetchNextChangedGeomFeature( f ) )
318  return true;
319 
320  // no more changed features
321  }
322 
323  while ( fetchNextAddedFeature( f ) )
324  {
325  return true;
326  }
327  // no more added features
328 
329  if ( mProviderIterator.isClosed() )
330  {
333  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
334  }
335 
336  while ( mProviderIterator.nextFeature( f ) )
337  {
338  if ( mFetchConsidered.contains( f.id() ) )
339  continue;
340 
341  // TODO[MD]: just one resize of attributes
342  f.setFields( mSource->mFields );
343 
344  // update attributes
345  if ( mSource->mHasEditBuffer )
347 
348  if ( mHasVirtualAttributes )
350 
352  {
353  //filtering by expression, and couldn't do it on the provider side
356  {
357  //feature did not match filter
358  continue;
359  }
360  }
361 
362  // update geometry
363  // TODO[MK]: FilterRect check after updating the geometry
366 
367  if ( !postProcessFeature( f ) )
368  continue;
369 
370  return true;
371  }
372  // no more provider features
373 
374  close();
375  return false;
376 }
377 
378 
379 
381 {
382  if ( mClosed )
383  return false;
384 
386  {
387  mFetchedFid = false;
388  }
389  else
390  {
393  }
394 
395  return true;
396 }
397 
399 {
400  if ( mClosed )
401  return false;
402 
404 
405  iteratorClosed();
406 
407  mClosed = true;
408  return true;
409 }
410 
412 {
413  mProviderIterator.setInterruptionChecker( interruptionChecker );
414  mInterruptionChecker = interruptionChecker;
415 }
416 
418 {
419  return mProviderIterator.isValid();
420 }
421 
423 {
424  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
425  {
427 
428  if ( mFetchConsidered.contains( fid ) )
429  // must have changed geometry outside rectangle
430  continue;
431 
433 
434  // can't test for feature acceptance until after calling useAddedFeature
435  // since acceptFeature may rely on virtual fields
436  if ( !mRequest.acceptFeature( f ) )
437  // skip features which are not accepted by the filter
438  continue;
439 
440  if ( !postProcessFeature( f ) )
441  continue;
442 
443  return true;
444  }
445 
447  return false; // no more added features
448 }
449 
450 
452 {
453  // since QgsFeature is implicitly shared, it's more efficient to just copy the
454  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
455  // This helps potentially avoid an unnecessary detach of the feature
456  f = src;
457  f.setValid( true );
458  f.setFields( mSource->mFields );
459 
460  if ( mHasVirtualAttributes )
462 }
463 
464 
465 
467 {
468  // check if changed geometries are in rectangle
470  {
471  QgsFeatureId fid = mFetchChangedGeomIt.key();
472 
473  if ( mFetchConsidered.contains( fid ) )
474  // skip deleted features
475  continue;
476 
477  mFetchConsidered << fid;
478 
479  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
480  // skip changed geometries not in rectangle and don't check again
481  continue;
482 
484 
486  {
489  {
490  continue;
491  }
492  }
493 
494  if ( postProcessFeature( f ) )
495  {
496  // return complete feature
498  return true;
499  }
500  }
501 
502  return false; // no more changed geometries
503 }
504 
506 {
508  {
509  if ( mFetchConsidered.contains( f.id() ) )
510  // skip deleted features and those already handled by the geometry
511  continue;
512 
513  mFetchConsidered << f.id();
514 
516 
517  if ( mHasVirtualAttributes )
519 
521  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
522  {
523  return true;
524  }
525  }
526 
527  return false;
528 }
529 
530 
532 {
533  f.setId( fid );
534  f.setValid( true );
535  f.setFields( mSource->mFields );
536 
539  {
540  f.setGeometry( geom );
541  }
542 
543  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
544  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
545  {
546  // retrieve attributes from provider
547  QgsFeature tmp;
548  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
549  QgsFeatureRequest request;
551  if ( subsetAttrs )
552  {
554  }
556  if ( fi.nextFeature( tmp ) )
557  {
560  f.setAttributes( tmp.attributes() );
561  }
562  }
563 
565 }
566 
567 
568 
570 {
572 
575 }
576 
578 {
579  if ( !mSource->mFields.exists( fieldIdx ) )
580  return;
581 
582  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
583  return;
584 
585  int sourceLayerIndex;
586  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
587  Q_ASSERT( joinInfo );
588 
589  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
590  if ( !joinLayer )
591  return; // invalid join (unresolved reference to layer)
592 
593  if ( !mFetchJoinInfo.contains( joinInfo ) )
594  {
595  FetchJoinInfo info;
596  info.joinInfo = joinInfo;
597  info.joinLayer = joinLayer;
600  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
601 
602  // for joined fields, we always need to request the targetField from the provider too
603  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
604  mFieldsToPrepare << info.targetField;
605 
608 
609  mFetchJoinInfo.insert( joinInfo, info );
610  }
611 
612  // store field source index - we'll need it when fetching from provider
613  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
614 }
615 
617 {
618  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
619 
620  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
621  QgsExpression *exp = new QgsExpression( exps[oi].cachedExpression );
622 
623  QgsDistanceArea da;
625  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
626  exp->setGeomCalculator( &da );
627  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
628  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
629 
630  exp->prepare( mExpressionContext.get() );
631  Q_FOREACH ( const QString &col, exp->referencedColumns() )
632  {
633  if ( mSource->fields().lookupField( col ) == fieldIdx )
634  {
635  // circular reference - expression depends on column itself
636  delete exp;
637  return;
638  }
639  }
640  mExpressionFieldInfo.insert( fieldIdx, exp );
641 
642  Q_FOREACH ( const QString &col, exp->referencedColumns() )
643  {
644  int dependentFieldIdx = mSource->mFields.lookupField( col );
646  {
647  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
648  }
649  // also need to fetch this dependent field
650  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
651  mFieldsToPrepare << dependentFieldIdx;
652  }
653 
654  if ( exp->needsGeometry() )
655  {
656  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
657  }
658 }
659 
661 {
662  mPreparedFields.clear();
663  mFieldsToPrepare.clear();
664  mFetchJoinInfo.clear();
665  mOrderedJoinInfoList.clear();
666 
667  mExpressionContext.reset( new QgsExpressionContext() );
668  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
669  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
670  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
671 
673 
674  while ( !mFieldsToPrepare.isEmpty() )
675  {
676  int fieldIdx = mFieldsToPrepare.takeFirst();
677  if ( mPreparedFields.contains( fieldIdx ) )
678  continue;
679 
680  mPreparedFields << fieldIdx;
681  prepareField( fieldIdx );
682  }
683 
684  //sort joins by dependency
685  if ( !mFetchJoinInfo.empty() )
686  {
687  createOrderedJoinList();
688  }
689 }
690 
691 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
692 {
693  mOrderedJoinInfoList = mFetchJoinInfo.values();
694  if ( mOrderedJoinInfoList.size() < 2 )
695  {
696  return;
697  }
698 
699  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
700 
701  //add all provider fields without joins as resolved fields
702  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
703  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
704  {
705  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
706  {
707  resolvedFields.insert( *prepFieldIt );
708  }
709  }
710 
711  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
712 
713  //some join combinations might not have a resolution at all
714  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
715  int currentIteration = 0;
716 
717  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
718  {
719  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
720  {
721  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
722  mOrderedJoinInfoList.removeAt( i );
723  --i;
724  }
725  else
726  {
727  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
728  int joinField = mOrderedJoinInfoList.at( i ).joinField;
729 
730  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
731  for ( int n = 0; n < attributes.size(); n++ )
732  {
733  if ( n != joinField )
734  {
735  resolvedFields.insert( joinField < n ? n + offset - 1 : n + offset );
736  }
737  }
738  }
739 
740  ++currentIteration;
741  if ( currentIteration >= maxIterations )
742  {
743  break;
744  }
745  }
746 }
747 
748 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
749 {
750  bool result = checkGeometryValidity( feature );
751  if ( result )
753  return result;
754 }
755 
756 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
757 {
758  if ( !feature.hasGeometry() )
759  return true;
760 
761  switch ( mRequest.invalidGeometryCheck() )
762  {
764  return true;
765 
767  {
768  if ( !feature.geometry().isGeosValid() )
769  {
770  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
772  {
773  mRequest.invalidGeometryCallback()( feature );
774  }
775  return false;
776  }
777  break;
778  }
779 
781  if ( !feature.geometry().isGeosValid() )
782  {
783  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), Qgis::Critical );
784  close();
786  {
787  mRequest.invalidGeometryCallback()( feature );
788  }
789  return false;
790  }
791  break;
792  }
793 
794  return true;
795 }
796 
798 {
799  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
800  {
802  prepareExpression( fieldIdx );
803  break;
804 
807  {
808  prepareJoin( fieldIdx );
809  }
810  break;
811 
815  break;
816  }
817 }
818 
820 {
821  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
822  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
823  {
824  QVariant targetFieldValue = f.attribute( joinIt->targetField );
825  if ( !targetFieldValue.isValid() )
826  continue;
827 
828  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
829  if ( memoryCache.isEmpty() )
830  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
831  else
832  joinIt->addJoinedAttributesCached( f, targetFieldValue );
833  }
834 }
835 
837 {
838  // make sure we have space for newly added attributes
839  QgsAttributes attr = f.attributes();
840  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
841  f.setAttributes( attr );
842 
843  // possible TODO - handle combinations of expression -> join -> expression -> join?
844  // but for now, write that off as too complex and an unlikely rare, unsupported use case
845 
846  QList< int > fetchedVirtualAttributes;
847  //first, check through joins for any virtual fields we need
848  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
849  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
850  {
851  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
852  {
853  // have to calculate expression field before we can handle this join
854  addExpressionAttribute( f, joinIt->targetField );
855  fetchedVirtualAttributes << joinIt->targetField;
856  }
857  }
858 
859  if ( !mFetchJoinInfo.isEmpty() )
860  addJoinedAttributes( f );
861 
862  // add remaining expression fields
863  if ( !mExpressionFieldInfo.isEmpty() )
864  {
865  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
866  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
867  {
868  if ( fetchedVirtualAttributes.contains( it.key() ) )
869  continue;
870 
871  addExpressionAttribute( f, it.key() );
872  }
873  }
874 }
875 
877 {
878  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
879  if ( exp )
880  {
881  mExpressionContext->setFeature( f );
882  QVariant val = exp->evaluate( mExpressionContext.get() );
883  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
884  f.setAttribute( attrIndex, val );
885  }
886  else
887  {
888  f.setAttribute( attrIndex, QVariant() );
889  }
890 }
891 
893 {
894  Q_UNUSED( simplifyMethod );
895  return false;
896 }
897 
898 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
899 {
900  Q_UNUSED( methodType );
901  return false;
902 }
903 
904 
906 {
907  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
908  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
909  if ( it == memoryCache.constEnd() )
910  return; // joined value not found -> leaving the attributes empty (null)
911 
912  int index = indexOffset;
913 
914  const QgsAttributes &featureAttributes = it.value();
915  for ( int i = 0; i < featureAttributes.count(); ++i )
916  {
917  f.setAttribute( index++, featureAttributes.at( i ) );
918  }
919 }
920 
921 
922 
924 {
925  // no memory cache, query the joined values by setting substring
926  QString subsetString;
927 
928  QString joinFieldName = joinInfo->joinFieldName();
929 
930  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
931 
932  if ( joinValue.isNull() )
933  {
934  subsetString += QLatin1String( " IS NULL" );
935  }
936  else
937  {
938  QString v = joinValue.toString();
939  switch ( joinValue.type() )
940  {
941  case QVariant::Int:
942  case QVariant::LongLong:
943  case QVariant::Double:
944  break;
945 
946  default:
947  case QVariant::String:
948  v.replace( '\'', QLatin1String( "''" ) );
949  v.prepend( '\'' ).append( '\'' );
950  break;
951  }
952  subsetString += '=' + v;
953  }
954 
955  // maybe user requested just a subset of layer's attributes
956  // so we do not have to cache everything
957  QVector<int> subsetIndices;
958  if ( joinInfo->hasSubset() )
959  {
960  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
961  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
962  }
963 
964  // select (no geometry)
965  QgsFeatureRequest request;
967  request.setSubsetOfAttributes( attributes );
968  request.setFilterExpression( subsetString );
969  request.setLimit( 1 );
970  QgsFeatureIterator fi = joinLayer->getFeatures( request );
971 
972  // get first feature
973  QgsFeature fet;
974  if ( fi.nextFeature( fet ) )
975  {
976  int index = indexOffset;
977  QgsAttributes attr = fet.attributes();
978  if ( joinInfo->hasSubset() )
979  {
980  for ( int i = 0; i < subsetIndices.count(); ++i )
981  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
982  }
983  else
984  {
985  // use all fields except for the one used for join (has same value as exiting field in target layer)
986  for ( int i = 0; i < attr.count(); ++i )
987  {
988  if ( i == joinField )
989  continue;
990 
991  f.setAttribute( index++, attr.at( i ) );
992  }
993  }
994  }
995  else
996  {
997  // no suitable join feature found, keeping empty (null) attributes
998  }
999 }
1000 
1001 
1002 
1003 
1005 {
1006  QgsFeatureId featureId = mRequest.filterFid();
1007 
1008  // deleted already?
1009  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1010  return false;
1011 
1012  // has changed geometry?
1013  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1014  {
1015  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1016  return true;
1017  }
1018 
1019  // added features
1020  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1021  {
1022  if ( iter->id() == featureId )
1023  {
1024  useAddedFeature( *iter, f );
1025  return true;
1026  }
1027  }
1028 
1029  // regular features
1031  if ( fi.nextFeature( f ) )
1032  {
1033  f.setFields( mSource->mFields );
1034 
1035  if ( mSource->mHasEditBuffer )
1037 
1038  if ( mHasVirtualAttributes )
1039  addVirtualAttributes( f );
1040 
1041  return true;
1042  }
1043 
1044  return false;
1045 }
1046 
1048 {
1049  QgsAttributes attrs = f.attributes();
1050 
1051  // remove all attributes that will disappear - from higher indices to lower
1052  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1053  {
1054  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1055  }
1056 
1057  // adjust size to accommodate added attributes
1058  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1059 
1060  // update changed attributes
1061  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1062  {
1064  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1065  attrs[it.key()] = it.value();
1066  }
1067  f.setAttributes( attrs );
1068 }
1069 
1071 {
1072  if ( mSource->mChangedGeometries.contains( f.id() ) )
1074 }
1075 
1076 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1077 {
1078  Q_UNUSED( orderBys );
1079  return true;
1080 }
1081 
1082 
1083 //
1084 // QgsVectorLayerSelectedFeatureSource
1085 //
1086 
1088  : mSource( layer )
1089  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1090  , mWkbType( layer->wkbType() )
1091  , mName( layer->name() )
1092  , mLayer( layer )
1093 {}
1094 
1096 {
1097  QgsFeatureRequest req( request );
1098 
1099  // while QgsVectorLayerSelectedFeatureIterator will reject any features not in mSelectedFeatureIds,
1100  // we still tweak the feature request to only request selected feature ids wherever we can -- this
1101  // allows providers to optimise the request and avoid requesting features we don't need
1102  // note that we can't do this for some request types - e.g. expression based requests, so
1103  // in that case we just pass the request on to the provider and let QgsVectorLayerSelectedFeatureIterator
1104  // do ALL the filtering
1105  if ( req.filterFids().isEmpty() && req.filterType() == QgsFeatureRequest::FilterNone )
1106  {
1107  req.setFilterFids( mSelectedFeatureIds );
1108  }
1109  else if ( !req.filterFids().isEmpty() )
1110  {
1111  QgsFeatureIds reqIds = mSelectedFeatureIds;
1112  reqIds.intersect( req.filterFids() );
1113  req.setFilterFids( reqIds );
1114  }
1115 
1116  return QgsFeatureIterator( new QgsVectorLayerSelectedFeatureIterator( mSelectedFeatureIds, req, mSource ) );
1117 }
1118 
1120 {
1121  return mSource.crs();
1122 }
1123 
1125 {
1126  return mSource.fields();
1127 }
1128 
1130 {
1131  return mWkbType;
1132 }
1133 
1135 {
1136  return mSelectedFeatureIds.count();
1137 }
1138 
1140 {
1141  return mName;
1142 }
1143 
1145 {
1146  if ( mLayer )
1147  return mLayer->createExpressionContextScope();
1148  else
1149  return nullptr;
1150 }
1151 
1152 //
1153 // QgsVectorLayerSelectedFeatureIterator
1154 //
1155 
1157 QgsVectorLayerSelectedFeatureIterator::QgsVectorLayerSelectedFeatureIterator( const QgsFeatureIds &selectedFeatureIds, const QgsFeatureRequest &request, QgsVectorLayerFeatureSource &source )
1158  : QgsAbstractFeatureIterator( request )
1159  , mSelectedFeatureIds( selectedFeatureIds )
1160 {
1161  QgsFeatureRequest sourceRequest = request;
1162  if ( sourceRequest.filterType() == QgsFeatureRequest::FilterExpression && sourceRequest.limit() > 0 )
1163  {
1164  // we can't pass the request limit to the provider here - otherwise the provider will
1165  // limit the number of returned features and may only return a bunch of matching features
1166  // which AREN'T in the selected feature set
1167  sourceRequest.setLimit( -1 );
1168  }
1169  mIterator = source.getFeatures( sourceRequest );
1170 }
1171 
1172 bool QgsVectorLayerSelectedFeatureIterator::rewind()
1173 {
1174  return mIterator.rewind();
1175 }
1176 
1177 bool QgsVectorLayerSelectedFeatureIterator::close()
1178 {
1179  return mIterator.close();
1180 }
1181 
1182 bool QgsVectorLayerSelectedFeatureIterator::fetchFeature( QgsFeature &f )
1183 {
1184  while ( mIterator.nextFeature( f ) )
1185  {
1186  if ( mSelectedFeatureIds.contains( f.id() ) )
1187  return true;
1188  }
1189  return false;
1190 }
1191 
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:302
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:171
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:135
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:272
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: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: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:145
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:179
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:184
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:329
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:411
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:435
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.
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:70
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.