Address PR comments - part 2

This commit is contained in:
Alessandro Pasotti 2021-07-07 12:43:14 +02:00
parent 78a42cf7e8
commit 878b2436a5
18 changed files with 141 additions and 70 deletions

View File

@ -315,11 +315,11 @@ Qgis.VectorExportResult.__doc__ = 'Vector layer export result codes.\n\n.. versi
# -- # --
Qgis.VectorExportResult.baseClass = Qgis Qgis.VectorExportResult.baseClass = Qgis
# monkey patching scoped based enum # monkey patching scoped based enum
Qgis.SqlLayerDefinitionCapability.Filter.__doc__ = "SQL layer definition supports filter" Qgis.SqlLayerDefinitionCapability.SubsetStringFilter.__doc__ = "SQL layer definition supports subset string filter"
Qgis.SqlLayerDefinitionCapability.GeometryColumn.__doc__ = "SQL layer definition supports geometry column" Qgis.SqlLayerDefinitionCapability.GeometryColumn.__doc__ = "SQL layer definition supports geometry column"
Qgis.SqlLayerDefinitionCapability.PrimaryKeys.__doc__ = "SQL layer definition supports primary keys" Qgis.SqlLayerDefinitionCapability.PrimaryKeys.__doc__ = "SQL layer definition supports primary keys"
Qgis.SqlLayerDefinitionCapability.SelectAtId.__doc__ = "SQL layer definition supports disabling select at id" Qgis.SqlLayerDefinitionCapability.UnstableFeatureIds.__doc__ = "SQL layer definition supports disabling select at id"
Qgis.SqlLayerDefinitionCapability.__doc__ = 'SqlLayerDefinitionCapability enum lists the arguments supported by the provider when creating SQL query layers.\n\n.. versionadded:: 3.22\n\n' + '* ``Filter``: ' + Qgis.SqlLayerDefinitionCapability.Filter.__doc__ + '\n' + '* ``GeometryColumn``: ' + Qgis.SqlLayerDefinitionCapability.GeometryColumn.__doc__ + '\n' + '* ``PrimaryKeys``: ' + Qgis.SqlLayerDefinitionCapability.PrimaryKeys.__doc__ + '\n' + '* ``SelectAtId``: ' + Qgis.SqlLayerDefinitionCapability.SelectAtId.__doc__ Qgis.SqlLayerDefinitionCapability.__doc__ = 'SqlLayerDefinitionCapability enum lists the arguments supported by the provider when creating SQL query layers.\n\n.. versionadded:: 3.22\n\n' + '* ``SubsetStringFilter``: ' + Qgis.SqlLayerDefinitionCapability.SubsetStringFilter.__doc__ + '\n' + '* ``GeometryColumn``: ' + Qgis.SqlLayerDefinitionCapability.GeometryColumn.__doc__ + '\n' + '* ``PrimaryKeys``: ' + Qgis.SqlLayerDefinitionCapability.PrimaryKeys.__doc__ + '\n' + '* ``UnstableFeatureIds``: ' + Qgis.SqlLayerDefinitionCapability.UnstableFeatureIds.__doc__
# -- # --
Qgis.SqlLayerDefinitionCapability.baseClass = Qgis Qgis.SqlLayerDefinitionCapability.baseClass = Qgis
# monkey patching scoped based enum # monkey patching scoped based enum

View File

