Skip to content

Commit

Permalink
Speed up spatialite provider
Browse files Browse the repository at this point in the history
No need to iterate over all the features in the datasource only to find
out that there is no feature which is not in an empty list of feature
ids.
  • Loading branch information
m-kuhn committed Oct 24, 2017
1 parent 269f751 commit 86b28ff
Showing 1 changed file with 66 additions and 60 deletions.
126 changes: 66 additions & 60 deletions src/providers/spatialite/qgsspatialitefeatureiterator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
catch ( QgsCsException & ) catch ( QgsCsException & )
{ {
// can't reproject mFilterRect // can't reproject mFilterRect
mClosed = true; close();
return; return;
} }


Expand Down Expand Up @@ -90,10 +90,13 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
} }
else if ( request.filterType() == QgsFeatureRequest::FilterFids ) else if ( request.filterType() == QgsFeatureRequest::FilterFids )
{ {
whereClause = whereClauseFids(); if ( request.filterFids().isEmpty() )
if ( ! whereClause.isEmpty() )
{ {
whereClauses.append( whereClause ); close();
}
else
{
whereClauses.append( whereClauseFids() );
} }
} }
//IMPORTANT - this MUST be the last clause added! //IMPORTANT - this MUST be the last clause added!
Expand Down Expand Up @@ -144,77 +147,80 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
} }
} }


whereClause = whereClauses.join( QStringLiteral( " AND " ) ); if ( !mClosed )
{
whereClause = whereClauses.join( QStringLiteral( " AND " ) );


// Setup the order by // Setup the order by
QStringList orderByParts; QStringList orderByParts;


mOrderByCompiled = true; mOrderByCompiled = true;


if ( QgsSettings().value( QStringLiteral( "qgis/compileExpressions" ), true ).toBool() ) if ( QgsSettings().value( QStringLiteral( "qgis/compileExpressions" ), true ).toBool() )
{
Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
{ {
QgsSQLiteExpressionCompiler compiler = QgsSQLiteExpressionCompiler( source->mFields ); Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
QgsExpression expression = clause.expression();
if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete )
{ {
QString part; QgsSQLiteExpressionCompiler compiler = QgsSQLiteExpressionCompiler( source->mFields );
part = compiler.result(); QgsExpression expression = clause.expression();
if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete )
{
QString part;
part = compiler.result();


if ( clause.nullsFirst() ) if ( clause.nullsFirst() )
orderByParts << QStringLiteral( "%1 IS NOT NULL" ).arg( part ); orderByParts << QStringLiteral( "%1 IS NOT NULL" ).arg( part );
else else
orderByParts << QStringLiteral( "%1 IS NULL" ).arg( part ); orderByParts << QStringLiteral( "%1 IS NULL" ).arg( part );


part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC"; part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC";
orderByParts << part; orderByParts << part;
} }
else else
{ {
// Bail out on first non-complete compilation. // Bail out on first non-complete compilation.
// Most important clauses at the beginning of the list // Most important clauses at the beginning of the list
// will still be sent and used to pre-sort so the local // will still be sent and used to pre-sort so the local
// CPU can use its cycles for fine-tuning. // CPU can use its cycles for fine-tuning.
mOrderByCompiled = false; mOrderByCompiled = false;
break; break;
}
} }
} }
} else
else {
{ mOrderByCompiled = false;
mOrderByCompiled = false; }
}


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


// also need attributes required by order by // also need attributes required by order by
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() ) if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
QSet<int> attributeIndexes;
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
{ {
attributeIndexes << mSource->mFields.lookupField( attr ); QSet<int> attributeIndexes;
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
{
attributeIndexes << mSource->mFields.lookupField( attr );
}
attributeIndexes += mRequest.subsetOfAttributes().toSet();
mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
} }
attributeIndexes += mRequest.subsetOfAttributes().toSet();
mRequest.setSubsetOfAttributes( attributeIndexes.toList() );
}


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


if ( !success ) if ( !success )
{ {
// some error occurred // some error occurred
sqliteStatement = nullptr; sqliteStatement = nullptr;
close(); close();
}
} }
} }


Expand Down

0 comments on commit 86b28ff

Please sign in to comment.