QGIS API Documentation  2.99.0-Master (f1c3692)
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 
36  // update layer's join caches if necessary
37  if ( layer->mJoinBuffer->containsJoins() )
38  layer->mJoinBuffer->createJoinCaches();
39 
40  mJoinBuffer = layer->mJoinBuffer->clone();
41 
42  mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
43  mCrs = layer->crs();
44 
45  mHasEditBuffer = layer->editBuffer();
46  if ( mHasEditBuffer )
47  {
48 #if 0
49  // TODO[MD]: after merge
50  if ( request.filterType() == QgsFeatureRequest::FilterFid )
51  {
52 
53  // only copy relevant parts
54  if ( L->editBuffer()->addedFeatures().contains( request.filterFid() ) )
55  mAddedFeatures.insert( request.filterFid(), L->editBuffer()->addedFeatures()[ request.filterFid()] );
56 
57  if ( L->editBuffer()->changedGeometries().contains( request.filterFid() ) )
58  mChangedGeometries.insert( request.filterFid(), L->editBuffer()->changedGeometries()[ request.filterFid()] );
59 
60  if ( L->editBuffer()->deletedFeatureIds().contains( request.filterFid() ) )
61  mDeletedFeatureIds.insert( request.filterFid() );
62 
63  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
64  mChangedAttributeValues.insert( request.filterFid(), L->editBuffer()->changedAttributeValues()[ request.filterFid()] );
65 
66  if ( L->editBuffer()->changedAttributeValues().contains( request.filterFid() ) )
67  mChangedFeaturesRequest.setFilterFids( QgsFeatureIds() << request.filterFid() );
68  }
69  else
70  {
71 #endif
76  mAddedAttributes = QList<QgsField>( layer->editBuffer()->addedAttributes() );
78 #if 0
79  }
80 #endif
81  }
82 
83  std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
84  mLayerScope = *layerScope;
85 }
86 
88 {
89  delete mJoinBuffer;
92 }
93 
95 {
96  // return feature iterator that does not own this source
97  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( this, false, request ) );
98 }
99 
101 {
102  return mFields;
103 }
104 
106 {
107  return mCrs;
108 }
109 
110 
113  , mFetchedFid( false )
114 
115 {
117  {
119  }
120  try
121  {
123  }
124  catch ( QgsCsException & )
125  {
126  // can't reproject mFilterRect
127  mClosed = true;
128  return;
129  }
130  if ( !mFilterRect.isNull() )
131  {
132  // update request to be the unprojected filter rect
134  }
135 
137  {
140 
142  {
143  //ensure that all fields required for filter expressions are prepared
144  QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
145  attributeIndexes += mRequest.subsetOfAttributes().toSet();
146  mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
147  }
148  }
149 
150  prepareFields();
151 
152  mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
153 
154  // by default provider's request is the same
156  // but we remove any destination CRS parameter - that is handled in QgsVectorLayerFeatureIterator,
157  // not at the provider level. Otherwise virtual fields depending on geometry would have incorrect
158  // values
159  if ( mRequest.destinationCrs().isValid() )
160  {
162  }
163 
165  {
166  // prepare list of attributes to match provider fields
167  QSet<int> providerSubset;
169  int nPendingFields = mSource->mFields.count();
170  Q_FOREACH ( int attrIndex, subset )
171  {
172  if ( attrIndex < 0 || attrIndex >= nPendingFields )
173  continue;
174  if ( mSource->mFields.fieldOrigin( attrIndex ) == QgsFields::OriginProvider )
175  providerSubset << mSource->mFields.fieldOriginIndex( attrIndex );
176  }
177 
178  // This is done in order to be prepared to do fallback order bys
179  // and be sure we have the required columns.
180  // TODO:
181  // It would be nicer to first check if we can compile the order by
182  // and only modify the subset if we cannot.
183  if ( !mProviderRequest.orderBy().isEmpty() )
184  {
185  Q_FOREACH ( const QString &attr, mProviderRequest.orderBy().usedAttributes() )
186  {
187  providerSubset << mSource->mFields.lookupField( attr );
188  }
189  }
190 
191  mProviderRequest.setSubsetOfAttributes( providerSubset.toList() );
192  }
193 
195  {
196  Q_FOREACH ( const QString &field, mProviderRequest.filterExpression()->referencedColumns() )
197  {
198  int idx = source->mFields.lookupField( field );
199 
200  // If there are fields in the expression which are not of origin provider, the provider will not be able to filter based on them.
201  // In this case we disable the expression filter.
202  if ( source->mFields.fieldOrigin( idx ) != QgsFields::OriginProvider )
203  {
205  // can't limit at provider side
207  }
208  }
209  }
210 
211  if ( mSource->mHasEditBuffer )
212  {
214  QgsFeatureIds changedIds;
215  QgsChangedAttributesMap::const_iterator attIt = mSource->mChangedAttributeValues.constBegin();
216  for ( ; attIt != mSource->mChangedAttributeValues.constEnd(); ++attIt )
217  {
218  changedIds << attIt.key();
219  }
221 
222  if ( mChangedFeaturesRequest.limit() > 0 )
223  {
224  int providerLimit = mProviderRequest.limit();
225 
226  // features may be deleted in buffer, so increase limit sent to provider
227  providerLimit += mSource->mDeletedFeatureIds.size();
228 
230  {
231  // attribute changes may mean some features no longer match expression, so increase limit sent to provider
232  providerLimit += mSource->mChangedAttributeValues.size();
233  }
234 
236  {
237  // geometry changes may mean some features no longer match expression or rect, so increase limit sent to provider
238  providerLimit += mSource->mChangedGeometries.size();
239  }
240 
241  mProviderRequest.setLimit( providerLimit );
242  mChangedFeaturesRequest.setLimit( providerLimit );
243  }
244  }
245 
246  if ( request.filterType() == QgsFeatureRequest::FilterFid )
247  {
248  mFetchedFid = false;
249  }
250  else // no filter or filter by rect
251  {
252  if ( mSource->mHasEditBuffer )
253  {
255  }
256  else
257  {
259  }
260 
262  }
263 }
264 
265 
267 {
268  qDeleteAll( mExpressionFieldInfo );
269 
270  close();
271 }
272 
273 
274 
276 {
277  f.setValid( false );
278 
279  if ( mClosed )
280  return false;
281 
283  {
284  if ( mFetchedFid )
285  return false;
286  bool res = nextFeatureFid( f );
287  if ( res && postProcessFeature( f ) )
288  {
289  mFetchedFid = true;
290  return res;
291  }
292  else
293  {
294  return false;
295  }
296  }
297 
298  if ( !mFilterRect.isNull() )
299  {
300  if ( fetchNextChangedGeomFeature( f ) )
301  return true;
302 
303  // no more changed geometries
304  }
305 
307  {
309  return true;
310 
311  if ( fetchNextChangedGeomFeature( f ) )
312  return true;
313 
314  // no more changed features
315  }
316 
317  while ( fetchNextAddedFeature( f ) )
318  {
319  return true;
320  }
321  // no more added features
322 
323  if ( mProviderIterator.isClosed() )
324  {
327  mProviderIterator.setInterruptionChecker( mInterruptionChecker );
328  }
329 
330  while ( mProviderIterator.nextFeature( f ) )
331  {
332  if ( mFetchConsidered.contains( f.id() ) )
333  continue;
334 
335  // TODO[MD]: just one resize of attributes
336  f.setFields( mSource->mFields );
337 
338  // update attributes
339  if ( mSource->mHasEditBuffer )
341 
342  if ( mHasVirtualAttributes )
344 
346  {
347  //filtering by expression, and couldn't do it on the provider side
349  if ( !mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() )
350  {
351  //feature did not match filter
352  continue;
353  }
354  }
355 
356  // update geometry
357  // TODO[MK]: FilterRect check after updating the geometry
360 
361  if ( !postProcessFeature( f ) )
362  continue;
363 
364  return true;
365  }
366  // no more provider features
367 
368  close();
369  return false;
370 }
371 
372 
373 
375 {
376  if ( mClosed )
377  return false;
378 
380  {
381  mFetchedFid = false;
382  }
383  else
384  {
387  }
388 
389  return true;
390 }
391 
393 {
394  if ( mClosed )
395  return false;
396 
398 
399  iteratorClosed();
400 
401  mClosed = true;
402  return true;
403 }
404 
406 {
407  mProviderIterator.setInterruptionChecker( interruptionChecker );
408  mInterruptionChecker = interruptionChecker;
409 }
410 
412 {
413  return mProviderIterator.isValid();
414 }
415 
417 {
418  while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
419  {
421 
422  if ( mFetchConsidered.contains( fid ) )
423  // must have changed geometry outside rectangle
424  continue;
425 
427 
428  // can't test for feature acceptance until after calling useAddedFeature
429  // since acceptFeature may rely on virtual fields
430  if ( !mRequest.acceptFeature( f ) )
431  // skip features which are not accepted by the filter
432  continue;
433 
434  if ( !postProcessFeature( f ) )
435  continue;
436 
437  return true;
438  }
439 
441  return false; // no more added features
442 }
443 
444 
446 {
447  // since QgsFeature is implicitly shared, it's more efficient to just copy the
448  // whole feature, even if flags like NoGeometry or a subset of attributes is set at the request.
449  // This helps potentially avoid an unnecessary detach of the feature
450  f = src;
451  f.setValid( true );
452  f.setFields( mSource->mFields );
453 
454  if ( mHasVirtualAttributes )
456 }
457 
458 
459 
461 {
462  // check if changed geometries are in rectangle
464  {
465  QgsFeatureId fid = mFetchChangedGeomIt.key();
466 
467  if ( mFetchConsidered.contains( fid ) )
468  // skip deleted features
469  continue;
470 
471  mFetchConsidered << fid;
472 
473  if ( !mFilterRect.isNull() && !mFetchChangedGeomIt->intersects( mFilterRect ) )
474  // skip changed geometries not in rectangle and don't check again
475  continue;
476 
478 
480  {
482  if ( !mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() )
483  {
484  continue;
485  }
486  }
487 
488  if ( postProcessFeature( f ) )
489  {
490  // return complete feature
492  return true;
493  }
494  }
495 
496  return false; // no more changed geometries
497 }
498 
500 {
502  {
503  if ( mFetchConsidered.contains( f.id() ) )
504  // skip deleted features and those already handled by the geometry
505  continue;
506 
507  mFetchConsidered << f.id();
508 
510 
511  if ( mHasVirtualAttributes )
513 
515  if ( mRequest.filterExpression()->evaluate( mRequest.expressionContext() ).toBool() && postProcessFeature( f ) )
516  {
517  return true;
518  }
519  }
520 
521  return false;
522 }
523 
524 
526 {
527  f.setId( fid );
528  f.setValid( true );
529  f.setFields( mSource->mFields );
530 
533  {
534  f.setGeometry( geom );
535  }
536 
537  bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
538  if ( !subsetAttrs || !mRequest.subsetOfAttributes().isEmpty() )
539  {
540  // retrieve attributes from provider
541  QgsFeature tmp;
542  //mDataProvider->featureAtId( fid, tmp, false, mFetchProvAttributes );
543  QgsFeatureRequest request;
545  if ( subsetAttrs )
546  {
548  }
550  if ( fi.nextFeature( tmp ) )
551  {
554  f.setAttributes( tmp.attributes() );
555  }
556  }
557 
559 }
560 
561 
562 
564 {
566 
569 }
570 
572 {
573  if ( !mSource->mFields.exists( fieldIdx ) )
574  return;
575 
576  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
577  return;
578 
579  int sourceLayerIndex;
580  const QgsVectorLayerJoinInfo *joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
581  Q_ASSERT( joinInfo );
582 
583  QgsVectorLayer *joinLayer = joinInfo->joinLayer();
584  if ( !joinLayer )
585  return; // invalid join (unresolved reference to layer)
586 
587  if ( !mFetchJoinInfo.contains( joinInfo ) )
588  {
589  FetchJoinInfo info;
590  info.joinInfo = joinInfo;
591  info.joinLayer = joinLayer;
594  info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName() );
595 
596  // for joined fields, we always need to request the targetField from the provider too
597  if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
598  mFieldsToPrepare << info.targetField;
599 
602 
603  mFetchJoinInfo.insert( joinInfo, info );
604  }
605 
606  // store field source index - we'll need it when fetching from provider
607  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
608 }
609 
611 {
612  const QList<QgsExpressionFieldBuffer::ExpressionField> &exps = mSource->mExpressionFieldBuffer->expressions();
613 
614  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
615  QgsExpression *exp = new QgsExpression( exps[oi].cachedExpression );
616 
617  QgsDistanceArea da;
618  da.setSourceCrs( mSource->mCrs );
619  da.setEllipsoid( QgsProject::instance()->ellipsoid() );
620  exp->setGeomCalculator( &da );
621  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
622  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
623 
624  exp->prepare( mExpressionContext.get() );
625  Q_FOREACH ( const QString &col, exp->referencedColumns() )
626  {
627  if ( mSource->fields().lookupField( col ) == fieldIdx )
628  {
629  // circular reference - expression depends on column itself
630  delete exp;
631  return;
632  }
633  }
634  mExpressionFieldInfo.insert( fieldIdx, exp );
635 
636  Q_FOREACH ( const QString &col, exp->referencedColumns() )
637  {
638  int dependentFieldIdx = mSource->mFields.lookupField( col );
640  {
641  mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependentFieldIdx );
642  }
643  // also need to fetch this dependent field
644  if ( !mPreparedFields.contains( dependentFieldIdx ) && !mFieldsToPrepare.contains( dependentFieldIdx ) )
645  mFieldsToPrepare << dependentFieldIdx;
646  }
647 
648  if ( exp->needsGeometry() )
649  {
650  mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
651  }
652 }
653 
655 {
656  mPreparedFields.clear();
657  mFieldsToPrepare.clear();
658  mFetchJoinInfo.clear();
659  mOrderedJoinInfoList.clear();
660 
661  mExpressionContext.reset( new QgsExpressionContext() );
662  mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
663  mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
664  mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );
665 
667 
668  while ( !mFieldsToPrepare.isEmpty() )
669  {
670  int fieldIdx = mFieldsToPrepare.takeFirst();
671  if ( mPreparedFields.contains( fieldIdx ) )
672  continue;
673 
674  mPreparedFields << fieldIdx;
675  prepareField( fieldIdx );
676  }
677 
678  //sort joins by dependency
679  if ( !mFetchJoinInfo.empty() )
680  {
681  createOrderedJoinList();
682  }
683 }
684 
685 void QgsVectorLayerFeatureIterator::createOrderedJoinList()
686 {
687  mOrderedJoinInfoList = mFetchJoinInfo.values();
688  if ( mOrderedJoinInfoList.size() < 2 )
689  {
690  return;
691  }
692 
693  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
694 
695  //add all provider fields without joins as resolved fields
696  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
697  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
698  {
699  if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
700  {
701  resolvedFields.insert( *prepFieldIt );
702  }
703  }
704 
705  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
706 
707  //some join combinations might not have a resolution at all
708  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
709  int currentIteration = 0;
710 
711  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
712  {
713  if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
714  {
715  mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
716  mOrderedJoinInfoList.removeAt( i );
717  --i;
718  }
719  else
720  {
721  int offset = mOrderedJoinInfoList.at( i ).indexOffset;
722  int joinField = mOrderedJoinInfoList.at( i ).joinField;
723 
724  QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
725  QgsAttributeList::const_iterator attIt = attributes.constBegin();
726  for ( ; attIt != attributes.constEnd(); ++attIt )
727  {
728  if ( *attIt != joinField )
729  {
730  resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
731  }
732  }
733  }
734 
735  ++currentIteration;
736  if ( currentIteration >= maxIterations )
737  {
738  break;
739  }
740  }
741 }
742 
743 bool QgsVectorLayerFeatureIterator::postProcessFeature( QgsFeature &feature )
744 {
745  bool result = checkGeometryValidity( feature );
746  if ( result )
748  return result;
749 }
750 
751 bool QgsVectorLayerFeatureIterator::checkGeometryValidity( const QgsFeature &feature )
752 {
753  if ( !feature.hasGeometry() )
754  return true;
755 
756  switch ( mRequest.invalidGeometryCheck() )
757  {
759  return true;
760 
762  {
763  if ( !feature.geometry().isGeosValid() )
764  {
765  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), QgsMessageLog::CRITICAL );
767  {
768  mRequest.invalidGeometryCallback()( feature );
769  }
770  return false;
771  }
772  break;
773  }
774 
776  if ( !feature.geometry().isGeosValid() )
777  {
778  QgsMessageLog::logMessage( QObject::tr( "Geometry error: One or more input features have invalid geometry." ), QString(), QgsMessageLog::CRITICAL );
779  close();
781  {
782  mRequest.invalidGeometryCallback()( feature );
783  }
784  return false;
785  }
786  break;
787  }
788 
789  return true;
790 }
791 
793 {
794  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
795  {
797  prepareExpression( fieldIdx );
798  break;
799 
802  {
803  prepareJoin( fieldIdx );
804  }
805  break;
806 
810  break;
811  }
812 }
813 
815 {
816  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
817  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
818  {
819  QVariant targetFieldValue = f.attribute( joinIt->targetField );
820  if ( !targetFieldValue.isValid() )
821  continue;
822 
823  const QHash< QString, QgsAttributes> &memoryCache = joinIt->joinInfo->cachedAttributes;
824  if ( memoryCache.isEmpty() )
825  joinIt->addJoinedAttributesDirect( f, targetFieldValue );
826  else
827  joinIt->addJoinedAttributesCached( f, targetFieldValue );
828  }
829 }
830 
832 {
833  // make sure we have space for newly added attributes
834  QgsAttributes attr = f.attributes();
835  attr.resize( mSource->mFields.count() ); // Provider attrs count + joined attrs count + expression attrs count
836  f.setAttributes( attr );
837 
838  // possible TODO - handle combinations of expression -> join -> expression -> join?
839  // but for now, write that off as too complex and an unlikely rare, unsupported use case
840 
841  QList< int > fetchedVirtualAttributes;
842  //first, check through joins for any virtual fields we need
843  QMap<const QgsVectorLayerJoinInfo *, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
844  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
845  {
846  if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
847  {
848  // have to calculate expression field before we can handle this join
849  addExpressionAttribute( f, joinIt->targetField );
850  fetchedVirtualAttributes << joinIt->targetField;
851  }
852  }
853 
854  if ( !mFetchJoinInfo.isEmpty() )
855  addJoinedAttributes( f );
856 
857  // add remaining expression fields
858  if ( !mExpressionFieldInfo.isEmpty() )
859  {
860  QMap<int, QgsExpression *>::ConstIterator it = mExpressionFieldInfo.constBegin();
861  for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
862  {
863  if ( fetchedVirtualAttributes.contains( it.key() ) )
864  continue;
865 
866  addExpressionAttribute( f, it.key() );
867  }
868  }
869 }
870 
872 {
873  QgsExpression *exp = mExpressionFieldInfo.value( attrIndex );
874  if ( exp )
875  {
876  mExpressionContext->setFeature( f );
877  QVariant val = exp->evaluate( mExpressionContext.get() );
878  ( void )mSource->mFields.at( attrIndex ).convertCompatible( val );
879  f.setAttribute( attrIndex, val );
880  }
881  else
882  {
883  f.setAttribute( attrIndex, QVariant() );
884  }
885 }
886 
888 {
889  Q_UNUSED( simplifyMethod );
890  return false;
891 }
892 
893 bool QgsVectorLayerFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const
894 {
895  Q_UNUSED( methodType );
896  return false;
897 }
898 
899 
901 {
902  const QHash<QString, QgsAttributes> &memoryCache = joinInfo->cachedAttributes;
903  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
904  if ( it == memoryCache.constEnd() )
905  return; // joined value not found -> leaving the attributes empty (null)
906 
907  int index = indexOffset;
908 
909  const QgsAttributes &featureAttributes = it.value();
910  for ( int i = 0; i < featureAttributes.count(); ++i )
911  {
912  f.setAttribute( index++, featureAttributes.at( i ) );
913  }
914 }
915 
916 
917 
919 {
920  // no memory cache, query the joined values by setting substring
921  QString subsetString;
922 
923  QString joinFieldName = joinInfo->joinFieldName();
924 
925  subsetString.append( QStringLiteral( "\"%1\"" ).arg( joinFieldName ) );
926 
927  if ( joinValue.isNull() )
928  {
929  subsetString += QLatin1String( " IS NULL" );
930  }
931  else
932  {
933  QString v = joinValue.toString();
934  switch ( joinValue.type() )
935  {
936  case QVariant::Int:
937  case QVariant::LongLong:
938  case QVariant::Double:
939  break;
940 
941  default:
942  case QVariant::String:
943  v.replace( '\'', QLatin1String( "''" ) );
944  v.prepend( '\'' ).append( '\'' );
945  break;
946  }
947  subsetString += '=' + v;
948  }
949 
950  // maybe user requested just a subset of layer's attributes
951  // so we do not have to cache everything
952  QVector<int> subsetIndices;
953  if ( joinInfo->hasSubset() )
954  {
955  const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
956  subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
957  }
958 
959  // select (no geometry)
960  QgsFeatureRequest request;
962  request.setSubsetOfAttributes( attributes );
963  request.setFilterExpression( subsetString );
964  request.setLimit( 1 );
965  QgsFeatureIterator fi = joinLayer->getFeatures( request );
966 
967  // get first feature
968  QgsFeature fet;
969  if ( fi.nextFeature( fet ) )
970  {
971  int index = indexOffset;
972  QgsAttributes attr = fet.attributes();
973  if ( joinInfo->hasSubset() )
974  {
975  for ( int i = 0; i < subsetIndices.count(); ++i )
976  f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );
977  }
978  else
979  {
980  // use all fields except for the one used for join (has same value as exiting field in target layer)
981  for ( int i = 0; i < attr.count(); ++i )
982  {
983  if ( i == joinField )
984  continue;
985 
986  f.setAttribute( index++, attr.at( i ) );
987  }
988  }
989  }
990  else
991  {
992  // no suitable join feature found, keeping empty (null) attributes
993  }
994 }
995 
996 
997 
998 
1000 {
1001  QgsFeatureId featureId = mRequest.filterFid();
1002 
1003  // deleted already?
1004  if ( mSource->mDeletedFeatureIds.contains( featureId ) )
1005  return false;
1006 
1007  // has changed geometry?
1008  if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && mSource->mChangedGeometries.contains( featureId ) )
1009  {
1010  useChangedAttributeFeature( featureId, mSource->mChangedGeometries[featureId], f );
1011  return true;
1012  }
1013 
1014  // added features
1015  for ( QgsFeatureMap::ConstIterator iter = mSource->mAddedFeatures.constBegin(); iter != mSource->mAddedFeatures.constEnd(); ++iter )
1016  {
1017  if ( iter->id() == featureId )
1018  {
1019  useAddedFeature( *iter, f );
1020  return true;
1021  }
1022  }
1023 
1024  // regular features
1026  if ( fi.nextFeature( f ) )
1027  {
1028  f.setFields( mSource->mFields );
1029 
1030  if ( mSource->mHasEditBuffer )
1032 
1033  if ( mHasVirtualAttributes )
1034  addVirtualAttributes( f );
1035 
1036  return true;
1037  }
1038 
1039  return false;
1040 }
1041 
1043 {
1044  QgsAttributes attrs = f.attributes();
1045 
1046  // remove all attributes that will disappear - from higher indices to lower
1047  for ( int idx = mSource->mDeletedAttributeIds.count() - 1; idx >= 0; --idx )
1048  {
1049  attrs.remove( mSource->mDeletedAttributeIds[idx] );
1050  }
1051 
1052  // adjust size to accommodate added attributes
1053  attrs.resize( attrs.count() + mSource->mAddedAttributes.count() );
1054 
1055  // update changed attributes
1056  if ( mSource->mChangedAttributeValues.contains( f.id() ) )
1057  {
1059  for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
1060  attrs[it.key()] = it.value();
1061  }
1062  f.setAttributes( attrs );
1063 }
1064 
1066 {
1067  if ( mSource->mChangedGeometries.contains( f.id() ) )
1069 }
1070 
1071 bool QgsVectorLayerFeatureIterator::prepareOrderBy( const QList<QgsFeatureRequest::OrderByClause> &orderBys )
1072 {
1073  Q_UNUSED( orderBys );
1074  return true;
1075 }
1076 
1077 
1078 //
1079 // QgsVectorLayerSelectedFeatureSource
1080 //
1081 
1083  : mSource( layer )
1084  , mSelectedFeatureIds( layer->selectedFeatureIds() )
1085  , mWkbType( layer->wkbType() )
1086  , mName( layer->name() )
1087 {}
1088 
1090 {
1091  QgsFeatureRequest req( request );
1092 
1093  if ( req.filterFids().isEmpty() && req.filterType() != QgsFeatureRequest::FilterFid )
1094  {
1095  req.setFilterFids( mSelectedFeatureIds );
1096  }
1097  else if ( !req.filterFids().isEmpty() )
1098  {
1099  QgsFeatureIds reqIds = mSelectedFeatureIds;
1100  reqIds.intersect( req.filterFids() );
1101  req.setFilterFids( reqIds );
1102  }
1103 
1104  return mSource.getFeatures( req );
1105 }
1106 
1108 {
1109  return mSource.crs();
1110 }
1111 
1113 {
1114  return mSource.fields();
1115 }
1116 
1118 {
1119  return mWkbType;
1120 }
1121 
1123 {
1124  return mSelectedFeatureIds.count();
1125 }
1126 
1128 {
1129  return mName;
1130 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:299
QList< QgsExpressionFieldBuffer::ExpressionField > expressions() const
QgsAbstractFeatureSource * mProviderFeatureSource
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Returns an iterator for the features in the source.
QgsFeatureId id
Definition: qgsfeature.h:71
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:537
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
virtual void setInterruptionChecker(QgsInterruptionChecker *interruptionChecker) override
Attach an object that can be queried regularly by the iterator to check if it must stopped...
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:171
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:155
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
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
Return if a field index is valid.
Definition: qgsfields.cpp:135
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
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.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) override
Get an iterator for features matching the specified request.
QgsFeatureId filterFid() const
Get the feature ID that should be fetched.
QgsRectangle filterRectToSourceCrs(const QgsCoordinateTransform &transform) const
Returns a rectangle representing the original request&#39;s QgsFeatureRequest::filterRect().
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for feature&#39;s geometries, or an invalid QgsCoordi...
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Get an iterator for features matching the specified request.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:224
FilterType filterType() const
Return 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
Get feature IDs that should be fetched.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:204
Skip any features with invalid geometry. This requires a slow geometry validity check for every featu...
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
Set to true, as soon as the iterator is closed.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed. ...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:190
QgsVectorLayer * joinLayer
Resolved pointer to the joined layer.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
int count() const
Return number of items.
Definition: qgsfields.cpp:115
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
bool isGeosValid() const
Checks validity of the geometry using GEOS.
It has not been specified where the field comes from.
Definition: qgsfields.h:48
QgsFields fields() const override
Returns the fields associated with features in the source.
QgsField at(int i) const
Get 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
Get field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:179
virtual QgsAbstractFeatureSource * featureSource() const =0
Return feature source object that can be used for querying provider&#39;s data.
Interface that can be optionally attached to an iterator so its nextFeature() implementaton can check...
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Set feature ID that should be fetched.
QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on...
QgsGeometryMap changedGeometries() const
Returns a map of features with changed geometries which are not committed.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
void iteratorClosed()
to be called by from subclass in close()
int indexFromName(const QString &fieldName) const
Get the field index from the field name.
Definition: qgsfields.cpp: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...
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:326
QgsFields fields() const override
Returns the list of fields of this layer.
QgsFields fields() const
Returns the fields that will be available for features that are retrieved from this source...
QgsFeatureRequest & disableFilter()
Disables filter conditions.
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual bool prepareSimplification(const QgsSimplifyMethod &simplifyMethod) override
Setup the simplification of geometries to fetch using the specified simplify method.
void addJoinedAttributesCached(QgsFeature &f, const QVariant &joinValue) const
Defines left outer join from our vector layer to some other vector layer.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:39
virtual bool fetchFeature(QgsFeature &feature) override
fetch next feature, return true on success
QgsAttributeList deletedAttributeIds() const
Returns a list of deleted attributes fields which are not committed.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
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
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QgsAttributeList subsetOfAttributes() const
Return the subset of attributes which at least need to be fetched.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
int indexOffset
At what position the joined fields start.
void useChangedAttributeFeature(QgsFeatureId fid, const QgsGeometry &geom, QgsFeature &f)
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:181
QMap< QgsFeatureId, QgsFeature > QgsFeatureMap
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.
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
int targetField
Index of field (of this layer) that drives the join.
Buffers information about expression fields for a vector layer.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Set feature IDs that should be fetched.
QMap< QgsFeatureId, QgsAttributeMap > QgsChangedAttributesMap
Definition: qgsfeature.h:528
virtual bool rewind() override
reset the iterator to the starting position
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
QMap< const QgsVectorLayerJoinInfo *, QgsVectorLayerFeatureIterator::FetchJoinInfo > mFetchJoinInfo
Information about joins used in the current select() statement.
This class represents a coordinate reference system (CRS).
virtual bool close() override
end of iterating: free the resources / lock
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Return a vector of indices for use in join based on field names from the layer.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
InvalidGeometryCheck invalidGeometryCheck() const
Returns the invalid geometry checking behavior.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Class for doing transforms between two map coordinate systems.
Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAtt...
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination crs for feature&#39;s geometries.
qint64 QgsFeatureId
Definition: qgsfeature.h:37
This class contains information about how to simplify geometries fetched from a QgsFeatureIterator.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
void setSourceCrs(const QgsCoordinateReferenceSystem &srcCRS)
Sets source spatial reference system.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
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
Return a list of order by clauses specified for this feature request.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QList< QgsField > addedAttributes() const
Returns a list of added attributes fields which are not committed.
A vector of attributes.
Definition: qgsattributes.h:58
Represents a vector layer which manages a vector based data sets.
virtual 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:255
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.
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
Get subset of fields to be used from joined layer.
QgsAttributes attributes
Definition: qgsfeature.h:72
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
std::function< void(const QgsFeature &) > invalidGeometryCallback() const
Returns the callback function to use when encountering an invalid geometry and invalidGeometryCheck()...
void setInterruptionChecker(QgsInterruptionChecker *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped...
int joinedFieldsOffset(const QgsVectorLayerJoinInfo *info, const QgsFields &fields)
Find out what is the first index of the join within fields.
QgsVectorLayerJoinBuffer * clone() const
Create a copy of the join buffer.
void addVirtualAttributes(QgsFeature &f)
Adds attributes that don&#39;t source from the provider but are added inside QGIS Includes.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Set flags that affect how features will be fetched.
Helper template that cares of two things: 1.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.