Skip to content

Commit 41c1d6b

Browse files
committed
Sort joins by dependency
1 parent 45373d0 commit 41c1d6b

File tree

2 files changed

+76
-9
lines changed

2 files changed

+76
-9
lines changed

src/core/qgsvectorlayerfeatureiterator.cpp

+71-9
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ void QgsVectorLayerFeatureIterator::prepareFields()
559559
mPreparedFields.clear();
560560
mFieldsToPrepare.clear();
561561
mFetchJoinInfo.clear();
562+
mOrderedJoinInfoList.clear();
562563

563564
mExpressionContext.reset( new QgsExpressionContext() );
564565
mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
@@ -576,6 +577,70 @@ void QgsVectorLayerFeatureIterator::prepareFields()
576577
mPreparedFields << fieldIdx;
577578
prepareField( fieldIdx );
578579
}
580+
581+
//sort joins by dependency
582+
if ( mFetchJoinInfo.size() > 0 )
583+
{
584+
createOrderedJoinList();
585+
}
586+
}
587+
588+
void QgsVectorLayerFeatureIterator::createOrderedJoinList()
589+
{
590+
mOrderedJoinInfoList = mFetchJoinInfo.values();
591+
if( mOrderedJoinInfoList.size() < 2 )
592+
{
593+
return;
594+
}
595+
596+
QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
597+
598+
//add all provider fields without joins as resolved fields
599+
QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
600+
for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
601+
{
602+
if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
603+
{
604+
resolvedFields.insert( *prepFieldIt );
605+
}
606+
}
607+
608+
//iterate through the joins. If target field is not yet covered, move the entry to the end of the list
609+
610+
//some join combinations might not have a resolution at all
611+
int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
612+
int currentIteration = 0;
613+
614+
for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
615+
{
616+
if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
617+
{
618+
mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
619+
mOrderedJoinInfoList.removeAt( i );
620+
--i;
621+
}
622+
else
623+
{
624+
int offset = mOrderedJoinInfoList.at( i ).indexOffset;
625+
int joinField = mOrderedJoinInfoList.at( i ).joinField;
626+
627+
QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
628+
QgsAttributeList::const_iterator attIt = attributes.constBegin();
629+
for ( ; attIt != attributes.constEnd(); ++attIt )
630+
{
631+
if ( *attIt != joinField )
632+
{
633+
resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
634+
}
635+
}
636+
}
637+
638+
++currentIteration;
639+
if ( currentIteration >= maxIterations )
640+
{
641+
break;
642+
}
643+
}
579644
}
580645

581646
void QgsVectorLayerFeatureIterator::prepareField( int fieldIdx )
@@ -602,21 +667,18 @@ void QgsVectorLayerFeatureIterator::prepareField( int fieldIdx )
602667

603668
void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
604669
{
605-
QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
606-
for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
670+
QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
671+
for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
607672
{
608-
const FetchJoinInfo& info = joinIt.value();
609-
Q_ASSERT( joinIt.key() );
610-
611-
QVariant targetFieldValue = f.attribute( info.targetField );
673+
QVariant targetFieldValue = f.attribute( joinIt->targetField );
612674
if ( !targetFieldValue.isValid() )
613675
continue;
614676

615-
const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
677+
const QHash< QString, QgsAttributes>& memoryCache = joinIt->joinInfo->cachedAttributes;
616678
if ( memoryCache.isEmpty() )
617-
info.addJoinedAttributesDirect( f, targetFieldValue );
679+
joinIt->addJoinedAttributesDirect( f, targetFieldValue );
618680
else
619-
info.addJoinedAttributesCached( f, targetFieldValue );
681+
joinIt->addJoinedAttributesCached( f, targetFieldValue );
620682
}
621683
}
622684

src/core/qgsvectorlayerfeatureiterator.h

+5
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
206206
QList< int > mPreparedFields;
207207
QList< int > mFieldsToPrepare;
208208

209+
/** Join list sorted by dependency*/
210+
QList< FetchJoinInfo > mOrderedJoinInfoList;
211+
209212
/**
210213
* Will always return true. We assume that ordering has been done on provider level already.
211214
*
@@ -214,6 +217,8 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
214217

215218
//! returns whether the iterator supports simplify geometries on provider side
216219
virtual bool providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const override;
220+
221+
void createOrderedJoinList();
217222
};
218223

219224
#endif // QGSVECTORLAYERFEATUREITERATOR_H

0 commit comments

Comments
 (0)