@ -91,7 +91,7 @@ Returns the number of fetched rows.
long long rowCount( ) const; long long rowCount( ) const;
%Docstring %Docstring
Returns the number of rows returned by a SELECT query or -1 if unknown Returns the number of rows returned by a SELECT query or Qgis.FeatureCountState.UnknownCount if unknown.
.. seealso:: :py:func:`fetchedRowCount` .. seealso:: :py:func:`fetchedRowCount`
%End %End
@ -125,6 +125,16 @@ Returns the number of rows returned by a SELECT query or -1 if unknown
double queryExecutionTime( );
%Docstring
Returns the query execution time in milliseconds.
%End
void setQueryExecutionTime( double queryExecutionTime );
%Docstring
Sets the query execution time to ``queryExecutionTime`` milliseconds.
%End
}; };
@ -135,7 +145,7 @@ Returns the number of rows returned by a SELECT query or -1 if unknown
QString layerName; //!< Optional name for the new layer QString layerName; //!< Optional name for the new layer
QStringList primaryKeyColumns; //!< List of primary key column names QStringList primaryKeyColumns; //!< List of primary key column names
QString geometryColumn; //!< Name of the geometry column QString geometryColumn; //!< Name of the geometry column
bool disableSelectAtId; //!< If SelectAtId is disabled (default is false), not all data providers support this feature: check support with SqlLayerDefinitionCapability::SelectAtId capability bool disableSelectAtId;
}; };
struct TableProperty struct TableProperty
@ -462,7 +472,7 @@ Renames a raster table with given ``schema`` (schema is ignored if not supported
%Docstring %Docstring
Creates a new schema with the specified ``name``. Creates a new schema with the specified ``name``.
:raises QgsProviderConnectionException: :raises QgsProviderConnectionException: if any errors are encountered.
%End %End
virtual void dropSchema( const QString &name, bool force = false ) const throw( QgsProviderConnectionException ); virtual void dropSchema( const QString &name, bool force = false ) const throw( QgsProviderConnectionException );
@ -523,7 +533,7 @@ Raises a :py:class:`QgsProviderConnectionException` if any errors are encountere
it is responsibility of the caller to handle open layers and registry entries. it is responsibility of the caller to handle open layers and registry entries.
:raises QgsProviderConnectionException: :raises QgsProviderConnectionException: if any errors are encountered.
%End %End
virtual QList<QList<QVariant>> executeSql( const QString &sql, QgsFeedback *feedback = 0 ) const throw( QgsProviderConnectionException ); virtual QList<QList<QVariant>> executeSql( const QString &sql, QgsFeedback *feedback = 0 ) const throw( QgsProviderConnectionException );
@ -538,9 +548,8 @@ Executes raw ``sql`` and returns the (possibly empty) list of results in a multi
virtual QgsVectorLayer *createSqlVectorLayer( const SqlVectorLayerOptions &options ) const throw( QgsProviderConnectionException ) /Factory/; virtual QgsVectorLayer *createSqlVectorLayer( const SqlVectorLayerOptions &options ) const throw( QgsProviderConnectionException ) /Factory/;
%Docstring %Docstring
Creates and returns a (possibly invalid) vector layer based on the ``sql`` statement and optional ``options``. Creates and returns a (possibly invalid) vector layer based on the ``sql`` statement and optional ``options``.
Raises a :py:class:`QgsProviderConnectionException` if any errors are encountered or if SQL layer creation is not supported.
:raises QgsProviderConnectionException: :raises QgsProviderConnectionException: if any errors are encountered or if SQL layer creation is not supported.
.. versionadded:: 3.22 .. versionadded:: 3.22
%End %End
@ -638,7 +647,7 @@ Returns the fields of a ``table`` and ``schema``.
behavior when the layer does not expose all fields (GPKG for example hides geometry behavior when the layer does not expose all fields (GPKG for example hides geometry
and primary key column). and primary key column).
:raises QgsProviderConnectionException: :raises QgsProviderConnectionException: if any errors are encountered.
.. versionadded:: 3.16 .. versionadded:: 3.16
%End %End
@ -647,7 +656,7 @@ Returns the fields of a ``table`` and ``schema``.
%Docstring %Docstring
Returns a list of native types supported by the connection. Returns a list of native types supported by the connection.
:raises QgsProviderConnectionException: :raises QgsProviderConnectionException: if any errors are encountered.
.. versionadded:: 3.16 .. versionadded:: 3.16
%End %End

View File

@ -228,12 +228,11 @@ The development version
enum class SqlLayerDefinitionCapability enum class SqlLayerDefinitionCapability
{ {
Filter, SubsetStringFilter,
GeometryColumn, GeometryColumn,
PrimaryKeys, PrimaryKeys,
SelectAtId UnstableFeatureIds
}; };
typedef QFlags<Qgis::SqlLayerDefinitionCapability> SqlLayerDefinitionCapabilities; typedef QFlags<Qgis::SqlLayerDefinitionCapability> SqlLayerDefinitionCapabilities;
@ -250,7 +249,6 @@ The development version
Identifier Identifier
}; };
enum class DriveType enum class DriveType
{ {
Unknown, Unknown,
@ -387,6 +385,8 @@ QFlags<Qgis::BrowserItemCapability> operator|(Qgis::BrowserItemCapability f1, QF
QFlags<Qgis::SublayerQueryFlag> operator|(Qgis::SublayerQueryFlag f1, QFlags<Qgis::SublayerQueryFlag> f2); QFlags<Qgis::SublayerQueryFlag> operator|(Qgis::SublayerQueryFlag f1, QFlags<Qgis::SublayerQueryFlag> f2);
QFlags<Qgis::SqlLayerDefinitionCapability> operator|(Qgis::SqlLayerDefinitionCapability f1, QFlags<Qgis::SqlLayerDefinitionCapability> f2);

View File

@ -65,7 +65,7 @@ Returns the query result
void rowsReady( const QList<QList<QVariant> > &rows ); void rowsReady( const QList<QList<QVariant> > &rows );
%Docstring %Docstring
Triggered when ``newRows`` have been fetched and can be added to the model Triggered when ``newRows`` have been fetched and can be added to the model.
%End %End
void cancel(); void cancel();
@ -78,14 +78,17 @@ Cancels the row fetching.
void fetchingComplete(); void fetchingComplete();
%Docstring %Docstring
Emitted when all rows have been fetched or when the fetching has been stopped (canceled) Emitted when rows have been fetched (all of them or a batch if `maxRows` was passed to :py:func:`~QgsQueryResultModel.fetchMoreRows` )
or when the fetching has been stopped (canceled).
.. seealso:: :py:func:`fetchMoreRows`
%End %End
void fetchMoreRows( qlonglong maxRows ); void fetchMoreRows( qlonglong maxRows );
%Docstring %Docstring
Emitted when more rows are requested Emitted when more rows are requested.
:param maxRows: the number of rows that will be fetched :param maxRows: the number of rows that will be fetched.
%End %End
void fetchingStarted(); void fetchingStarted();

View File

@ -1065,7 +1065,7 @@ void QgsDatabaseItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *
// SQL dialog // SQL dialog
if ( std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( item->databaseConnection() ); conn && conn->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::ExecuteSql ) ) if ( std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( item->databaseConnection() ); conn && conn->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::ExecuteSql ) )
{ {
QAction *sqlAction = new QAction( QObject::tr( "Run SQL command" ), menu ); QAction *sqlAction = new QAction( QObject::tr( "Execute SQL " ), menu );
QObject::connect( sqlAction, &QAction::triggered, item, [ item, context ] QObject::connect( sqlAction, &QAction::triggered, item, [ item, context ]
{ {
@ -1082,7 +1082,7 @@ void QgsDatabaseItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *
QgsDialog dialog; QgsDialog dialog;
dialog.setObjectName( QStringLiteral( "SQLCommandsDialog" ) ); dialog.setObjectName( QStringLiteral( "SQLCommandsDialog" ) );
dialog.setWindowTitle( tr( "%1 — Run SQL Commands" ).arg( item->name() ) ); dialog.setWindowTitle( tr( "%1 — Execute SQL" ).arg( item->name() ) );
// If this is a layer item (or below the hierarchy) we can pre-set the query to something // If this is a layer item (or below the hierarchy) we can pre-set the query to something
// meaningful // meaningful

View File

@ -22,6 +22,7 @@
#include "qgsogrprovider.h" #include "qgsogrprovider.h"
#include "qgsmessagelog.h" #include "qgsmessagelog.h"
#include "qgsproviderregistry.h" #include "qgsproviderregistry.h"
#include "qgsprovidermetadata.h"
#include "qgsapplication.h" #include "qgsapplication.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsfeedback.h" #include "qgsfeedback.h"
@ -29,6 +30,8 @@
#include <QTextCodec> #include <QTextCodec>
#include <QRegularExpression> #include <QRegularExpression>
#include <chrono>
///@cond PRIVATE ///@cond PRIVATE
QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString &name ) QgsGeoPackageProviderConnection::QgsGeoPackageProviderConnection( const QString &name )
@ -176,7 +179,11 @@ void QgsGeoPackageProviderConnection::renameVectorTable( const QString &schema,
QgsVectorLayer *QgsGeoPackageProviderConnection::createSqlVectorLayer( const QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions &options ) const QgsVectorLayer *QgsGeoPackageProviderConnection::createSqlVectorLayer( const QgsAbstractDatabaseProviderConnection::SqlVectorLayerOptions &options ) const
{ {
return new QgsVectorLayer( QStringLiteral( "%1|subset=%2" ).arg( uri(), options.sql ), options.layerName.isEmpty() ? QStringLiteral( "QueryLayer" ) : options.layerName, providerKey() ); QgsProviderMetadata *providerMetadata { QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) ) };
Q_ASSERT( providerMetadata );
QMap<QString, QVariant> decoded = providerMetadata->decodeUri( uri() );
decoded[ QStringLiteral( "subset" ) ] = options.sql;
return new QgsVectorLayer( providerMetadata->encodeUri( decoded ), options.layerName.isEmpty() ? QStringLiteral( "QueryLayer" ) : options.layerName, providerKey() );
} }
QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnection::execSql( const QString &sql, QgsFeedback *feedback ) const QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnection::execSql( const QString &sql, QgsFeedback *feedback ) const
@ -381,7 +388,7 @@ void QgsGeoPackageProviderConnection::setDefaultCapabilities()
}; };
mSqlLayerDefinitionCapabilities = mSqlLayerDefinitionCapabilities =
{ {
Qgis::SqlLayerDefinitionCapability::Filter, Qgis::SqlLayerDefinitionCapability::SubsetStringFilter,
Qgis::SqlLayerDefinitionCapability::PrimaryKeys, Qgis::SqlLayerDefinitionCapability::PrimaryKeys,
Qgis::SqlLayerDefinitionCapability::GeometryColumn, Qgis::SqlLayerDefinitionCapability::GeometryColumn,
}; };
@ -405,7 +412,9 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
return QgsAbstractDatabaseProviderConnection::QueryResult(); return QgsAbstractDatabaseProviderConnection::QueryResult();
} }
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
OGRLayerH ogrLayer( GDALDatasetExecuteSQL( hDS.get(), sql.toUtf8().constData(), nullptr, nullptr ) ); OGRLayerH ogrLayer( GDALDatasetExecuteSQL( hDS.get(), sql.toUtf8().constData(), nullptr, nullptr ) );
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
// Read fields // Read fields
if ( ogrLayer ) if ( ogrLayer )
@ -413,6 +422,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
auto iterator = std::make_shared<QgsGeoPackageProviderResultIterator>( std::move( hDS ), ogrLayer ); auto iterator = std::make_shared<QgsGeoPackageProviderResultIterator>( std::move( hDS ), ogrLayer );
QgsAbstractDatabaseProviderConnection::QueryResult results( iterator ); QgsAbstractDatabaseProviderConnection::QueryResult results( iterator );
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
gdal::ogr_feature_unique_ptr fet; gdal::ogr_feature_unique_ptr fet;
if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet ) if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet )

