Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport to queued_ltr_backports][Oracle] Use QgsTask to retrieve available tables so we can properly cancel it #44436

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/providers/oracle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set(ORACLE_SRCS
qgsoraclenewconnection.cpp
qgsoracletablecache.cpp
qgsoracletablemodel.cpp
qgsoraclecolumntypethread.cpp
qgsoraclecolumntypetask.cpp
qgsoraclefeatureiterator.cpp
qgsoracleconnpool.cpp
qgsoracleexpressioncompiler.cpp
Expand Down
92 changes: 92 additions & 0 deletions src/providers/oracle/qgsoraclecolumntypetask.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/***************************************************************************
qgscolumntypetask.cpp - lookup oracle geometry type and srid in a thread
-------------------
begin : 3.1.2012
copyright : (C) 2012 by Juergen E. Fischer
email : jef at norbit dot de
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsoraclecolumntypetask.h"
#include "qgslogger.h"
#include "qgsoracleconnpool.h"

#include <QMetaType>

QgsOracleColumnTypeTask::QgsOracleColumnTypeTask( const QString &name, const QString &limitToSchema, bool useEstimatedMetadata, bool allowGeometrylessTables )
: QgsTask( tr( "Scanning tables for %1" ).arg( name ) )
, mName( name )
, mSchema( limitToSchema )
, mUseEstimatedMetadata( useEstimatedMetadata )
, mAllowGeometrylessTables( allowGeometrylessTables )
{
qRegisterMetaType<QgsOracleLayerProperty>( "QgsOracleLayerProperty" );
}

bool QgsOracleColumnTypeTask::run()
{
QString conninfo = QgsOracleConn::toPoolName( QgsOracleConn::connUri( mName ) );
QgsOracleConn *conn = QgsOracleConnPool::instance()->acquireConnection( conninfo );
if ( !conn )
{
QgsDebugMsg( "Connection failed - " + conninfo );
return false;
}

emit progressMessage( tr( "Retrieving tables of %1…" ).arg( mName ) );
QVector<QgsOracleLayerProperty> layerProperties;
if ( !conn->supportedLayers( layerProperties,
mSchema,
QgsOracleConn::geometryColumnsOnly( mName ),
QgsOracleConn::userTablesOnly( mName ),
mAllowGeometrylessTables ) ||
layerProperties.isEmpty() )
{
return false;
}

int i = 0, n = layerProperties.size();
for ( QVector<QgsOracleLayerProperty>::iterator it = layerProperties.begin(),
end = layerProperties.end();
it != end; ++it )
{
QgsOracleLayerProperty &layerProperty = *it;
if ( !isCanceled() )
{
setProgress( ( i * 100. ) / n );
emit progressMessage( tr( "Scanning column %1.%2.%3…" )
.arg( layerProperty.ownerName,
layerProperty.tableName,
layerProperty.geometryColName ) );
conn->retrieveLayerTypes( layerProperty, mUseEstimatedMetadata, QgsOracleConn::onlyExistingTypes( mName ) );
}

if ( isCanceled() )
{
layerProperty.types.clear();
layerProperty.srids.clear();
}

// Now tell the layer list dialog box...
emit setLayerType( layerProperty );
}

// store the list for later use (cache)
if ( !isCanceled() )
mLayerProperties = layerProperties;

setProgress( 100 );
emit progressMessage( tr( "Table retrieval finished." ) );

QgsOracleConnPool::instance()->releaseConnection( conn );

return true;
}
67 changes: 67 additions & 0 deletions src/providers/oracle/qgsoraclecolumntypetask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/***************************************************************************
qgsoraclecolumntypetask.h - lookup oracle geometry type and srid in a thread
-------------------
begin : 12.12.2012
copyright : (C) 2012 by Juergen E. Fischer
email : jef at norbit dot de
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSORACLECOLUMNTYPETASK_H
#define QGSORACLECOLUMNTYPETASK_H

#include "qgstaskmanager.h"
#include "qgsoracleconn.h"

// A class that determines the geometry type of a given database
// schema.table.column, with the option of doing so in a separate
// thread.

class QgsOracleColumnTypeTask : public QgsTask
{
Q_OBJECT
public:

/**
*
* \param connName
* \param limitToSchema If specified, only tables from this schema will be scanned
* \param useEstimatedMetaData
* \param allowGeometrylessTables
*/
QgsOracleColumnTypeTask( const QString &connName,
const QString &limitToSchema,
bool useEstimatedMetaData,
bool allowGeometrylessTables );

// These functions get the layer types and pass that information out
// by emitting the setLayerType() signal.
bool run() override;

QVector<QgsOracleLayerProperty> layerProperties() const { return mLayerProperties; }
QString connectionName() const { return mName; }
bool useEstimatedMetadata() const { return mUseEstimatedMetadata; }
bool allowGeometrylessTables() const { return mAllowGeometrylessTables; }

signals:
void setLayerType( const QgsOracleLayerProperty &layerProperty );
void progressMessage( const QString &message );

private:
QgsOracleColumnTypeTask() = default;

QString mName;
QString mSchema;
bool mUseEstimatedMetadata = false;
bool mAllowGeometrylessTables = false;
QVector<QgsOracleLayerProperty> mLayerProperties;
};

#endif // QGSORACLECOLUMNTYPETASK_H
62 changes: 29 additions & 33 deletions src/providers/oracle/qgsoracledataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "qgsoracletablemodel.h"
#include "qgsoraclenewconnection.h"
#include "qgsoraclecolumntypethread.h"
#include "qgsoraclecolumntypetask.h"
#include "qgsoracleprovider.h"

#include "qgslogger.h"
Expand All @@ -29,6 +29,7 @@
#include <QMessageBox>
#include <QProgressDialog>
#include <QSqlError>
#include <QStatusBar>

