Skip to content

Commit

Permalink
Removed sophisticated implementation
Browse files Browse the repository at this point in the history
Store rows in the model, remove rewind and random access from
query result class.

This implementation is way simpler but the (forward) iterator
can be used only once.

I'm still convinced that the old implementation was better and more
flexible but I need to move forward.

Client code will need to store the results from the iterator.
  • Loading branch information
elpaso committed Jan 13, 2021
1 parent 3ab4497 commit 337c7c3
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 236 deletions.
Expand Up @@ -47,39 +47,21 @@ is not supported or cannot be performed without errors.

struct QueryResult
{
SIP_PYOBJECT __repr__();
%MethodCode
const qlonglong rowCount = sipCpp->rowCount();
const QString str = QStringLiteral( "<QgsAbstractDatabaseProviderConnection.QueryResult: %1 rows>" ).arg( rowCount > -1 ? QString::number( rowCount ) : QStringLiteral( "unknown" ) );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End

QStringList columns() const;
%Docstring
Returns the column names
%End

QList<QList<QVariant> > rows( QgsFeedback *feedback = 0 ) const;
QList<QList<QVariant> > rows( QgsFeedback *feedback = 0 );
%Docstring
Returns the result rows by calling the iterator internally and fetching
all the rows, an optional ``feedback`` can be used to interrupt the fetching loop.

.. note::

results are cached internally and subsequent calls to this method
will return the cached results.
%End

qlonglong rowCount() const;
%Docstring
Returns the maximum value between the estimated row count (this value may not be exact or
it may be -1 if not known) and the actual number of fetched rows

.. note::

When all the results have been retrieved returns the actual number of rows

.. seealso:: :py:func:`fetchedRowCount`
calling this function more than one time is not supported: the second
call will always return an empty list.
%End

bool hasNextRow() const;
Expand All @@ -98,16 +80,6 @@ Returns the next result row or an empty row if there are no rows left
.. seealso:: :py:func:`hasNextRow`

.. seealso:: :py:func:`rewind`
%End

void rewind();
%Docstring
Resets the internal iterator counter, the next call to :py:func:`~QgsAbstractDatabaseProviderConnection.nextRow`
will return the first row (if any)

.. seealso:: :py:func:`hasNextRow`

.. seealso:: :py:func:`nextRow`
%End

qlonglong fetchedRowCount( ) const;
Expand All @@ -117,14 +89,6 @@ Returns the number of fetched rows
.. seealso:: :py:func:`rowCount`
%End

QList<QVariant> at( qlonglong index ) const;
%Docstring
Returns the row at 0-based index ``index``, if index is not valid, an empty row is returned

.. note::

this method calls the iterator internally until ``index`` row is retrieved
%End

// Python iterator
QueryResult *__iter__();
Expand Down Expand Up @@ -155,7 +119,6 @@ Returns the row at 0-based index ``index``, if index is not valid, an empty row




};


Expand Down
4 changes: 2 additions & 2 deletions python/core/auto_generated/qgsqueryresultmodel.sip.in
Expand Up @@ -44,9 +44,9 @@ Constructs a QgsQueryResultModel from a ``queryResult`` with optional ``parent``

public slots:

void newRowsReady( int newRowsCount );
void rowsReady( const QList<QList<QVariant> > &rows );
%Docstring
Triggered when ``newRowsCount`` have been fetched and can be added to the model
Triggered when ``newRows`` have been fetched and can be added to the model
%End

};
Expand Down
4 changes: 0 additions & 4 deletions src/core/providers/ogr/qgsgeopackageproviderconnection.cpp
Expand Up @@ -380,10 +380,6 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti

auto iterator = std::make_shared<QgsGeoPackageProviderResultIterator>( std::move( hDS ), ogrLayer );
QgsAbstractDatabaseProviderConnection::QueryResult results( iterator );
// Note: Returns the number of features in the layer. For dynamic databases the count may not be exact.
// If bForce is FALSE, and it would be expensive to establish the feature count a value of -1 may
// be returned indicating that the count isn’t know.
results.setRowCount( OGR_L_GetFeatureCount( ogrLayer, 0 /* bForce=false: do not scan the whole layer */ ) );

