Skip to content

Commit 233a809

Browse files
committedJul 6, 2021
Add rowCount to connections API
+ fix memory leak in API fetcher + add progress bar to result widget
1 parent 357fa9c commit 233a809

21 files changed

+151
-34
lines changed
 

‎python/core/auto_generated/providers/qgsabstractdatabaseproviderconnection.sip.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ Returns the number of fetched rows.
8989
.. seealso:: :py:func:`rowCount`
9090
%End
9191

92+
qlonglong rowCount( ) const;
93+
%Docstring
94+
Returns the number of rows returned by a SELECT query or -1 if unknown
95+
96+
.. seealso:: :py:func:`fetchedRowCount`
97+
%End
98+
9299

93100
// Python iterator
94101
QueryResult *__iter__();

‎src/core/providers/ogr/qgsgeopackageproviderconnection.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <QTextCodec>
3030

3131

32+
///@cond PRIVATE
33+
3234
QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString &name )
3335
: QgsAbstractDatabaseProviderConnection( name )
3436
{
@@ -616,6 +618,11 @@ bool QgsGeoPackageProviderResultIterator::hasNextRowPrivate() const
616618
return ! mNextRow.isEmpty();
617619
}
618620

621+
qlonglong QgsGeoPackageProviderResultIterator::rowCountPrivate() const
622+
{
623+
return mRowCount;
624+
}
625+
619626
void QgsGeoPackageProviderResultIterator::setFields( const QgsFields &fields )
620627
{
621628
mFields = fields;
@@ -1153,10 +1160,23 @@ QMap<QgsAbstractDatabaseProviderConnection::SqlKeywordCategory, QStringList> Qgs
11531160
} );
11541161
}
11551162

1163+
QgsGeoPackageProviderResultIterator::QgsGeoPackageProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer )
1164+
: mHDS( std::move( hDS ) )
1165+
, mOgrLayer( ogrLayer )
1166+
{
1167+
if ( mOgrLayer )
1168+
{
1169+
// Do not scan the layer!
1170+
mRowCount = OGR_L_GetFeatureCount( mOgrLayer, false );
1171+
}
1172+
}
1173+
11561174
QgsGeoPackageProviderResultIterator::~QgsGeoPackageProviderResultIterator()
11571175
{
11581176
if ( mHDS )
11591177
{
11601178
GDALDatasetReleaseResultSet( mHDS.get(), mOgrLayer );
11611179
}
11621180
}
1181+
1182+
///@endcond

‎src/core/providers/ogr/qgsgeopackageproviderconnection.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@
2828
struct QgsGeoPackageProviderResultIterator: public QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator
2929
{
3030

31-
QgsGeoPackageProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer )
32-
: mHDS( std::move( hDS ) )
33-
, mOgrLayer( ogrLayer )
34-
{}
31+
QgsGeoPackageProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer );
3532

3633
~QgsGeoPackageProviderResultIterator();
3734

@@ -47,10 +44,12 @@ struct QgsGeoPackageProviderResultIterator: public QgsAbstractDatabaseProviderCo
4744
QVariantList mNextRow;
4845
QString mGeometryColumnName;
4946
QString mPrimaryKeyColumnName;
47+
qlonglong mRowCount = -1;
5048

5149
QVariantList nextRowPrivate() override;
52-
QVariantList nextRowInternal();
5350
bool hasNextRowPrivate() const override;
51+
qlonglong rowCountPrivate() const override;
52+
QVariantList nextRowInternal();
5453

5554
};
5655

‎src/core/providers/qgsabstractdatabaseproviderconnection.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,15 @@ qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::fetchedRowCount()
14381438
return mResultIterator->fetchedRowCount();
14391439
}
14401440

1441+
qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::rowCount() const
1442+
{
1443+
if ( ! mResultIterator )
1444+
{
1445+
return -1;
1446+
}
1447+
return mResultIterator->rowCount();
1448+
}
1449+
14411450