View File

@ -1467,6 +1467,16 @@ QgsAbstractDatabaseProviderConnection::QueryResult::QueryResult( std::shared_ptr
: mResultIterator( iterator ) : mResultIterator( iterator )
{} {}
double QgsAbstractDatabaseProviderConnection::QueryResult::queryExecutionTime()
{
return mQueryExecutionTime;
}
void QgsAbstractDatabaseProviderConnection::QueryResult::setQueryExecutionTime( double queryExecutionTime )
{
mQueryExecutionTime = queryExecutionTime;
}
QVariantList QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::nextRow() QVariantList QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::nextRow()
{ {

View File

@ -120,7 +120,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
long long fetchedRowCount( ) const; long long fetchedRowCount( ) const;
/** /**
* Returns the number of rows returned by a SELECT query or -1 if unknown * Returns the number of rows returned by a SELECT query or Qgis::FeatureCountState::UnknownCount if unknown.
* *
* \see fetchedRowCount() * \see fetchedRowCount()
*/ */
@ -206,12 +206,24 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
*/ */
QueryResult( ) = default SIP_SKIP; QueryResult( ) = default SIP_SKIP;
/**
* Returns the query execution time in milliseconds.
*/
double queryExecutionTime( );
/**
* Sets the query execution time to \a queryExecutionTime milliseconds.
*/
void setQueryExecutionTime( double queryExecutionTime );
///@endcond private ///@endcond private
private: private:
mutable std::shared_ptr<QueryResultIterator> mResultIterator; mutable std::shared_ptr<QueryResultIterator> mResultIterator;
QStringList mColumns; QStringList mColumns;
//! Query execution time in milliseconds
double mQueryExecutionTime = 0;
}; };
@ -228,7 +240,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
QString layerName; //!< Optional name for the new layer QString layerName; //!< Optional name for the new layer
QStringList primaryKeyColumns; //!< List of primary key column names QStringList primaryKeyColumns; //!< List of primary key column names
QString geometryColumn; //!< Name of the geometry column QString geometryColumn; //!< Name of the geometry column
bool disableSelectAtId; //!< If SelectAtId is disabled (default is false), not all data providers support this feature: check support with SqlLayerDefinitionCapability::SelectAtId capability bool disableSelectAtId = false; //!< If SelectAtId is disabled (default is false), not all data providers support this feature: check support with SqlLayerDefinitionCapability::SelectAtId capability
}; };
/** /**
@ -596,7 +608,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
/** /**
* Creates a new schema with the specified \a name. * Creates a new schema with the specified \a name.
* *
* \throws QgsProviderConnectionException * \throws QgsProviderConnectionException if any errors are encountered.
*/ */
virtual void createSchema( const QString &name ) const SIP_THROW( QgsProviderConnectionException ); virtual void createSchema( const QString &name ) const SIP_THROW( QgsProviderConnectionException );
@ -639,7 +651,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* Renames a schema with the specified \a name. * Renames a schema with the specified \a name.
* Raises a QgsProviderConnectionException if any errors are encountered. * Raises a QgsProviderConnectionException if any errors are encountered.
* \note it is responsibility of the caller to handle open layers and registry entries. * \note it is responsibility of the caller to handle open layers and registry entries.
* \throws QgsProviderConnectionException * \throws QgsProviderConnectionException if any errors are encountered.
*/ */
virtual void renameSchema( const QString &name, const QString &newName ) const SIP_THROW( QgsProviderConnectionException ); virtual void renameSchema( const QString &name, const QString &newName ) const SIP_THROW( QgsProviderConnectionException );
@ -653,8 +665,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
/** /**
* Creates and returns a (possibly invalid) vector layer based on the \a sql statement and optional \a options. * Creates and returns a (possibly invalid) vector layer based on the \a sql statement and optional \a options.
* Raises a QgsProviderConnectionException if any errors are encountered or if SQL layer creation is not supported. * \throws QgsProviderConnectionException if any errors are encountered or if SQL layer creation is not supported.
* \throws QgsProviderConnectionException
* \since QGIS 3.22 * \since QGIS 3.22
*/ */
virtual QgsVectorLayer *createSqlVectorLayer( const SqlVectorLayerOptions &options ) const SIP_THROW( QgsProviderConnectionException ) SIP_FACTORY; virtual QgsVectorLayer *createSqlVectorLayer( const SqlVectorLayerOptions &options ) const SIP_THROW( QgsProviderConnectionException ) SIP_FACTORY;
@ -748,7 +759,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
* choose to override this method for a greater efficiency of to overcome provider's * choose to override this method for a greater efficiency of to overcome provider's
* behavior when the layer does not expose all fields (GPKG for example hides geometry * behavior when the layer does not expose all fields (GPKG for example hides geometry
* and primary key column). * and primary key column).
* \throws QgsProviderConnectionException * \throws QgsProviderConnectionException if any errors are encountered.
* \since QGIS 3.16 * \since QGIS 3.16
*/ */
virtual QgsFields fields( const QString &schema, const QString &table ) const SIP_THROW( QgsProviderConnectionException ); virtual QgsFields fields( const QString &schema, const QString &table ) const SIP_THROW( QgsProviderConnectionException );
@ -756,7 +767,7 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
/** /**
* Returns a list of native types supported by the connection. * Returns a list of native types supported by the connection.
* *
* \throws QgsProviderConnectionException * \throws QgsProviderConnectionException if any errors are encountered.
* \since QGIS 3.16 * \since QGIS 3.16
*/ */
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW( QgsProviderConnectionException ) = 0; virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW( QgsProviderConnectionException ) = 0;

