Skip to content

Commit

Permalink
[FEATURE] Oracle: local cache of the list of tables
Browse files Browse the repository at this point in the history
Caching is done using SQLite database (could be shared also with other providers)
  • Loading branch information
wonder-sk committed Apr 8, 2014
1 parent 35e4350 commit 5b72daa
Show file tree
Hide file tree
Showing 9 changed files with 501 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/providers/oracle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ SET(ORACLE_SRCS
qgsoracledataitems.cpp
qgsoraclesourceselect.cpp
qgsoraclenewconnection.cpp
qgsoracletablecache.cpp
qgsoracletablemodel.cpp
qgsoraclecolumntypethread.cpp
qgsoraclefeatureiterator.cpp
Expand All @@ -20,6 +21,7 @@ SET(ORACLE_MOC_HDRS
qgsoracledataitems.h
qgsoraclesourceselect.h
qgsoraclenewconnection.h
qgsoracletablecache.h
qgsoracletablemodel.h
qgsoraclecolumntypethread.h
)
Expand Down
9 changes: 7 additions & 2 deletions src/providers/oracle/qgsoraclecolumntypethread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,17 @@ void QgsOracleColumnTypeThread::stop()

void QgsOracleColumnTypeThread::run()
{
mStopped = false;

QgsDataSourceURI uri = QgsOracleConn::connUri( mName );
QgsOracleConn *conn = QgsOracleConn::connectDb( uri.connectionInfo() );
if ( !conn )
{
QgsDebugMsg( "Connection failed - " + uri.connectionInfo() );
mStopped = true;
return;
}

mStopped = false;

emit progressMessage( tr( "Retrieving tables of %1..." ).arg( mName ) );
QVector<QgsOracleLayerProperty> layerProperties;
if ( !conn->supportedLayers( layerProperties,
Expand Down Expand Up @@ -84,6 +85,10 @@ void QgsOracleColumnTypeThread::run()
emit setLayerType( layerProperty );
}

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

emit progress( 0, 0 );
emit progressMessage( tr( "Table retrieval finished." ) );

Expand Down
8 changes: 7 additions & 1 deletion src/providers/oracle/qgsoraclecolumntypethread.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class QgsOracleColumnTypeThread : public QThread
// by emitting the setLayerType() signal.
virtual void run();

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

signals:
void setLayerType( QgsOracleLayerProperty layerProperty );
void progress( int, int );
Expand All @@ -51,7 +57,7 @@ class QgsOracleColumnTypeThread : public QThread
bool mUseEstimatedMetadata;
bool mAllowGeometrylessTables;
bool mStopped;
QList<QgsOracleLayerProperty> layerProperties;
QVector<QgsOracleLayerProperty> mLayerProperties;
};

#endif // QGSORACLECOLUMNTYPETHREAD_H
7 changes: 7 additions & 0 deletions src/providers/oracle/qgsoracleconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ struct QgsOracleLayerProperty

int size() const { Q_ASSERT( types.size() == srids.size() ); return types.size(); }

bool operator==( const QgsOracleLayerProperty& other )
{
return types == other.types && srids == other.srids && ownerName == other.ownerName &&
tableName == other.tableName && geometryColName == other.geometryColName &&
isView == other.isView && pkCols == other.pkCols && sql == other.sql;
}

QgsOracleLayerProperty at( int i ) const
{
QgsOracleLayerProperty property;
Expand Down
4 changes: 4 additions & 0 deletions src/providers/oracle/qgsoraclenewconnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class QgsOracleNewConnection : public QDialog, private Ui::QgsOracleNewConnectio
QgsOracleNewConnection( QWidget *parent = 0, const QString& connName = QString::null, Qt::WindowFlags fl = QgisGui::ModalDialogFlags );
//! Destructor
~QgsOracleNewConnection();

QString originalConnName() const { return mOriginalConnName; }
QString connName() const { return txtName->text(); }

public slots:
void accept();
void on_btnConnect_clicked();
Expand Down
82 changes: 70 additions & 12 deletions src/providers/oracle/qgsoraclesourceselect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ email : jef at norbit dot de
#include "qgscontexthelp.h"
#include "qgsoracleprovider.h"
#include "qgsoraclenewconnection.h"
#include "qgsoracletablecache.h"
#include "qgsmanageconnectionsdialog.h"
#include "qgsquerybuilder.h"
#include "qgsdatasourceuri.h"
Expand Down Expand Up @@ -79,7 +80,8 @@ QWidget *QgsOracleSourceSelectDelegate::createEditor( QWidget *parent, const QSt
if ( values.size() == 0 )
{
QString ownerName = index.sibling( index.row(), QgsOracleTableModel::dbtmOwner ).data( Qt::DisplayRole ).toString();
values = mConn->pkCandidates( ownerName, tableName );
if ( conn() )
values = conn()->pkCandidates( ownerName, tableName );
}

if ( values.size() == 0 )
Expand Down Expand Up @@ -198,8 +200,6 @@ QgsOracleSourceSelect::QgsOracleSourceSelect( QWidget *parent, Qt::WindowFlags f
connect( mBuildQueryButton, SIGNAL( clicked() ), this, SLOT( buildQuery() ) );
}

populateConnectionList();

mSearchModeComboBox->addItem( tr( "Wildcard" ) );
mSearchModeComboBox->addItem( tr( "RegExp" ) );

Expand Down Expand Up @@ -251,6 +251,8 @@ QgsOracleSourceSelect::QgsOracleSourceSelect( QWidget *parent, Qt::WindowFlags f
mSearchModeComboBox->setVisible( false );
mSearchModeLabel->setVisible( false );
mSearchTableEdit->setVisible( false );

populateConnectionList();
}
/** Autoconnected SLOTS **/
// Slot for adding a new connection
Expand All @@ -274,6 +276,8 @@ void QgsOracleSourceSelect::on_btnDelete_clicked()

QgsOracleConn::deleteConnection( cmbConnections->currentText() );

QgsOracleTableCache::removeFromCache( cmbConnections->currentText() );

populateConnectionList();
emit connectionsChanged();
}
Expand Down Expand Up @@ -304,6 +308,9 @@ void QgsOracleSourceSelect::on_btnEdit_clicked()
QgsOracleNewConnection *nc = new QgsOracleNewConnection( this, cmbConnections->currentText() );
if ( nc->exec() )
{
if ( nc->connName() != nc->originalConnName() )
QgsOracleTableCache::renameConnectionInCache( nc->originalConnName(), nc->connName() );

populateConnectionList();
emit connectionsChanged();
}
Expand All @@ -321,6 +328,15 @@ void QgsOracleSourceSelect::on_cmbConnections_currentIndexChanged( const QString
cbxAllowGeometrylessTables->blockSignals( true );
cbxAllowGeometrylessTables->setChecked( QgsOracleConn::allowGeometrylessTables( text ) );
cbxAllowGeometrylessTables->blockSignals( false );

// populate the table list
QgsDataSourceURI uri = QgsOracleConn::connUri( cmbConnections->currentText() );
mConnInfo = uri.connectionInfo();
mUseEstimatedMetadata = uri.useEstimatedMetadata();

QgsDebugMsg( "Connection info: " + uri.connectionInfo() );

loadTableFromCache();
}

void QgsOracleSourceSelect::on_cbxAllowGeometrylessTables_stateChanged( int )
Expand Down Expand Up @@ -452,6 +468,8 @@ void QgsOracleSourceSelect::populateConnectionList()
btnDelete->setDisabled( cmbConnections->count() == 0 );
btnConnect->setDisabled( cmbConnections->count() == 0 );
cmbConnections->setDisabled( cmbConnections->count() == 0 );

on_cmbConnections_currentIndexChanged( cmbConnections->currentText() );
}

// Slot for performing action when the Add button is clicked
Expand Down Expand Up @@ -498,18 +516,12 @@ void QgsOracleSourceSelect::on_btnConnect_clicked()
QModelIndex rootItemIndex = mTableModel.indexFromItem( mTableModel.invisibleRootItem() );
mTableModel.removeRows( 0, mTableModel.rowCount( rootItemIndex ), rootItemIndex );

// populate the table list
QgsDataSourceURI uri = QgsOracleConn::connUri( cmbConnections->currentText() );

QgsDebugMsg( "Connection info: " + uri.connectionInfo() );

mConnInfo = uri.connectionInfo();
mUseEstimatedMetadata = uri.useEstimatedMetadata();

QApplication::setOverrideCursor( Qt::BusyCursor );

QgsDataSourceURI uri = QgsOracleConn::connUri( cmbConnections->currentText() );

mIsConnected = true;
mTablesTreeDelegate->setConn( QgsOracleConn::connectDb( uri.connectionInfo() ) );
mTablesTreeDelegate->setConnectionInfo( uri.connectionInfo() );

mColumnTypeThread = new QgsOracleColumnTypeThread( cmbConnections->currentText(),
mUseEstimatedMetadata,
Expand Down Expand Up @@ -544,8 +556,31 @@ void QgsOracleSourceSelect::finishList()
mTablesTreeView->sortByColumn( QgsOracleTableModel::dbtmOwner, Qt::AscendingOrder );
}

static QgsOracleTableCache::CacheFlags _currentFlags( QString connName, bool useEstimatedMetadata, bool allowGeometrylessTables )
{
QgsOracleTableCache::CacheFlags flags;
if ( QgsOracleConn::geometryColumnsOnly( connName ) )
flags |= QgsOracleTableCache::OnlyLookIntoMetadataTable;
if ( QgsOracleConn::userTablesOnly( connName ) )
flags |= QgsOracleTableCache::OnlyLookForUserTables;
if ( QgsOracleConn::onlyExistingTypes( connName ) )
flags |= QgsOracleTableCache::OnlyExistingGeometryTypes;
if ( useEstimatedMetadata )
flags |= QgsOracleTableCache::UseEstimatedTableMetadata;
if ( allowGeometrylessTables )
flags |= QgsOracleTableCache::AllowGeometrylessTables;
return flags;
}

void QgsOracleSourceSelect::columnThreadFinished()
{
if ( !mColumnTypeThread->isStopped() )
{
QString connName = mColumnTypeThread->connectionName();
QgsOracleTableCache::CacheFlags flags = _currentFlags( connName, mColumnTypeThread->useEstimatedMetadata(), mColumnTypeThread->allowGeometrylessTables() );
QgsOracleTableCache::saveToCache( connName, flags, mColumnTypeThread->layerProperties() );
}

delete mColumnTypeThread;
mColumnTypeThread = 0;
btnConnect->setText( tr( "Connect" ) );
Expand Down Expand Up @@ -628,3 +663,26 @@ void QgsOracleSourceSelect::setSearchExpression( const QString& regexp )
{
Q_UNUSED( regexp );
}

void QgsOracleSourceSelect::loadTableFromCache()
{
QModelIndex rootItemIndex = mTableModel.indexFromItem( mTableModel.invisibleRootItem() );
mTableModel.removeRows( 0, mTableModel.rowCount( rootItemIndex ), rootItemIndex );

QString connName = cmbConnections->currentText();
QVector<QgsOracleLayerProperty> layers;
if ( !QgsOracleTableCache::loadFromCache( connName, _currentFlags( connName, mUseEstimatedMetadata, cbxAllowGeometrylessTables->isChecked() ), layers ) )
return;

foreach ( const QgsOracleLayerProperty& layerProperty, layers )
mTableModel.addTableEntry( layerProperty );

QApplication::setOverrideCursor( Qt::BusyCursor );

QgsDataSourceURI uri = QgsOracleConn::connUri( connName );

mIsConnected = true;
mTablesTreeDelegate->setConnectionInfo( uri.connectionInfo() );

finishList();
}
19 changes: 17 additions & 2 deletions src/providers/oracle/qgsoraclesourceselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,22 @@ class QgsOracleSourceSelectDelegate : public QItemDelegate
void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const;
void setEditorData( QWidget *editor, const QModelIndex &index ) const;

void setConn( QgsOracleConn *conn ) { if ( mConn ) mConn->disconnect(); mConn = conn; }
void setConnectionInfo( const QString& connInfo ) { mConnInfo = connInfo; }

protected:
void setConn( QgsOracleConn *conn ) const { if ( mConn ) mConn->disconnect(); mConn = conn; }

QgsOracleConn* conn() const
{
if ( !mConn )
setConn( QgsOracleConn::connectDb( mConnInfo ) );
return mConn;
}

private:
QgsOracleConn *mConn;
QString mConnInfo;
//! lazily initialized connection (to detect possible primary keys)
mutable QgsOracleConn *mConn;
};


Expand Down Expand Up @@ -136,6 +148,9 @@ class QgsOracleSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
//! Embedded mode, without 'Close'
bool mEmbeddedMode;

//! try to load list of tables from local cache
void loadTableFromCache();

// queue another query for the thread
void addSearchGeometryColumn( QgsOracleLayerProperty layerProperty );

Expand Down
Loading

0 comments on commit 5b72daa

Please sign in to comment.