Skip to content
Permalink
Browse files

Fix joins over several tables

  • Loading branch information
mhugent committed Sep 12, 2016
1 parent c27c9b5 commit 45e485ce0db84a659e2f0e6101efc26236abbf3b
Showing with 76 additions and 8 deletions.
  1. +71 −8 src/core/qgsvectorlayerfeatureiterator.cpp
  2. +5 −0 src/core/qgsvectorlayerfeatureiterator.h
@@ -555,6 +555,7 @@ void QgsVectorLayerFeatureIterator::prepareFields()
mPreparedFields.clear();
mFieldsToPrepare.clear();
mFetchJoinInfo.clear();
mOrderedJoinInfoList.clear();

mExpressionContext.reset( new QgsExpressionContext() );
mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
@@ -572,6 +573,70 @@ void QgsVectorLayerFeatureIterator::prepareFields()
mPreparedFields << fieldIdx;
prepareField( fieldIdx );
}

//sort joins by dependency
if ( mFetchJoinInfo.size() > 0 )
{
createOrderedJoinList();
}
}

void QgsVectorLayerFeatureIterator::createOrderedJoinList()
{
mOrderedJoinInfoList = mFetchJoinInfo.values();
if ( mOrderedJoinInfoList.size() < 2 )
{
return;
}

QSet<int> resolvedFields; //todo: get provider / virtual fields without joins

//add all provider fields without joins as resolved fields
QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
{
if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
{
resolvedFields.insert( *prepFieldIt );
}
}

//iterate through the joins. If target field is not yet covered, move the entry to the end of the list

//some join combinations might not have a resolution at all
int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
int currentIteration = 0;

for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
{
if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
{
mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
mOrderedJoinInfoList.removeAt( i );
--i;
}
else
{
int offset = mOrderedJoinInfoList.at( i ).indexOffset;
int joinField = mOrderedJoinInfoList.at( i ).joinField;

QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
QgsAttributeList::const_iterator attIt = attributes.constBegin();
for ( ; attIt != attributes.constEnd(); ++attIt )
{
if ( *attIt != joinField )
{
resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
}
}
}

++currentIteration;
if ( currentIteration >= maxIterations )
{
break;
}
}
}

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

void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
{
QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
{
const FetchJoinInfo& info = joinIt.value();
Q_ASSERT( joinIt.key() );
QVariant targetFieldValue = f.attribute( joinIt->targetField );

QVariant targetFieldValue = f.attribute( info.targetField );
if ( !targetFieldValue.isValid() )
continue;

const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
const QHash< QString, QgsAttributes>& memoryCache = joinIt->joinInfo->cachedAttributes;
if ( memoryCache.isEmpty() )
info.addJoinedAttributesDirect( f, targetFieldValue );
joinIt->addJoinedAttributesDirect( f, targetFieldValue );
else
info.addJoinedAttributesCached( f, targetFieldValue );
joinIt->addJoinedAttributesCached( f, targetFieldValue );
}
}

@@ -199,6 +199,9 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
QList< int > mPreparedFields;
QList< int > mFieldsToPrepare;

/** Join list sorted by dependency*/
QList< FetchJoinInfo > mOrderedJoinInfoList;

/**
* Will always return true. We assume that ordering has been done on provider level already.
*
@@ -207,6 +210,8 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera

//! returns whether the iterator supports simplify geometries on provider side
virtual bool providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const override;

void createOrderedJoinList();
};

#endif // QGSVECTORLAYERFEATUREITERATOR_H

0 comments on commit 45e485c

Please sign in to comment.
You can’t perform that action at this time.