View File

@ -336,12 +336,11 @@ class CORE_EXPORT Qgis
*/ */
enum class SqlLayerDefinitionCapability : int enum class SqlLayerDefinitionCapability : int
{ {
Filter = 1 << 1, //!< SQL layer definition supports filter SubsetStringFilter = 1 << 1, //!< SQL layer definition supports subset string filter
GeometryColumn = 1 << 2, //!< SQL layer definition supports geometry column GeometryColumn = 1 << 2, //!< SQL layer definition supports geometry column
PrimaryKeys = 1 << 3, //!< SQL layer definition supports primary keys PrimaryKeys = 1 << 3, //!< SQL layer definition supports primary keys
SelectAtId = 1 << 4 //!< SQL layer definition supports disabling select at id UnstableFeatureIds = 1 << 4 //!< SQL layer definition supports disabling select at id
}; };
Q_ENUM( SqlLayerDefinitionCapability ) Q_ENUM( SqlLayerDefinitionCapability )
Q_DECLARE_FLAGS( SqlLayerDefinitionCapabilities, SqlLayerDefinitionCapability ) Q_DECLARE_FLAGS( SqlLayerDefinitionCapabilities, SqlLayerDefinitionCapability )
@ -364,7 +363,6 @@ class CORE_EXPORT Qgis
}; };
Q_ENUM( SqlKeywordCategory ) Q_ENUM( SqlKeywordCategory )
/** /**
* Drive types * Drive types
* \since QGIS 3.20 * \since QGIS 3.20
@ -583,6 +581,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SymbolFlags )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SymbolPreviewFlags ) Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SymbolPreviewFlags )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::BrowserItemCapabilities ) Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::BrowserItemCapabilities )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SublayerQueryFlags ) Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SublayerQueryFlags )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SqlLayerDefinitionCapabilities )
// hack to workaround warnings when casting void pointers // hack to workaround warnings when casting void pointers
// retrieved from QLibrary::resolve to function pointers. // retrieved from QLibrary::resolve to function pointers.

View File

@ -112,7 +112,7 @@ class CORE_EXPORT QgsQueryResultModel : public QAbstractTableModel
public slots: public slots:
/** /**
* Triggered when \a newRows have been fetched and can be added to the model * Triggered when \a newRows have been fetched and can be added to the model.
*/ */
void rowsReady( const QList<QList<QVariant> > &rows ); void rowsReady( const QList<QList<QVariant> > &rows );
@ -125,13 +125,15 @@ class CORE_EXPORT QgsQueryResultModel : public QAbstractTableModel
signals: signals:
/** /**
* Emitted when all rows have been fetched or when the fetching has been stopped (canceled) * Emitted when rows have been fetched (all of them or a batch if `maxRows` was passed to fetchMoreRows() )
* or when the fetching has been stopped (canceled).
* \see fetchMoreRows()
*/ */
void fetchingComplete(); void fetchingComplete();
/** /**
* Emitted when more rows are requested * Emitted when more rows are requested.
* \param maxRows the number of rows that will be fetched * \param maxRows the number of rows that will be fetched.
*/ */
void fetchMoreRows( qlonglong maxRows ); void fetchMoreRows( qlonglong maxRows );