gdal::ogr_feature_unique_ptr fet;
if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet )
Expand Down
69 changes: 12 additions & 57 deletions src/core/qgsabstractdatabaseproviderconnection.cpp
Expand Up @@ -444,12 +444,10 @@ QStringList QgsAbstractDatabaseProviderConnection::QueryResult::columns() const
return mColumns;
}

QList<QList<QVariant> > QgsAbstractDatabaseProviderConnection::QueryResult::rows( QgsFeedback *feedback ) const
QList<QList<QVariant> > QgsAbstractDatabaseProviderConnection::QueryResult::rows( QgsFeedback *feedback )
{
if ( ! mResultIterator )
{
return QList<QList<QVariant> >();
}

QList<QList<QVariant> > rows;

while ( mResultIterator &&
mResultIterator->hasNextRow() &&
Expand All @@ -460,8 +458,12 @@ QList<QList<QVariant> > QgsAbstractDatabaseProviderConnection::QueryResult::rows
{
break;
}
else
{
rows.push_back( row );
}
}
return mResultIterator->rows();
return rows;
}

QList<QVariant> QgsAbstractDatabaseProviderConnection::QueryResult::nextRow() const
Expand All @@ -470,13 +472,9 @@ QList<QVariant> QgsAbstractDatabaseProviderConnection::QueryResult::nextRow() co
{
return QList<QVariant>();
}
return at( mIteratorCounter++ );
return mResultIterator->nextRow();
}

void QgsAbstractDatabaseProviderConnection::QueryResult::rewind()
{
mIteratorCounter = 0;
}

qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::fetchedRowCount() const
{
Expand All @@ -487,58 +485,21 @@ qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::fetchedRowCount()
return mResultIterator->fetchedRowCount();
}

QList<QVariant> QgsAbstractDatabaseProviderConnection::QueryResult::at( qlonglong index ) const
{
if ( index < 0 || ! mResultIterator )
{
return QList<QVariant>();
}

// Fetch rows until the index
while ( index >= mResultIterator->fetchedRowCount() )
{
if ( mResultIterator->nextRow().isEmpty() )
{
break;
}
}

if ( index >= mResultIterator->fetchedRowCount() )
{
return QList<QVariant>();
}

return mResultIterator->rows().at( index );
}


qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::rowCount() const
{
if ( mResultIterator )
{
return std::max( mResultIterator->fetchedRowCount(), mRowCount );
}
return mRowCount;
}

bool QgsAbstractDatabaseProviderConnection::QueryResult::hasNextRow() const
{
if ( ! mResultIterator )
{
return false;
}
return ! at( mIteratorCounter ).isEmpty();
return mResultIterator->hasNextRow();
}

void QgsAbstractDatabaseProviderConnection::QueryResult::appendColumn( const QString &columnName )
{
mColumns.push_back( columnName );
}

void QgsAbstractDatabaseProviderConnection::QueryResult::setRowCount( const qlonglong &rowCount )
{
mRowCount = rowCount;
}

QgsAbstractDatabaseProviderConnection::QueryResult::QueryResult( std::shared_ptr<QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator> iterator )
: mResultIterator( iterator )
Expand All @@ -551,7 +512,7 @@ QVariantList QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIter
const QVariantList row { nextRowPrivate() };
if ( ! row.isEmpty() )
{
mRows.push_back( row );
mFetchedRowCount++;
}
return row;
}
Expand All @@ -565,13 +526,7 @@ bool QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::ha
qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::fetchedRowCount()
{
QMutexLocker lock( &mMutex );
return mRows.count();
}

QList<QList<QVariant> > QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::rows() const
{
QMutexLocker lock( &mMutex );
return mRows;
return mFetchedRowCount;
}


