Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[postgres] respect empty FilterFids list
Considering this statement:

    layer.dataProvider().getFeatures(QgsFeatureRequest().setFilterFids([]))

this resulted in an iteration over the whole postgres source.
Internally, this happened implicitly when iterating over a layer with
an active edit buffer but no edited features. In such a scenario, we are
now much faster.
  • Loading branch information
m-kuhn committed Oct 24, 2017
1 parent e086d9a commit f33acca
Showing 1 changed file with 86 additions and 76 deletions.
162 changes: 86 additions & 76 deletions src/providers/postgres/qgspostgresfeatureiterator.cpp
Expand Up @@ -95,9 +95,16 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource
}
else if ( request.filterType() == QgsFeatureRequest::FilterFids )
{
QString fidsWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFids(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );
if ( request.filterFids().isEmpty() )
{
mClosed = true;
}
else
{
QString fidsWhereClause = QgsPostgresUtils::whereClause( mRequest.filterFids(), mSource->mFields, mConn, mSource->mPrimaryKeyType, mSource->mPrimaryKeyAttrs, mSource->mShared );

whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidsWhereClause );
whereClause = QgsPostgresUtils::andWhereClauses( whereClause, fidsWhereClause );
}
}
else if ( request.filterType() == QgsFeatureRequest::FilterExpression )
{
Expand Down Expand Up @@ -136,98 +143,101 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource
}
}

QStringList orderByParts;
if ( !mClosed )
{
QStringList orderByParts;

mOrderByCompiled = true;
mOrderByCompiled = true;

// THIS CODE IS BROKEN - since every retrieved column is cast as text during declareCursor, this method of sorting will always be
// performed using a text sort.
// TODO - fix ordering by so that instead of
// SELECT my_int_col::text FROM some_table ORDER BY my_int_col
// we instead use
// SELECT my_int_col::text FROM some_table ORDER BY some_table.my_int_col
// but that's non-trivial
// THIS CODE IS BROKEN - since every retrieved column is cast as text during declareCursor, this method of sorting will always be
// performed using a text sort.
// TODO - fix ordering by so that instead of
// SELECT my_int_col::text FROM some_table ORDER BY my_int_col
// we instead use
// SELECT my_int_col::text FROM some_table ORDER BY some_table.my_int_col
// but that's non-trivial
#if 0
if ( QgsSettings().value( "qgis/compileExpressions", true ).toBool() )
{
Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
if ( QgsSettings().value( "qgis/compileExpressions", true ).toBool() )
{
QgsPostgresExpressionCompiler compiler = QgsPostgresExpressionCompiler( source );
QgsExpression expression = clause.expression();
if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete )
{
QString part;
part = compiler.result();
part += clause.ascending() ? " ASC" : " DESC";
part += clause.nullsFirst() ? " NULLS FIRST" : " NULLS LAST";
orderByParts << part;
}
else
Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
{
// Bail out on first non-complete compilation.
// Most important clauses at the beginning of the list
// will still be sent and used to pre-sort so the local
// CPU can use its cycles for fine-tuning.
mOrderByCompiled = false;
break;
QgsPostgresExpressionCompiler compiler = QgsPostgresExpressionCompiler( source );
QgsExpression expression = clause.expression();
if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete )
{
QString part;
part = compiler.result();
part += clause.ascending() ? " ASC" : " DESC";
part += clause.nullsFirst() ? " NULLS FIRST" : " NULLS LAST";
orderByParts << part;
}
else
{
// Bail out on first non-complete compilation.
// Most important clauses at the beginning of the list
// will still be sent and used to pre-sort so the local
// CPU can use its cycles for fine-tuning.
mOrderByCompiled = false;
break;
}
}
}
}
else
else
#endif
{
mOrderByCompiled = false;
}
{
mOrderByCompiled = mRequest.orderBy().isEmpty();
}

// ensure that all attributes required for order by are fetched
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
QgsAttributeList attrs = mRequest.subsetOfAttributes();
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
// ensure that all attributes required for order by are fetched
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !attrs.contains( attrIndex ) )
attrs << attrIndex;
QgsAttributeList attrs = mRequest.subsetOfAttributes();
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !attrs.contains( attrIndex ) )
attrs << attrIndex;
}
mRequest.setSubsetOfAttributes( attrs );
}
mRequest.setSubsetOfAttributes( attrs );
}

if ( !mOrderByCompiled )
limitAtProvider = false;
if ( !mOrderByCompiled )
limitAtProvider = false;

bool success = declareCursor( whereClause, limitAtProvider ? mRequest.limit() : -1, false, orderByParts.join( QStringLiteral( "," ) ) );
if ( !success && useFallbackWhereClause )
{
//try with the fallback where clause, e.g., for cases when using compiled expression failed to prepare
success = declareCursor( fallbackWhereClause, -1, false, orderByParts.join( QStringLiteral( "," ) ) );
if ( success )
mExpressionCompiled = false;
}
bool success = declareCursor( whereClause, limitAtProvider ? mRequest.limit() : -1, false, orderByParts.join( QStringLiteral( "," ) ) );
if ( !success && useFallbackWhereClause )
{
//try with the fallback where clause, e.g., for cases when using compiled expression failed to prepare
success = declareCursor( fallbackWhereClause, -1, false, orderByParts.join( QStringLiteral( "," ) ) );
if ( success )
mExpressionCompiled = false;
}

if ( !success && !orderByParts.isEmpty() )
{
//try with no order by clause
success = declareCursor( whereClause, -1, false );
if ( success )
mOrderByCompiled = false;
}
if ( !success && !orderByParts.isEmpty() )
{
//try with no order by clause
success = declareCursor( whereClause, -1, false );
if ( success )
mOrderByCompiled = false;
}

if ( !success && useFallbackWhereClause && !orderByParts.isEmpty() )
{
//try with no expression compilation AND no order by clause
success = declareCursor( fallbackWhereClause, -1, false );
if ( success )
if ( !success && useFallbackWhereClause && !orderByParts.isEmpty() )
{
mExpressionCompiled = false;
mOrderByCompiled = false;
//try with no expression compilation AND no order by clause
success = declareCursor( fallbackWhereClause, -1, false );
if ( success )
{
mExpressionCompiled = false;
mOrderByCompiled = false;
}
}
}

if ( !success )
{
close();
mClosed = true;
iteratorClosed();
if ( !success )
{
close();
mClosed = true;
iteratorClosed();
}
}

mFetched = 0;
Expand Down

0 comments on commit f33acca

Please sign in to comment.