Skip to content
Permalink
Browse files

Speed up spatialite provider

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 86b28ff39eec6d264a6bd6e6eee190efdc390869
Showing with 66 additions and 60 deletions.
  1. +66 −60 src/providers/spatialite/qgsspatialitefeatureiterator.cpp
@@ -53,7 +53,7 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
catch ( QgsCsException & )
{
// can't reproject mFilterRect
mClosed = true;
close();
return;
}

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

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

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

mOrderByCompiled = true;
mOrderByCompiled = true;

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

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

part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC";
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;
part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC";
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
{
mOrderByCompiled = false;
}
else
{
mOrderByCompiled = false;
}

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

// also need attributes required by order by
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
QSet<int> attributeIndexes;
Q_FOREACH ( const QString &attr, mRequest.orderBy().usedAttributes() )
// also need attributes required by order by
if ( !mOrderByCompiled && mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.orderBy().isEmpty() )
{
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
bool success = prepareStatement( whereClause, limitAtProvider ? mRequest.limit() : -1, orderByParts.join( QStringLiteral( "," ) ) );
if ( !success && useFallbackWhereClause )
{
//try with the fallback where clause, e.g., for cases when using compiled expression failed to prepare
mExpressionCompiled = false;
success = prepareStatement( fallbackWhereClause, -1, orderByParts.join( QStringLiteral( "," ) ) );
}
// preparing the SQL statement
bool success = prepareStatement( whereClause, limitAtProvider ? mRequest.limit() : -1, orderByParts.join( QStringLiteral( "," ) ) );
if ( !success && useFallbackWhereClause )
{
//try with the fallback where clause, e.g., for cases when using compiled expression failed to prepare
mExpressionCompiled = false;
success = prepareStatement( fallbackWhereClause, -1, orderByParts.join( QStringLiteral( "," ) ) );
}

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

0 comments on commit 86b28ff

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