14421451
bool QgsAbstractDatabaseProviderConnection::QueryResult::hasNextRow() const
14431452
{
@@ -1482,5 +1491,11 @@ qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterato
14821491
return mFetchedRowCount;
14831492
}
14841493

1494+
qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::rowCount()
1495+
{
1496+
QMutexLocker lock( &mMutex );
1497+
return rowCountPrivate();
1498+
}
1499+
14851500

14861501
///@endcond private

‎src/core/providers/qgsabstractdatabaseproviderconnection.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
119119
*/
120120
qlonglong fetchedRowCount( ) const;
121121

122+
/**
123+
* Returns the number of rows returned by a SELECT query or -1 if unknown
124+
*
125+
* \see fetchedRowCount()
126+
*/
127+
qlonglong rowCount( ) const;
128+
122129

123130
#ifdef SIP_RUN
124131
// Python iterator
@@ -154,15 +161,26 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
154161
*/
155162
struct CORE_EXPORT QueryResultIterator SIP_SKIP
156163
{
164+
//! Returns the next result row
157165
QVariantList nextRow();
166+
167+
//! Returns TRUE if there is another row to fetch
158168
bool hasNextRow() const;
169+
170+
//! Returns the number of actually fetched rows
159171
qlonglong fetchedRowCount();
172+
173+
//! Returns the total number of rows returned by a SELECT query or -1 if this is not known.
174+
qlonglong rowCount();
175+
160176
virtual ~QueryResultIterator() = default;
161177

162178
private:
163179

164180
virtual QVariantList nextRowPrivate() = 0;
165181
virtual bool hasNextRowPrivate() const = 0;
182+
virtual qlonglong rowCountPrivate() const = 0;
183+
166184
mutable qlonglong mFetchedRowCount = 0;
167185
mutable QMutex mMutex;
168186

‎src/core/qgsqueryresultmodel.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ QgsQueryResultModel::QgsQueryResultModel( const QgsAbstractDatabaseProviderConne
2121
, mColumns( queryResult.columns() )
2222
{
2323
qRegisterMetaType< QList<QList<QVariant>>>( "QList<QList<QVariant>>" );
24-
mWorker = new QgsQueryResultFetcher( &mQueryResult );
24+
mWorker = std::make_unique<QgsQueryResultFetcher>( &mQueryResult );
2525
mWorker->moveToThread( &mWorkerThread );
26-
connect( &mWorkerThread, &QThread::started, mWorker, &QgsQueryResultFetcher::fetchRows );
27-
connect( mWorker, &QgsQueryResultFetcher::rowsReady, this, &QgsQueryResultModel::rowsReady );
28-
// Forward signal
29-
connect( mWorker, &QgsQueryResultFetcher::fetchingComplete, this, &QgsQueryResultModel::fetchingComplete );
26+
connect( &mWorkerThread, &QThread::started, mWorker.get(), &QgsQueryResultFetcher::fetchRows );
27+
// Forward signals to the model
28+
connect( mWorker.get(), &QgsQueryResultFetcher::rowsReady, this, &QgsQueryResultModel::rowsReady );
29+
connect( mWorker.get(), &QgsQueryResultFetcher::fetchingComplete, this, &QgsQueryResultModel::fetchingComplete );
3030
mWorkerThread.start();
3131
}
3232

@@ -57,7 +57,6 @@ QgsQueryResultModel::~QgsQueryResultModel()
5757
mWorker->stopFetching();
5858
mWorkerThread.quit();
5959
mWorkerThread.wait();
60-
mWorker->deleteLater();
6160
}
6261
else
6362
{

‎src/core/qgsqueryresultmodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class CORE_EXPORT QgsQueryResultModel : public QAbstractTableModel
122122
QgsAbstractDatabaseProviderConnection::QueryResult mQueryResult;
123123
QStringList mColumns;
124124
QThread mWorkerThread;
125-
QgsQueryResultFetcher *mWorker = nullptr;
125+
std::unique_ptr<QgsQueryResultFetcher> mWorker;
126126
QList<QVariantList> mRows;
127127

128128
};

‎src/gui/qgsqueryresultwidget.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ void QgsQueryResultWidget::cancelApiFetcher()
219219
mApiFetcher->stopFetching();
220220
mApiFetcherWorkerThread.quit();
221221
mApiFetcherWorkerThread.wait();
222-
mApiFetcherWorkerThread.deleteLater();
223222
}
224223
}
225224

