Skip to content

Commit 45e485c

Browse files
committed
Fix joins over several tables
1 parent c27c9b5 commit 45e485c

File tree

2 files changed

+76
-8
lines changed

2 files changed

+76
-8
lines changed

src/core/qgsvectorlayerfeatureiterator.cpp

+71-8
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ void QgsVectorLayerFeatureIterator::prepareFields()
555555
mPreparedFields.clear();
556556
mFieldsToPrepare.clear();
557557
mFetchJoinInfo.clear();
558+
mOrderedJoinInfoList.clear();
558559

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

577642
void QgsVectorLayerFeatureIterator::prepareField( int fieldIdx )
@@ -598,21 +663,19 @@ void QgsVectorLayerFeatureIterator::prepareField( int fieldIdx )
598663

599664
void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
600665
{
601-
QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
602-
for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
666+
QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
667+
for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
603668
{
604-
const FetchJoinInfo& info = joinIt.value();
605-
Q_ASSERT( joinIt.key() );
669+
QVariant targetFieldValue = f.attribute( joinIt->targetField );
606670

607-
QVariant targetFieldValue = f.attribute( info.targetField );
608671
if ( !targetFieldValue.isValid() )
609672
continue;
610673

611-
const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
674+
const QHash< QString, QgsAttributes>& memoryCache = joinIt->joinInfo->cachedAttributes;
612675
if ( memoryCache.isEmpty() )
613-
info.addJoinedAttributesDirect( f, targetFieldValue );
676+
joinIt->addJoinedAttributesDirect( f, targetFieldValue );
614677
else
615-
info.addJoinedAttributesCached( f, targetFieldValue );
678+
joinIt->addJoinedAttributesCached( f, targetFieldValue );
616679
}
617680
}
618681

src/core/qgsvectorlayerfeatureiterator.h

+5
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
199199
QList< int > mPreparedFields;
200200
QList< int > mFieldsToPrepare;
201201

202+
/** Join list sorted by dependency*/
203+
QList< FetchJoinInfo > mOrderedJoinInfoList;
204+
202205
/**
203206
* Will always return true. We assume that ordering has been done on provider level already.
204207
*
@@ -207,6 +210,8 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
207210

208211
//! returns whether the iterator supports simplify geometries on provider side
209212
virtual bool providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const override;
213+
214+
void createOrderedJoinList();
210215
};
211216

212217
#endif // QGSVECTORLAYERFEATUREITERATOR_H

0 commit comments

Comments
 (0)