Skip to content
Permalink
Browse files

[FEATURE][oracle] Allow restricting table list for a connection

to a specific schema

This allows a schema to be set in the connection properties for
an oracle db connection. If set, only tables within that schema
will be scanned and listed for the connection.

Previously the option existed to restrict the scan to tables
which belong to the user, but this option does not support
the use case where a connection must access tables from a different
user, and the default "scan everything" setting is too expensive
(since it often takes multiple minutes to perform, especially
when geometryless tables are shown).

Sponsored by Open Spatial (http://www.openspatial.com)
  • Loading branch information
nyalldawson committed Apr 22, 2018
1 parent 31faa11 commit 2273dfacb607246f946b4637cce86bfdb24e21c1
@@ -548,6 +548,7 @@ QDomDocument QgsManageConnectionsDialog::saveOracleConnections( const QStringLis
el.setAttribute( QStringLiteral( "database" ), settings.value( path + "/database", "" ).toString() );
el.setAttribute( QStringLiteral( "dboptions" ), settings.value( path + "/dboptions", "" ).toString() );
el.setAttribute( QStringLiteral( "dbworkspace" ), settings.value( path + "/dbworkspace", "" ).toString() );
el.setAttribute( QStringLiteral( "schema" ), settings.value( path + "/schema", QString() ).toString() );
el.setAttribute( QStringLiteral( "estimatedMetadata" ), settings.value( path + "/estimatedMetadata", "0" ).toString() );
el.setAttribute( QStringLiteral( "userTablesOnly" ), settings.value( path + "/userTablesOnly", "0" ).toString() );
el.setAttribute( QStringLiteral( "geometryColumnsOnly" ), settings.value( path + "/geometryColumnsOnly", "0" ).toString() );
@@ -1088,6 +1089,7 @@ void QgsManageConnectionsDialog::loadOracleConnections( const QDomDocument &doc,
settings.setValue( QStringLiteral( "/database" ), child.attribute( QStringLiteral( "database" ) ) );
settings.setValue( QStringLiteral( "/dboptions" ), child.attribute( QStringLiteral( "dboptions" ) ) );
settings.setValue( QStringLiteral( "/dbworkspace" ), child.attribute( QStringLiteral( "dbworkspace" ) ) );
settings.setValue( QStringLiteral( "/schema" ), child.attribute( QStringLiteral( "schema" ) ) );
settings.setValue( QStringLiteral( "/estimatedMetadata" ), child.attribute( QStringLiteral( "estimatedMetadata" ) ) );
settings.setValue( QStringLiteral( "/userTablesOnly" ), child.attribute( QStringLiteral( "userTablesOnly" ) ) );
settings.setValue( QStringLiteral( "/geometryColumnsOnly" ), child.attribute( QStringLiteral( "geometryColumnsOnly" ) ) );
@@ -21,9 +21,10 @@ email : jef at norbit dot de

#include <QMetaType>

QgsOracleColumnTypeThread::QgsOracleColumnTypeThread( const QString &name, bool useEstimatedMetadata, bool allowGeometrylessTables )
QgsOracleColumnTypeThread::QgsOracleColumnTypeThread( const QString &name, const QString &limitToSchema, bool useEstimatedMetadata, bool allowGeometrylessTables )
: QThread()
, mName( name )
, mSchema( limitToSchema )
, mUseEstimatedMetadata( useEstimatedMetadata )
, mAllowGeometrylessTables( allowGeometrylessTables )
, mStopped( false )
@@ -52,6 +53,7 @@ void QgsOracleColumnTypeThread::run()
emit progressMessage( tr( "Retrieving tables of %1…" ).arg( mName ) );
QVector<QgsOracleLayerProperty> layerProperties;
if ( !conn->supportedLayers( layerProperties,
mSchema,
QgsOracleConn::geometryColumnsOnly( mName ),
QgsOracleConn::userTablesOnly( mName ),
mAllowGeometrylessTables ) ||
@@ -28,7 +28,16 @@ class QgsOracleColumnTypeThread : public QThread
{
Q_OBJECT
public:

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

@@ -54,6 +63,7 @@ class QgsOracleColumnTypeThread : public QThread
QgsOracleColumnTypeThread() = default;

QString mName;
QString mSchema;
bool mUseEstimatedMetadata = false;
bool mAllowGeometrylessTables = false;
bool mStopped = false;
@@ -240,7 +240,7 @@ QStringList QgsOracleConn::pkCandidates( const QString &ownerName, const QString
return cols;
}

bool QgsOracleConn::tableInfo( bool geometryColumnsOnly, bool userTablesOnly, bool allowGeometrylessTables )
bool QgsOracleConn::tableInfo( const QString &schema, bool geometryColumnsOnly, bool userTablesOnly, bool allowGeometrylessTables )
{
QgsDebugMsgLevel( QStringLiteral( "Entering." ), 4 );

@@ -258,16 +258,18 @@ bool QgsOracleConn::tableInfo( bool geometryColumnsOnly, bool userTablesOnly, bo
.arg( geometryColumnsOnly ? QStringLiteral( "c.srid" ) : QStringLiteral( "NULL AS srid" ) )
.arg( prefix )
.arg( geometryColumnsOnly ? QStringLiteral( "sdo_geom_metadata" ) : QStringLiteral( "tab_columns" ) )
.arg( userTablesOnly ? QStringLiteral( "" ) : QStringLiteral( " AND c.owner='xxxxSCHEMAxxxx'" ) )
.arg( userTablesOnly ? QString() : QStringLiteral( " AND c.owner=%1" ).arg( schema.isEmpty() ? QStringLiteral( "o.owner" ) : quotedValue( schema ) ) )
.arg( geometryColumnsOnly ? QString() : QStringLiteral( " WHERE c.data_type='SDO_GEOMETRY'" ) );

if ( allowGeometrylessTables )
{

// also here!
sql += QStringLiteral( " UNION SELECT %1,object_name,NULL AS column_name,NULL AS srid,object_type AS type"
" FROM %2_objects c WHERE c.object_type IN ('TABLE','VIEW','SYNONYM')" )
.arg( owner, prefix );
" FROM %2_objects c WHERE c.object_type IN ('TABLE','VIEW','SYNONYM') %3" )
.arg( owner,
prefix,
userTablesOnly || schema.isEmpty() ? QString() : QStringLiteral( " AND c.owner=%1" ).arg( quotedValue( schema ) ) );
}

// sql = "SELECT * FROM (" + sql + ")";
@@ -302,10 +304,10 @@ bool QgsOracleConn::tableInfo( bool geometryColumnsOnly, bool userTablesOnly, bo
return true;
}

bool QgsOracleConn::supportedLayers( QVector<QgsOracleLayerProperty> &layers, bool geometryTablesOnly, bool userTablesOnly, bool allowGeometrylessTables )
bool QgsOracleConn::supportedLayers( QVector<QgsOracleLayerProperty> &layers, const QString &limitToSchema, bool geometryTablesOnly, bool userTablesOnly, bool allowGeometrylessTables )
{
// Get the list of supported tables
if ( !tableInfo( geometryTablesOnly, userTablesOnly, allowGeometrylessTables ) )
if ( !tableInfo( limitToSchema, geometryTablesOnly, userTablesOnly, allowGeometrylessTables ) )
{
QgsMessageLog::logMessage( tr( "Unable to get list of spatially enabled tables from the database" ), tr( "Oracle" ) );
return false;
@@ -786,6 +788,12 @@ bool QgsOracleConn::userTablesOnly( const QString &connName )
return settings.value( "/Oracle/connections/" + connName + "/userTablesOnly", false ).toBool();
}

QString QgsOracleConn::restrictToSchema( const QString &connName )
{
QgsSettings settings;
return settings.value( "/Oracle/connections/" + connName + "/schema" ).toString();
}

bool QgsOracleConn::geometryColumnsOnly( const QString &connName )
{
QgsSettings settings;
@@ -127,16 +127,27 @@ class QgsOracleConn : public QObject
*/
static QString quotedValue( const QVariant &value, QVariant::Type type = QVariant::Invalid );

//! Get the list of supported layers
/**
* Get the list of supported layers.
*
* If \a limitToSchema is specified, than only layers from the matching schema will be
* returned.
*
*/
bool supportedLayers( QVector<QgsOracleLayerProperty> &layers,
const QString &limitToSchema,
bool geometryTablesOnly,
bool userTablesOnly = true,
bool allowGeometrylessTables = false );

void retrieveLayerTypes( QgsOracleLayerProperty &layerProperty, bool useEstimatedMetadata, bool onlyExistingTypes );

//! Gets information about the spatial tables
bool tableInfo( bool geometryTablesOnly, bool userTablesOnly, bool allowGeometrylessTables );
/**
* Gets information about the spatial tables.
*
* If \a schema is specified, only tables from this schema will be retrieved.
*/
bool tableInfo( const QString &schema, bool geometryTablesOnly, bool userTablesOnly, bool allowGeometrylessTables );

//! Get primary key candidates (all int4 columns)
QStringList pkCandidates( const QString &ownerName, const QString &viewName );
@@ -163,6 +174,7 @@ class QgsOracleConn : public QObject
static void setSelectedConnection( const QString &connName );
static QgsDataSourceUri connUri( const QString &connName );
static bool userTablesOnly( const QString &connName );
static QString restrictToSchema( const QString &connName );
static bool geometryColumnsOnly( const QString &connName );
static bool allowGeometrylessTables( const QString &connName );
static bool estimatedMetadata( const QString &connName );
@@ -91,6 +91,7 @@ QVector<QgsDataItem *> QgsOracleConnectionItem::createChildren()
if ( !mColumnTypeThread )
{
mColumnTypeThread = new QgsOracleColumnTypeThread( mName,
QgsOracleConn::restrictToSchema( mName ),
/* useEstimatedMetadata */ true,
QgsOracleConn::allowGeometrylessTables( mName ) );

@@ -30,6 +30,9 @@ QgsOracleNewConnection::QgsOracleNewConnection( QWidget *parent, const QString &
, mOriginalConnName( connName )
{
setupUi( this );

txtSchema->setShowClearButton( true );

connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsOracleNewConnection::showHelp );
connect( btnConnect, &QPushButton::clicked, this, &QgsOracleNewConnection::testConnection );

@@ -50,6 +53,7 @@ QgsOracleNewConnection::QgsOracleNewConnection( QWidget *parent, const QString &
txtPort->setText( port );
txtOptions->setText( settings.value( key + QStringLiteral( "/dboptions" ) ).toString() );
txtWorkspace->setText( settings.value( key + QStringLiteral( "/dbworkspace" ) ).toString() );
txtSchema->setText( settings.value( key + QStringLiteral( "/schema" ) ).toString() );
cb_userTablesOnly->setChecked( settings.value( key + QStringLiteral( "/userTablesOnly" ), false ).toBool() );
cb_geometryColumnsOnly->setChecked( settings.value( key + QStringLiteral( "/geometryColumnsOnly" ), true ).toBool() );
cb_allowGeometrylessTables->setChecked( settings.value( key + QStringLiteral( "/allowGeometrylessTables" ), false ).toBool() );
@@ -136,6 +140,7 @@ void QgsOracleNewConnection::accept()
settings.setValue( baseKey + QStringLiteral( "/savePassword" ), chkStorePassword->isChecked() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
settings.setValue( baseKey + QStringLiteral( "/dboptions" ), txtOptions->text() );
settings.setValue( baseKey + QStringLiteral( "/dbworkspace" ), txtWorkspace->text() );
settings.setValue( baseKey + QStringLiteral( "/schema" ), txtSchema->text() );

QDialog::accept();
}
@@ -44,7 +44,7 @@ QWidget *QgsOracleSourceSelectDelegate::createEditor( QWidget *parent, const QSt

QString tableName = index.sibling( index.row(), QgsOracleTableModel::DbtmTable ).data( Qt::DisplayRole ).toString();
if ( tableName.isEmpty() )
return 0;
return nullptr;

if ( index.column() == QgsOracleTableModel::DbtmSql )
{
@@ -515,6 +515,7 @@ void QgsOracleSourceSelect::on_btnConnect_clicked()
mTablesTreeDelegate->setConnectionInfo( uri );

mColumnTypeThread = new QgsOracleColumnTypeThread( cmbConnections->currentText(),
QgsOracleConn::restrictToSchema( cmbConnections->currentText() ),
uri.useEstimatedMetadata(),
cbxAllowGeometrylessTables->isChecked() );

0 comments on commit 2273dfa

Please sign in to comment.
You can’t perform that action at this time.