@@ -250,10 +249,19 @@ void QgsQueryResultWidget::startFetching()
250249
mQueryResultsTableView->show();
251250
updateButtons();
252251
updateSqlLayerColumns( );
252+
mActualRowCount = result.rowCount();
253+
if ( mActualRowCount != -1 )
254+
{
255+
mProgressBar->setRange( 0, mActualRowCount );
256+
}
253257
}
254258
mStatusLabel->setText( tr( "Fetched rows: %1 %2" )
255259
.arg( mModel->rowCount( mModel->index( -1, -1 ) ) )
256260
.arg( mWasCanceled ? tr( "(stopped)" ) : QString() ) );
261+
if ( mActualRowCount != -1 )
262+
{
263+
mProgressBar->setValue( mModel->rowCount( mModel->index( -1, -1 ) ) );
264+
}
257265
} );
258266

259267
mQueryResultsTableView->setModel( mModel.get() );
@@ -356,6 +364,11 @@ void QgsQueryResultWidget::setConnection( QgsAbstractDatabaseProviderConnection
356364
mApiFetcher = nullptr;
357365
} );
358366
connect( mApiFetcher, &QgsConnectionsApiFetcher::tokensReady, this, &QgsQueryResultWidget::tokensReady );
367+
connect( mApiFetcher, &QgsConnectionsApiFetcher::fetchingFinished, &mApiFetcherWorkerThread, [ = ]
368+
{
369+
mApiFetcherWorkerThread.quit();
370+
mApiFetcherWorkerThread.wait();
371+
} );
359372
mApiFetcherWorkerThread.start();
360373
}
361374

‎src/gui/qgsqueryresultwidget.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ class GUI_EXPORT QgsConnectionsApiFetcher: public QObject
4040

4141
public:
4242

43-
//! Constructs a result fetcher from \a queryResult.
44-
QgsConnectionsApiFetcher( const QgsAbstractDatabaseProviderConnection *conn )
45-
: mConnection( conn )
43+
//! Constructs a result fetcher from \a connection.
44+
QgsConnectionsApiFetcher( const QgsAbstractDatabaseProviderConnection *connection )
45+
: mConnection( connection )
4646
{}
4747

4848
//! Start fetching
@@ -155,6 +155,7 @@ class GUI_EXPORT QgsQueryResultWidget: public QWidget, private Ui::QgsQueryResul
155155
bool mFirstRowFetched = false;
156156
QFutureWatcher<QgsAbstractDatabaseProviderConnection::QueryResult> mQueryResultWatcher;
157157
QString mSqlErrorMessage;
158+
qlonglong mActualRowCount = -1;
158159