bool deleteLayer( const QString &uri, QString &errCause )
{
Expand Down Expand Up @@ -124,7 +125,7 @@ QgsOracleConnectionItem::QgsOracleConnectionItem( QgsDataItem *parent, const QSt
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "ORACLE" ) )
{
mIconName = QStringLiteral( "mIconConnect.svg" );
mCapabilities |= Collapse;
mCapabilities |= Collapse | Fast;
}

QgsOracleConnectionItem::~QgsOracleConnectionItem()
Expand All @@ -134,12 +135,14 @@ QgsOracleConnectionItem::~QgsOracleConnectionItem()

void QgsOracleConnectionItem::stop()
{
if ( mColumnTypeThread )
if ( mColumnTypeTask )
{
mColumnTypeThread->stop();
mColumnTypeThread->wait();
delete mColumnTypeThread;
mColumnTypeThread = nullptr;
mColumnTypeTask->cancel();
disconnect( mColumnTypeTask, nullptr, this, nullptr );
disconnect( mColumnTypeTask, nullptr, QgsOracleRootItem::sMainWindow, nullptr );

// don't delete the task, taskManager takes ownership of it
mColumnTypeTask = nullptr;
}
}

Expand Down Expand Up @@ -181,56 +184,49 @@ QVector<QgsDataItem *> QgsOracleConnectionItem::createChildren()
if ( deferredDelete() )
return QVector<QgsDataItem *>();

if ( !mColumnTypeThread )
if ( !mColumnTypeTask )
{
mColumnTypeThread = new QgsOracleColumnTypeThread( mName,
mColumnTypeTask = new QgsOracleColumnTypeTask( mName,
QgsOracleConn::restrictToSchema( mName ),
/* useEstimatedMetadata */ true,
QgsOracleConn::allowGeometrylessTables( mName ) );
mColumnTypeTask = new QgsProxyProgressTask( tr( "Scanning tables for %1" ).arg( mName ) );
QgsApplication::taskManager()->addTask( mColumnTypeTask );

connect( mColumnTypeThread, &QgsOracleColumnTypeThread::setLayerType,
connect( mColumnTypeTask, &QgsOracleColumnTypeTask::setLayerType,
this, &QgsOracleConnectionItem::setLayerType );
connect( mColumnTypeThread, &QThread::started, this, &QgsOracleConnectionItem::threadStarted );
connect( mColumnTypeThread, &QThread::finished, this, &QgsOracleConnectionItem::threadFinished );
connect( mColumnTypeTask, &QgsTask::begun, this, &QgsOracleConnectionItem::taskStarted );
connect( mColumnTypeTask, &QgsTask::taskCompleted, this, &QgsOracleConnectionItem::taskFinished );
connect( mColumnTypeTask, &QgsTask::taskTerminated, this, &QgsOracleConnectionItem::taskFinished );

if ( QgsOracleRootItem::sMainWindow )
{
connect( mColumnTypeThread, &QgsOracleColumnTypeThread::progress,
mColumnTypeTask, [ = ]( int i, int n )
connect( mColumnTypeTask, &QgsOracleColumnTypeTask::progressMessage,
QgsOracleRootItem::sMainWindow->statusBar(), [ = ]( const QString & message )
{
mColumnTypeTask->setProxyProgress( 100.0 * static_cast< double >( i ) / n );
QgsOracleRootItem::sMainWindow->statusBar()->showMessage( message );
} );
connect( mColumnTypeThread, SIGNAL( progressMessage( QString ) ),
QgsOracleRootItem::sMainWindow, SLOT( showStatusMessage( QString ) ) );
}
}

if ( mColumnTypeThread )
{
mColumnTypeThread->start();
}
else
{
setAllAsPopulated();
QgsApplication::taskManager()->addTask( mColumnTypeTask );
}

return QVector<QgsDataItem *>();
}

void QgsOracleConnectionItem::threadStarted()
void QgsOracleConnectionItem::taskStarted()
{
QgsDebugMsgLevel( QStringLiteral( "Entering." ), 3 );
}

void QgsOracleConnectionItem::threadFinished()
void QgsOracleConnectionItem::taskFinished()
{
mColumnTypeTask->finalize( true );
mColumnTypeTask = nullptr;

QgsDebugMsgLevel( QStringLiteral( "Entering." ), 3 );
setAllAsPopulated();

if ( mColumnTypeTask->status() == QgsTask::Complete )
setAllAsPopulated();
else
setState( Qgis::BrowserItemState::NotPopulated );

mColumnTypeTask = nullptr;
}

void QgsOracleConnectionItem::setLayerType( const QgsOracleLayerProperty &layerProperty )
Expand Down
9 changes: 4 additions & 5 deletions src/providers/oracle/qgsoracledataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class QgsOracleRootItem;
class QgsOracleConnectionItem;
class QgsOracleOwnerItem;
class QgsOracleLayerItem;
class QgsProxyProgressTask;
class QgsOracleColumnTypeTask;

class QgsOracleRootItem : public QgsConnectionsRootItem
{
Expand Down Expand Up @@ -81,14 +81,13 @@ class QgsOracleConnectionItem : public QgsDataCollectionItem

void setLayerType( const QgsOracleLayerProperty &layerProperty );

void threadStarted();
void threadFinished();
void taskStarted();
void taskFinished();

private:
void stop();
QMap<QString, QgsOracleOwnerItem * > mOwnerMap;
QgsOracleColumnTypeThread *mColumnTypeThread = nullptr;
QgsProxyProgressTask *mColumnTypeTask = nullptr;
QgsOracleColumnTypeTask *mColumnTypeTask = nullptr;
void setAllAsPopulated();
};

Expand Down
Loading