Expand Down
57 changes: 6 additions & 51 deletions src/core/qgsabstractdatabaseproviderconnection.h
Expand Up @@ -70,28 +70,17 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
/**
* The QueryResult class represents the result of a query executed by execSql()
*
* It encapsulates the result rows and a list of the column names.
* The query result may be empty in case the query returns nothing.
* It encapsulates an iterator over the result rows and a list of the column names.
*
* Rows can be retrieved by iterating over the result with hasNextRow() and nextRow()
* or by calling rows() that will internally iterate over the results and return
* the result list.
* the whole result list.
*
* The list of results is cached internally and subsequent calls to rows() or at() return the
* cached results.
*
* \since QGIS 3.18
*/
struct CORE_EXPORT QueryResult
{
#ifdef SIP_RUN
SIP_PYOBJECT __repr__();
% MethodCode
const qlonglong rowCount = sipCpp->rowCount();
const QString str = QStringLiteral( "<QgsAbstractDatabaseProviderConnection.QueryResult: %1 rows>" ).arg( rowCount > -1 ? QString::number( rowCount ) : QStringLiteral( "unknown" ) );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
% End
#endif

/**
* Returns the column names
Expand All @@ -102,19 +91,10 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* Returns the result rows by calling the iterator internally and fetching
* all the rows, an optional \a feedback can be used to interrupt the fetching loop.
*
* \note results are cached internally and subsequent calls to this method
* will return the cached results.
* \note calling this function more than one time is not supported: the second
* call will always return an empty list.
*/
QList<QList<QVariant> > rows( QgsFeedback *feedback = nullptr ) const;

/**
* Returns the maximum value between the estimated row count (this value may not be exact or
* it may be -1 if not known) and the actual number of fetched rows
*
* \note When all the results have been retrieved returns the actual number of rows
* \see fetchedRowCount()
*/
qlonglong rowCount() const;
QList<QList<QVariant> > rows( QgsFeedback *feedback = nullptr );

/**
* Returns TRUE if there are more rows to fetch
Expand All @@ -132,28 +112,13 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
*/
QList<QVariant> nextRow() const;

/**
* Resets the internal iterator counter, the next call to nextRow()
* will return the first row (if any)
*
* \see hasNextRow()
* \see nextRow()
*/
void rewind();

/**
* Returns the number of fetched rows
*
* \see rowCount()
*/
qlonglong fetchedRowCount( ) const;

/**
* Returns the row at 0-based index \a index, if index is not valid, an empty row is returned
*
* \note this method calls the iterator internally until \a index row is retrieved
*/
QList<QVariant> at( qlonglong index ) const;

#ifdef SIP_RUN
// Python iterator
Expand Down Expand Up @@ -186,31 +151,23 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* The QueryResultIterator struct is an abstract interface for provider query result iterators.
* Providers must implement their own concrete iterator over query results.
*
* \note This struct is thread safe.
*/
struct CORE_EXPORT QueryResultIterator SIP_SKIP
{
QVariantList nextRow();
bool hasNextRow() const;
qlonglong fetchedRowCount();
virtual ~QueryResultIterator() = default;
QList<QList<QVariant> > rows() const;

private:

virtual QVariantList nextRowPrivate() = 0;
virtual bool hasNextRowPrivate() const = 0;
mutable QList<QList<QVariant>> mRows;
mutable qlonglong mFetchedRowCount = 0;
mutable QMutex mMutex;

};

/**
* Sets \a rowCount
* \note Not available in Python bindings
*/
void setRowCount( const qlonglong &rowCount ) SIP_SKIP;

/**
* Appends \a columnName to the list of column names.
* \note Not available in Python bindings
Expand All @@ -235,8 +192,6 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv

mutable std::shared_ptr<QueryResultIterator> mResultIterator;
QStringList mColumns;
qlonglong mRowCount = 0;
mutable qlonglong mIteratorCounter = 0;

};

Expand Down

0 comments on commit 337c7c3

Please sign in to comment.