View File

@ -91,12 +91,12 @@ QgsQueryResultWidget::QgsQueryResultWidget( QWidget *parent, QgsAbstractDatabase
mGeometryColumnCheckBox->setVisible( showGeometryColumnConfig ); mGeometryColumnCheckBox->setVisible( showGeometryColumnConfig );
mGeometryColumnComboBox->setVisible( showGeometryColumnConfig ); mGeometryColumnComboBox->setVisible( showGeometryColumnConfig );
const bool showFilterConfig { connection &&connection->sqlLayerDefinitionCapabilities().testFlag( Qgis::SqlLayerDefinitionCapability::Filter ) }; const bool showFilterConfig { connection &&connection->sqlLayerDefinitionCapabilities().testFlag( Qgis::SqlLayerDefinitionCapability::SubsetStringFilter ) };
mFilterLabel->setVisible( showFilterConfig ); mFilterLabel->setVisible( showFilterConfig );
mFilterToolButton->setVisible( showFilterConfig ); mFilterToolButton->setVisible( showFilterConfig );
mFilterLineEdit->setVisible( showFilterConfig ); mFilterLineEdit->setVisible( showFilterConfig );
const bool showDisableSelectAtId{ connection &&connection->sqlLayerDefinitionCapabilities().testFlag( Qgis::SqlLayerDefinitionCapability::SelectAtId ) }; const bool showDisableSelectAtId{ connection &&connection->sqlLayerDefinitionCapabilities().testFlag( Qgis::SqlLayerDefinitionCapability::UnstableFeatureIds ) };
mAvoidSelectingAsFeatureIdCheckBox->setVisible( showDisableSelectAtId ); mAvoidSelectingAsFeatureIdCheckBox->setVisible( showDisableSelectAtId );
} }
@ -244,12 +244,15 @@ void QgsQueryResultWidget::startFetching()
{ {
if ( mQueryResultWatcher.result().rowCount() != static_cast<long long>( Qgis::FeatureCountState::UnknownCount ) ) if ( mQueryResultWatcher.result().rowCount() != static_cast<long long>( Qgis::FeatureCountState::UnknownCount ) )
{ {
mStatusLabel->setText( QStringLiteral( "Query executed successfully (%1 rows)" ).arg( QLocale().toString( mQueryResultWatcher.result().rowCount() ) ) ); mStatusLabel->setText( QStringLiteral( "Query executed successfully (%1 rows, %2 ms)" )
.arg( QLocale().toString( mQueryResultWatcher.result().rowCount() ),
QLocale().toString( mQueryResultWatcher.result().queryExecutionTime() ) ) );
} }
else else
{ {
mStatusLabel->setText( QStringLiteral( "Query executed successfully" ) ); mStatusLabel->setText( QStringLiteral( "Query executed successfully (%1 s)" ).arg( QLocale().toString( mQueryResultWatcher.result().queryExecutionTime() ) ) );
} }
mProgressBar->hide();
mModel = std::make_unique<QgsQueryResultModel>( mQueryResultWatcher.result() ); mModel = std::make_unique<QgsQueryResultModel>( mQueryResultWatcher.result() );
connect( mFeedback.get(), &QgsFeedback::canceled, mModel.get(), [ = ] connect( mFeedback.get(), &QgsFeedback::canceled, mModel.get(), [ = ]
{ {
@ -257,13 +260,14 @@ void QgsQueryResultWidget::startFetching()
mWasCanceled = true; mWasCanceled = true;
} ); } );
connect( mModel.get(), &QgsQueryResultModel::fetchMoreRows, this, [ = ]( long long maxRows )
connect( mModel.get(), &QgsQueryResultModel::fetchingStarted, this, [ = ]
{ {
mFetchedRowsBatchCount = 0;
mProgressBar->setRange( 0, maxRows );
mProgressBar->show(); mProgressBar->show();
} ); } );
connect( mModel.get(), &QgsQueryResultModel::rowsInserted, this, [ = ]( const QModelIndex &, int, int ) connect( mModel.get(), &QgsQueryResultModel::rowsInserted, this, [ = ]( const QModelIndex &, int first, int last )
{ {
if ( ! mFirstRowFetched ) if ( ! mFirstRowFetched )
{ {
@ -273,19 +277,14 @@ void QgsQueryResultWidget::startFetching()
updateButtons(); updateButtons();
updateSqlLayerColumns( ); updateSqlLayerColumns( );
mActualRowCount = mModel->queryResult().rowCount(); mActualRowCount = mModel->queryResult().rowCount();
if ( mActualRowCount != -1 )
{
mProgressBar->setRange( 0, mActualRowCount );
}
} }
mStatusLabel->setText( tr( "Fetched rows: %1/%2 %3" ) mStatusLabel->setText( tr( "Fetched rows: %1/%2 %3 %4 ms" )
.arg( QLocale().toString( mModel->rowCount( mModel->index( -1, -1 ) ) ), .arg( QLocale().toString( mModel->rowCount( mModel->index( -1, -1 ) ) ),
mActualRowCount != -1 ? QLocale().toString( mActualRowCount ) : tr( "unknown" ), mActualRowCount != -1 ? QLocale().toString( mActualRowCount ) : tr( "unknown" ),
mWasCanceled ? tr( "(stopped)" ) : QString() ) ); mWasCanceled ? tr( "(stopped)" ) : QString(),
if ( mActualRowCount != -1 ) QLocale().toString( mQueryResultWatcher.result().queryExecutionTime() ) ) );
{ mFetchedRowsBatchCount += last - first + 1;
mProgressBar->setValue( mModel->rowCount( mModel->index( -1, -1 ) ) ); mProgressBar->setValue( mFetchedRowsBatchCount );
}
} ); } );
mQueryResultsTableView->setModel( mModel.get() ); mQueryResultsTableView->setModel( mModel.get() );
@ -293,6 +292,7 @@ void QgsQueryResultWidget::startFetching()
connect( mModel.get(), &QgsQueryResultModel::fetchingComplete, mStopButton, [ = ] connect( mModel.get(), &QgsQueryResultModel::fetchingComplete, mStopButton, [ = ]
{ {
mProgressBar->hide();
mStopButton->setEnabled( false ); mStopButton->setEnabled( false );
} ); } );
} }
@ -456,7 +456,7 @@ void QgsConnectionsApiFetcher::fetchTokens()
QStringList fieldNames; QStringList fieldNames;
try try
{ {
const auto fields( mConnection->fields( schema, table ) ); const QgsFields fields( mConnection->fields( schema, table ) );
if ( mStopFetching ) { return; } if ( mStopFetching ) { return; }
for ( const auto &field : std::as_const( fields ) ) for ( const auto &field : std::as_const( fields ) )
{ {

View File

@ -178,8 +178,8 @@ class GUI_EXPORT QgsQueryResultWidget: public QWidget, private Ui::QgsQueryResul
bool mFirstRowFetched = false; bool mFirstRowFetched = false;
QFutureWatcher<QgsAbstractDatabaseProviderConnection::QueryResult> mQueryResultWatcher; QFutureWatcher<QgsAbstractDatabaseProviderConnection::QueryResult> mQueryResultWatcher;
QString mSqlErrorMessage; QString mSqlErrorMessage;
qlonglong mActualRowCount = -1; long long mActualRowCount = -1;
long long mFetchedRowsBatchCount = 0;
/** /**
* Updates SQL layer columns. * Updates SQL layer columns.

View File

@ -28,6 +28,8 @@
#include "odbc/PreparedStatement.h" #include "odbc/PreparedStatement.h"
#include <chrono>
QgsHanaProviderResultIterator::QgsHanaProviderResultIterator( QgsHanaResultSetRef &&resultSet ) QgsHanaProviderResultIterator::QgsHanaProviderResultIterator( QgsHanaResultSetRef &&resultSet )
: mResultSet( std::move( resultSet ) ) : mResultSet( std::move( resultSet ) )
, mNumColumns( mResultSet->getMetadata().getColumnCount() ) , mNumColumns( mResultSet->getMetadata().getColumnCount() )
@ -264,6 +266,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsHanaProviderConnection::ex
try try
{ {
odbc::PreparedStatementRef stmt = conn->prepareStatement( sql ); odbc::PreparedStatementRef stmt = conn->prepareStatement( sql );
bool isQuery = stmt->getMetaDataUnicode()->getColumnCount() > 0; bool isQuery = stmt->getMetaDataUnicode()->getColumnCount() > 0;
if ( isQuery ) if ( isQuery )
@ -278,9 +281,13 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsHanaProviderConnection::ex
} }
else else
{ {
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
conn->execute( sql ); conn->execute( sql );
conn->commit(); conn->commit();
return QueryResult( std::make_shared<QgsHanaEmptyProviderResultIterator>() ); std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
QueryResult results( std::make_shared<QgsHanaEmptyProviderResultIterator>() );
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
return results;
} }
} }
catch ( const QgsHanaException &ex ) catch ( const QgsHanaException &ex )

View File

@ -27,6 +27,8 @@
#include "qgsfeedback.h" #include "qgsfeedback.h"
#include <QIcon> #include <QIcon>
#include <chrono>
const QStringList QgsMssqlProviderConnection::EXTRA_CONNECTION_PARAMETERS const QStringList QgsMssqlProviderConnection::EXTRA_CONNECTION_PARAMETERS
{ {
QStringLiteral( "geometryColumnsOnly" ), QStringLiteral( "geometryColumnsOnly" ),
@ -101,10 +103,10 @@ void QgsMssqlProviderConnection::setDefaultCapabilities()
}; };
mSqlLayerDefinitionCapabilities = mSqlLayerDefinitionCapabilities =
{ {
Qgis::SqlLayerDefinitionCapability::Filter, Qgis::SqlLayerDefinitionCapability::SubsetStringFilter,
Qgis::SqlLayerDefinitionCapability::PrimaryKeys, Qgis::SqlLayerDefinitionCapability::PrimaryKeys,
Qgis::SqlLayerDefinitionCapability::GeometryColumn, Qgis::SqlLayerDefinitionCapability::GeometryColumn,
Qgis::SqlLayerDefinitionCapability::SelectAtId, Qgis::SqlLayerDefinitionCapability::UnstableFeatureIds,
}; };
} }
@ -260,6 +262,8 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsMssqlProviderConnection::e
QSqlQuery q = QSqlQuery( db ); QSqlQuery q = QSqlQuery( db );
q.setForwardOnly( true ); q.setForwardOnly( true );
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
if ( ! q.exec( sql ) ) if ( ! q.exec( sql ) )
{ {
const QString errorMessage { q.lastError().text() }; const QString errorMessage { q.lastError().text() };
@ -270,10 +274,12 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsMssqlProviderConnection::e
if ( q.isActive() ) if ( q.isActive() )
{ {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
const QSqlRecord rec { q.record() }; const QSqlRecord rec { q.record() };
const int numCols { rec.count() }; const int numCols { rec.count() };
auto iterator = std::make_shared<QgssMssqlProviderResultIterator>( resolveTypes, numCols, q ); auto iterator = std::make_shared<QgssMssqlProviderResultIterator>( resolveTypes, numCols, q );
QgsAbstractDatabaseProviderConnection::QueryResult results( iterator ); QgsAbstractDatabaseProviderConnection::QueryResult results( iterator );
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
for ( int idx = 0; idx < numCols; ++idx ) for ( int idx = 0; idx < numCols; ++idx )
{ {
results.appendColumn( rec.field( idx ).name() ); results.appendColumn( rec.field( idx ).name() );

View File

@ -1351,6 +1351,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsOracleProviderConnection::
return QgsAbstractDatabaseProviderConnection::QueryResult(); return QgsAbstractDatabaseProviderConnection::QueryResult();
QSqlQuery qry( *pconn.get() ); QSqlQuery qry( *pconn.get() );
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
if ( !qry.exec( sql ) ) if ( !qry.exec( sql ) )
{ {
throw QgsProviderConnectionException( QObject::tr( "SQL error: %1 returned %2" ) throw QgsProviderConnectionException( QObject::tr( "SQL error: %1 returned %2" )
@ -1372,6 +1373,8 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsOracleProviderConnection::
results.appendColumn( rec.field( idx ).name() ); results.appendColumn( rec.field( idx ).name() );
} }
iterator->nextRow(); iterator->nextRow();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
return results; return results;
} }

View File

@ -25,6 +25,8 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QIcon> #include <QIcon>
#include <chrono>
extern "C" extern "C"
{ {
#include <libpq-fe.h> #include <libpq-fe.h>
@ -85,10 +87,10 @@ void QgsPostgresProviderConnection::setDefaultCapabilities()
}; };
mSqlLayerDefinitionCapabilities = mSqlLayerDefinitionCapabilities =
{ {
Qgis::SqlLayerDefinitionCapability::Filter, Qgis::SqlLayerDefinitionCapability::SubsetStringFilter,
Qgis::SqlLayerDefinitionCapability::PrimaryKeys, Qgis::SqlLayerDefinitionCapability::PrimaryKeys,
Qgis::SqlLayerDefinitionCapability::GeometryColumn, Qgis::SqlLayerDefinitionCapability::GeometryColumn,
Qgis::SqlLayerDefinitionCapability::SelectAtId, Qgis::SqlLayerDefinitionCapability::UnstableFeatureIds,
}; };
} }
@ -254,7 +256,10 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection
} ); } );
} }
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( conn->PQexec( sql ) ); std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( conn->PQexec( sql ) );
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
if ( feedback ) if ( feedback )
{ {

View File

@ -27,6 +27,8 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextCodec> #include <QTextCodec>
#include <chrono>
QgsSpatiaLiteProviderConnection::QgsSpatiaLiteProviderConnection( const QString &name ) QgsSpatiaLiteProviderConnection::QgsSpatiaLiteProviderConnection( const QString &name )
: QgsAbstractDatabaseProviderConnection( name ) : QgsAbstractDatabaseProviderConnection( name )
{ {
@ -439,7 +441,7 @@ void QgsSpatiaLiteProviderConnection::setDefaultCapabilities()
}; };
mSqlLayerDefinitionCapabilities = mSqlLayerDefinitionCapabilities =
{ {
Qgis::SqlLayerDefinitionCapability::Filter, Qgis::SqlLayerDefinitionCapability::SubsetStringFilter,
Qgis::SqlLayerDefinitionCapability::GeometryColumn Qgis::SqlLayerDefinitionCapability::GeometryColumn
}; };
@ -463,7 +465,9 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnecti
return QgsAbstractDatabaseProviderConnection::QueryResult(); return QgsAbstractDatabaseProviderConnection::QueryResult();
} }
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
OGRLayerH ogrLayer( GDALDatasetExecuteSQL( hDS.get(), sql.toUtf8().constData(), nullptr, nullptr ) ); OGRLayerH ogrLayer( GDALDatasetExecuteSQL( hDS.get(), sql.toUtf8().constData(), nullptr, nullptr ) );
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
// Read fields // Read fields
if ( ogrLayer ) if ( ogrLayer )
@ -471,6 +475,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnecti
auto iterator = std::make_shared<QgsSpatialiteProviderResultIterator>( std::move( hDS ), ogrLayer ); auto iterator = std::make_shared<QgsSpatialiteProviderResultIterator>( std::move( hDS ), ogrLayer );
QgsAbstractDatabaseProviderConnection::QueryResult results( iterator ); QgsAbstractDatabaseProviderConnection::QueryResult results( iterator );
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
gdal::ogr_feature_unique_ptr fet; gdal::ogr_feature_unique_ptr fet;
if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet ) if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet )

View File

@ -36,6 +36,7 @@ from qgis.core import (
QgsFeedback, QgsFeedback,
QgsApplication, QgsApplication,
QgsTask, QgsTask,
Qgis,
) )
from qgis.PyQt import QtCore from qgis.PyQt import QtCore
from qgis.PyQt.QtTest import QSignalSpy from qgis.PyQt.QtTest import QSignalSpy
@ -564,14 +565,14 @@ class TestPyQgsProviderConnectionBase():
self.assertEqual(vl.name(), options.layerName) self.assertEqual(vl.name(), options.layerName)
# Some providers can also create SQL layer without an explicit PK # Some providers can also create SQL layer without an explicit PK
if sql_layer_capabilities & QgsAbstractDatabaseProviderConnection.PrimaryKeys: if sql_layer_capabilities & Qgis.SqlLayerDefinitionCapability.PrimaryKeys:
options.primaryKeyColumns = [] options.primaryKeyColumns = []
vl = conn.createSqlVectorLayer(options) vl = conn.createSqlVectorLayer(options)
self.assertTrue(vl.isValid()) self.assertTrue(vl.isValid())
self.assertTrue(vl.isSpatial()) self.assertTrue(vl.isSpatial())
# Some providers can also create SQL layer without an explicit geometry column # Some providers can also create SQL layer without an explicit geometry column
if sql_layer_capabilities & QgsAbstractDatabaseProviderConnection.GeometryColumn: if sql_layer_capabilities & Qgis.SqlLayerDefinitionCapability.GeometryColumn:
options.primaryKeyColumns = table_info.primaryKeyColumns() options.primaryKeyColumns = table_info.primaryKeyColumns()
options.geometryColumn = '' options.geometryColumn = ''
vl = conn.createSqlVectorLayer(options) vl = conn.createSqlVectorLayer(options)
@ -581,7 +582,7 @@ class TestPyQgsProviderConnectionBase():
self.assertFalse(vl.isSpatial()) self.assertFalse(vl.isSpatial())
# Some providers can also create SQL layer with filters # Some providers can also create SQL layer with filters
if sql_layer_capabilities & QgsAbstractDatabaseProviderConnection.Filter: if sql_layer_capabilities & Qgis.SqlLayerDefinitionCapability.SubsetStringFilter:
options.primaryKeyColumns = table_info.primaryKeyColumns() options.primaryKeyColumns = table_info.primaryKeyColumns()
options.geometryColumn = table_info.geometryColumn() options.geometryColumn = table_info.geometryColumn()
options.filter = f'"{options.primaryKeyColumns[0]}" > 0' options.filter = f'"{options.primaryKeyColumns[0]}" > 0'