Skip to content

Commit

Permalink
[Oracle] Fixes #40001 : Use QgsTask to retrieve available tables so w…
Browse files Browse the repository at this point in the history
…e can properly

cancel it
  • Loading branch information
troopa81 committed Jun 10, 2021
1 parent 409b221 commit ec84beb
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 74 deletions.
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
60 changes: 26 additions & 34 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 Down Expand Up @@ -125,7 +125,7 @@ QgsOracleConnectionItem::QgsOracleConnectionItem( QgsDataItem *parent, const QSt
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "ORACLE" ) )
{
mIconName = QStringLiteral( "mIconConnect.svg" );
mCapabilities |= Qgis::BrowserItemCapability::Collapse;
mCapabilities |= Qgis::BrowserItemCapability::Collapse | Qgis::BrowserItemCapability::Fast;
}

QgsOracleConnectionItem::~QgsOracleConnectionItem()
Expand All @@ -135,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 @@ -182,56 +184,46 @@ 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 )
{
mColumnTypeTask->setProxyProgress( 100.0 * static_cast< double >( i ) / n );
} );
connect( mColumnTypeThread, SIGNAL( progressMessage( QString ) ),
connect( mColumnTypeTask, 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 @@ -33,7 +33,7 @@ class QgsOracleRootItem;
class QgsOracleConnectionItem;
class QgsOracleOwnerItem;
class QgsOracleLayerItem;
class QgsProxyProgressTask;
class QgsOracleColumnTypeTask;

class QgsOracleRootItem : public QgsConnectionsRootItem
{
Expand Down Expand Up @@ -82,14 +82,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

0 comments on commit ec84beb

Please sign in to comment.