159160
/**
160161
* Updates buttons status.

‎src/providers/hana/qgshanaproviderconnection.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ bool QgsHanaProviderResultIterator::hasNextRowPrivate() const
5252
return mNextRow;
5353
}
5454

55+
qlonglong QgsHanaProviderResultIterator::rowCountPrivate() const
56+
{
57+
// TODO: hana team, this is for you.
58+
return -1;
59+
}
60+
5561
QgsHanaProviderConnection::QgsHanaProviderConnection( const QString &name )
5662
: QgsAbstractDatabaseProviderConnection( name )
5763
{

‎src/providers/hana/qgshanaproviderconnection.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ struct QgsHanaEmptyProviderResultIterator: public QgsAbstractDatabaseProviderCon
2525
{
2626
// QueryResultIterator interface
2727
private:
28-
QVariantList nextRowPrivate();
29-
bool hasNextRowPrivate() const;
28+
QVariantList nextRowPrivate() override;
29+
bool hasNextRowPrivate() const override;
30+
qlonglong rowCountPrivate() const override { return 0; };
3031
};
3132

3233
struct QgsHanaProviderResultIterator: public QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator
@@ -40,8 +41,9 @@ struct QgsHanaProviderResultIterator: public QgsAbstractDatabaseProviderConnecti
4041

4142
// QueryResultIterator interface
4243
private:
43-
QVariantList nextRowPrivate();
44-
bool hasNextRowPrivate() const;
44+
QVariantList nextRowPrivate() override;
45+
bool hasNextRowPrivate() const override;
46+
qlonglong rowCountPrivate() const override;
4547
};
4648

4749
class QgsHanaConnectionRef;

‎src/providers/mssql/qgsmssqlproviderconnection.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ QVariantList QgssMssqlProviderResultIterator::nextRowInternal()
331331
return row;
332332
}
333333

334+
qlonglong QgssMssqlProviderResultIterator::rowCountPrivate() const
335+
{
336+
return mQuery.size();
337+
}
338+
334339

335340
QList<QgsMssqlProviderConnection::TableProperty> QgsMssqlProviderConnection::tables( const QString &schema, const TableFlags &flags ) const
336341
{

‎src/providers/mssql/qgsmssqlproviderconnection.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct QgssMssqlProviderResultIterator: public QgsAbstractDatabaseProviderConnec
3939

4040
QVariantList nextRowInternal();
4141

42+
43+
// QueryResultIterator interface
44+
qlonglong rowCountPrivate() const override;
4245
};
4346

4447
class QgsMssqlProviderConnection : public QgsAbstractDatabaseProviderConnection

‎src/providers/oracle/qgsoracleproviderconnection.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,11 @@ QVariantList QgsOracleProviderResultIterator::nextRowInternal()
14071407
return row;
14081408
}
14091409

1410+
qlonglong QgsOracleProviderResultIterator::rowCountPrivate() const
1411+
{
1412+
return mQuery.size();
1413+
}
1414+
14101415
void QgsOracleProviderConnection::createVectorTable( const QString &schema,
14111416
const QString &name,
14121417
const QgsFields &fields,

‎src/providers/oracle/qgsoracleproviderconnection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct QgsOracleProviderResultIterator: public QgsAbstractDatabaseProviderConnec
3737
QVariantList mNextRow;
3838

3939
QVariantList nextRowInternal();
40-
40+
qlonglong rowCountPrivate() const override;
4141
};
4242

4343
class QgsOracleProviderConnection : public QgsAbstractDatabaseProviderConnection

‎src/providers/postgres/qgspostgresproviderconnection.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ bool QgsPostgresProviderResultIterator::hasNextRowPrivate() const
427427
return result && mRowIndex < result->PQntuples();
428428
}
429429

430+
qlonglong QgsPostgresProviderResultIterator::rowCountPrivate() const
431+
{
432+
return result ? result->PQntuples() : -1;
433+
}
434+
430435

431436
void QgsPostgresProviderConnection::vacuum( const QString &schema, const QString &name ) const
432437
{

‎src/providers/postgres/qgspostgresproviderconnection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ struct QgsPostgresProviderResultIterator: public QgsAbstractDatabaseProviderConn
3232

3333
QVariantList nextRowPrivate() override;
3434
bool hasNextRowPrivate() const override;
35+
qlonglong rowCountPrivate() const override;
3536

3637
bool mResolveTypes = true;
3738
std::shared_ptr<QgsPoolPostgresConn> mConn;
3839
qlonglong mRowIndex = 0;
39-
4040
};
4141

4242
class QgsPostgresProviderConnection : public QgsAbstractDatabaseProviderConnection

‎src/providers/spatialite/qgsspatialiteproviderconnection.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,17 @@ void QgsSpatialiteProviderResultIterator::setFields( const QgsFields &fields )
554554
}
555555

556556

557+
QgsSpatialiteProviderResultIterator::QgsSpatialiteProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer )
558+
: mHDS( std::move( hDS ) )
559+
, mOgrLayer( ogrLayer )
560+
{
561+
if ( mOgrLayer )
562+
{
563+
// Do not scan the layer!
564+
mRowCount = OGR_L_GetFeatureCount( mOgrLayer, false );
565+
}
566+
}
567+
557568
QgsSpatialiteProviderResultIterator::~QgsSpatialiteProviderResultIterator()
558569
{
559570
if ( mHDS )
@@ -611,6 +622,11 @@ QVariantList QgsSpatialiteProviderResultIterator::nextRowInternal()
611622
return row;
612623
}
613624

625+
qlonglong QgsSpatialiteProviderResultIterator::rowCountPrivate() const
626+
{
627+
return mRowCount;
628+
}
629+
614630

615631
void QgsSpatialiteProviderResultIterator::setGeometryColumnName( const QString &geometryColumnName )
616632
{

‎src/providers/spatialite/qgsspatialiteproviderconnection.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@
2525

2626
struct QgsSpatialiteProviderResultIterator: public QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator
2727
{
28-
QgsSpatialiteProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer )
29-
: mHDS( std::move( hDS ) )
30-
, mOgrLayer( ogrLayer )
31-
{}
28+
QgsSpatialiteProviderResultIterator( gdal::ogr_datasource_unique_ptr hDS, OGRLayerH ogrLayer );
3229

3330
~QgsSpatialiteProviderResultIterator();
3431

@@ -47,6 +44,11 @@ struct QgsSpatialiteProviderResultIterator: public QgsAbstractDatabaseProviderCo
4744
QVariantList nextRowPrivate() override;
4845
bool hasNextRowPrivate() const override;
4946
QVariantList nextRowInternal();
47+
48+
// QueryResultIterator interface
49+
private:
50+
qlonglong rowCountPrivate() const override;
51+
qlonglong mRowCount = -1;
5052
};
5153

5254

‎src/ui/qgsqueryresultwidgetbase.ui

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<widget class="QgsCodeEditorSQL" name="mSqlEditor" native="true"/>
2222
</item>
2323
<item>
24-
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,2,0,1,1">
24+
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,1,0,0">
2525
<item>
2626
<widget class="QPushButton" name="mClearButton">
2727
<property name="text">
@@ -36,13 +36,6 @@
3636
</property>
3737
</widget>
3838
</item>
39-
<item>
40-
<widget class="QProgressBar" name="mProgressBar">
41-
<property name="value">
42-
<number>24</number>
43-
</property>
44-
</widget>
45-
</item>
4639
<item>
4740
<spacer name="horizontalSpacer">
4841
<property name="orientation">
@@ -56,6 +49,13 @@
5649
</property>
5750
</spacer>
5851
</item>
52+
<item>
53+
<widget class="QProgressBar" name="mProgressBar">
54+
<property name="value">
55+
<number>24</number>
56+
</property>
57+
</widget>
58+
</item>
5959
<item>
6060
<widget class="QPushButton" name="mExecuteButton">
6161
<property name="enabled">

‎tests/src/python/test_qgsproviderconnection_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ def _test_operations(self, md, conn):
273273

274274
# Test column names
275275
res = conn.execSql(sql)
276+
self.assertEqual(res.rowCount(), 1)
276277
rows = res.rows()
277278
self.assertEqual(rows, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, expected_date, QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]])
278279
self.assertEqual(res.columns(), ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t'])

0 commit comments

Comments
 (0)
Please sign in to comment.