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.
This commit is contained in:
Matthias Kuhn 2017-10-24 19:08:14 +02:00
parent 269f751e71
commit 86b28ff39e

View File

@ -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 " ) );
// Setup the order by
QStringList orderByParts;
mOrderByCompiled = true;
if ( QgsSettings().value( QStringLiteral( "qgis/compileExpressions" ), true ).toBool() )
if ( !mClosed )
{
Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
{
QgsSQLiteExpressionCompiler compiler = QgsSQLiteExpressionCompiler( source->mFields );
QgsExpression expression = clause.expression();
if ( compiler.compile( &expression ) == QgsSqlExpressionCompiler::Complete )
{
QString part;
part = compiler.result();
whereClause = whereClauses.join( QStringLiteral( " AND " ) );
if ( clause.nullsFirst() )
orderByParts << QStringLiteral( "%1 IS NOT NULL" ).arg( part );
// Setup the order by
QStringList orderByParts;
mOrderByCompiled = true;
if ( QgsSettings().value( QStringLiteral( "qgis/compileExpressions" ), true ).toBool() )
{
Q_FOREACH ( const QgsFeatureRequest::OrderByClause &clause, request.orderBy() )
{
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 );
part += clause.ascending() ? " COLLATE NOCASE ASC" : " COLLATE NOCASE DESC";
orderByParts << 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;
{
// 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;
}
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() )
else
{
attributeIndexes << mSource->mFields.lookupField( attr );
mOrderByCompiled = false;
}
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( "," ) ) );
}
if ( !mOrderByCompiled )
limitAtProvider = false;
if ( !success )
{
// some error occurred
sqliteStatement = nullptr;
close();
// 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() )
{
attributeIndexes << mSource->mFields.lookupField( attr );
}
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( "," ) ) );
}
if ( !success )
{
// some error occurred
sqliteStatement = nullptr;
close();
}
}
}