Merge pull request #5094 from pblottiere/trust2

[FEATURE] Trust project option
This commit is contained in:
Blottiere Paul 2017-09-07 16:21:37 +01:00 committed by GitHub
commit 20d824413e
16 changed files with 432 additions and 26 deletions

View File

@ -785,6 +785,31 @@ Returns the number of registered layers.
:rtype: QgsCoordinateReferenceSystem
%End
void setTrustLayerMetadata( bool trust );
%Docstring
Sets the trust option allowing to indicate if the extent has to be
read from the XML document when data source has no metadata or if the
data provider has to determine it. Moreover, when this option is
activated, primary key unicity is not checked for views and
materialized views with Postgres provider.
\param trust True to trust the project, false otherwise
.. versionadded:: 3.0
%End
bool trustLayerMetadata() const;
%Docstring
Returns true if the trust option is activated, false otherwise. This
option allows indicateing if the extent has to be read from the XML
document when data source has no metadata or if the data provider has
to determine it. Moreover, when this option is activated, primary key
unicity is not checked for views and materialized views with Postgres
provider.
.. versionadded:: 3.0
:rtype: bool
%End
signals:
void readProject( const QDomDocument & );

View File

@ -524,6 +524,15 @@ Returns a list of available encodings
:rtype: str
%End
virtual bool hasMetadata() const;
%Docstring
Returns true if the data source has metadata, false otherwise.
:return: true if data source has metadata, false otherwise.
.. versionadded:: 3.0
:rtype: bool
%End
signals:
void raiseError( const QString &msg ) const;

View File

@ -315,7 +315,8 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator, QgsFeatureSin
};
QgsVectorLayer( const QString &path = QString(), const QString &baseName = QString(),
const QString &providerLib = "ogr", bool loadDefaultStyleFlag = true );
const QString &providerLib = "ogr", bool loadDefaultStyleFlag = true,
bool readExtentFromXml = false );
%Docstring
Constructor - creates a vector layer
@ -328,6 +329,7 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator, QgsFeatureSin
\param baseName The name used to represent the layer in the legend
\param providerLib The name of the data provider, e.g., "memory", "postgres"
\param loadDefaultStyleFlag whether to load the default style
\param readExtentFromXml Read extent from XML if true or let provider determine it if false
%End
@ -1727,6 +1729,25 @@ Returns the current blending mode for features
.. versionadded:: 3.0
%End
void setReadExtentFromXml( bool readExtentFromXml );
%Docstring
Flag allowing to indicate if the extent has to be read from the XML
document when data source has no metadata or if the data provider has
to determine it.
.. versionadded:: 3.0
%End
bool readExtentFromXml() const;
%Docstring
Returns true if the extent is read from the XML document when data
source has no metadata, false if it's the data provider which determines
it.
.. versionadded:: 3.0
:rtype: bool
%End
public slots:
void select( QgsFeatureId featureId );
@ -1772,10 +1793,12 @@ Returns the current blending mode for features
.. seealso:: selectByIds()
%End
virtual void updateExtents();
virtual void updateExtents( bool force = false );
%Docstring
Update the extents for the layer. This is necessary if features are
added/deleted or the layer has been subsetted.
\param force true to update layer extent even if it's read from xml by default, false otherwise
%End
bool startEditing();

View File

@ -708,6 +708,7 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
mAutoTransaction->setChecked( QgsProject::instance()->autoTransaction() );
mEvaluateDefaultValues->setChecked( QgsProject::instance()->evaluateDefaultValues() );
mTrustProjectCheckBox->setChecked( QgsProject::instance()->trustLayerMetadata() );
// Variables editor
mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
@ -764,6 +765,7 @@ void QgsProjectProperties::apply()
QgsProject::instance()->setTitle( title() );
QgsProject::instance()->setAutoTransaction( mAutoTransaction->isChecked() );
QgsProject::instance()->setEvaluateDefaultValues( mEvaluateDefaultValues->isChecked() );
QgsProject::instance()->setTrustLayerMetadata( mTrustProjectCheckBox->isChecked() );
// set the mouse display precision method and the
// number of decimal places for the manual option

View File

@ -1387,7 +1387,7 @@ void QgsVectorLayerProperties::setPbnQueryBuilderEnabled()
void QgsVectorLayerProperties::on_pbnUpdateExtents_clicked()
{
mLayer->updateExtents();
mLayer->updateExtents( true ); // force update whatever options activated
mMetadataFilled = false;
}

View File

@ -474,12 +474,6 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, const QgsReadWr
setAutoRefreshInterval( layerElement.attribute( QStringLiteral( "autoRefreshTime" ), 0 ).toInt() );
setAutoRefreshEnabled( layerElement.attribute( QStringLiteral( "autoRefreshEnabled" ), QStringLiteral( "0" ) ).toInt() );
QDomNode extentNode = layerElement.namedItem( QStringLiteral( "extent" ) );
if ( !extentNode.isNull() )
{
setExtent( QgsXmlUtils::readRectangle( extentNode.toElement() ) );
}
// set name
mnl = layerElement.namedItem( QStringLiteral( "layername" ) );
mne = mnl.toElement();
@ -575,7 +569,7 @@ bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &docume
layerElement.setAttribute( QStringLiteral( "maxScale" ), QString::number( maximumScale() ) );
layerElement.setAttribute( QStringLiteral( "minScale" ), QString::number( minimumScale() ) );
if ( !mExtent.isNull() )
if ( !extent().isNull() )
{
layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
}

View File

@ -480,6 +480,7 @@ void QgsProject::clear()
mAutoTransaction = false;
mEvaluateDefaultValues = false;
mDirty = false;
mTrustLayerMetadata = false;
mCustomVariables.clear();
mEmbeddedLayers.clear();
@ -717,6 +718,12 @@ bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &broken
if ( type == QLatin1String( "vector" ) )
{
mapLayer = new QgsVectorLayer;
// apply specific settings to vector layer
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mapLayer ) )
{
vl->setReadExtentFromXml( mTrustLayerMetadata );
}
}
else if ( type == QLatin1String( "raster" ) )
{
@ -892,6 +899,14 @@ bool QgsProject::readProjectFile( const QString &filename )
mEvaluateDefaultValues = true;
}
nl = doc->elementsByTagName( QStringLiteral( "trust" ) );
if ( nl.count() )
{
QDomElement trustElement = nl.at( 0 ).toElement();
if ( trustElement.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
mTrustLayerMetadata = true;
}
// read the layer tree from project file
mRootGroup->setCustomProperty( QStringLiteral( "loading" ), 1 );
@ -1296,6 +1311,10 @@ bool QgsProject::writeProjectFile( const QString &filename )
evaluateDefaultValuesNode.setAttribute( QStringLiteral( "active" ), mEvaluateDefaultValues ? "1" : "0" );
qgisNode.appendChild( evaluateDefaultValuesNode );
QDomElement trustNode = doc->createElement( QStringLiteral( "trust" ) );
trustNode.setAttribute( QStringLiteral( "active" ), mTrustLayerMetadata ? "1" : "0" );
qgisNode.appendChild( trustNode );
QDomText titleText = doc->createTextNode( title() ); // XXX why have title TWICE?
titleNode.appendChild( titleText );
@ -2260,3 +2279,17 @@ QgsCoordinateReferenceSystem QgsProject::defaultCrsForNewLayers() const
return defaultCrs;
}
void QgsProject::setTrustLayerMetadata( bool trust )
{
mTrustLayerMetadata = trust;
Q_FOREACH ( QgsMapLayer *layer, mapLayers().values() )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
if ( vl )
{
vl->setReadExtentFromXml( trust );
}
}
}

View File

@ -755,6 +755,30 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
QgsCoordinateReferenceSystem defaultCrsForNewLayers() const;
/**
* Sets the trust option allowing to indicate if the extent has to be
* read from the XML document when data source has no metadata or if the
* data provider has to determine it. Moreover, when this option is
* activated, primary key unicity is not checked for views and
* materialized views with Postgres provider.
*
* \param trust True to trust the project, false otherwise
*
* \since QGIS 3.0
*/
void setTrustLayerMetadata( bool trust );
/**
* Returns true if the trust option is activated, false otherwise. This
* option allows indicateing if the extent has to be read from the XML
* document when data source has no metadata or if the data provider has
* to determine it. Moreover, when this option is activated, primary key
* unicity is not checked for views and materialized views with Postgres
* provider.
*
* \since QGIS 3.0
*/
bool trustLayerMetadata() const { return mTrustLayerMetadata; }
signals:
//! emitted when project is being read
@ -1083,6 +1107,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
bool mEvaluateDefaultValues; // evaluate default values immediately
QgsCoordinateReferenceSystem mCrs;
bool mDirty; // project has been modified since it has been read or saved
bool mTrustLayerMetadata = false;
};
/** Return the version string found in the given DOM document

View File

@ -516,6 +516,14 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual QString translateMetadataValue( const QString &mdKey, const QVariant &value ) const { Q_UNUSED( mdKey ); return value.toString(); }
/** Returns true if the data source has metadata, false otherwise.
*
* \returns true if data source has metadata, false otherwise.
*
* \since QGIS 3.0
*/
virtual bool hasMetadata() const { return true; };
signals:
/**

View File

@ -133,7 +133,8 @@ typedef bool deleteStyleById_t(
QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
const QString &baseName,
const QString &providerKey,
bool loadDefaultStyleFlag )
bool loadDefaultStyleFlag,
bool readExtentFromXml )
: QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
, mDataProvider( nullptr )
, mProviderKey( providerKey )
@ -153,6 +154,7 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
, mLazyExtent( true )
, mSymbolFeatureCounted( false )
, mEditCommandActive( false )
, mReadExtentFromXml( readExtentFromXml )
{
mActions = new QgsActionManager( this );
@ -222,6 +224,7 @@ QgsVectorLayer *QgsVectorLayer::clone() const
layer->setAttributeTableConfig( attributeTableConfig() );
layer->setFeatureBlendMode( featureBlendMode() );
layer->setOpacity( opacity() );
layer->setReadExtentFromXml( readExtentFromXml() );
Q_FOREACH ( const QgsAction &action, actions()->actions() )
{
@ -779,9 +782,11 @@ bool QgsVectorLayer::countSymbolFeatures()
return true;
}
void QgsVectorLayer::updateExtents()
void QgsVectorLayer::updateExtents( bool force )
{
mValidExtent = false;
// do not update extent by default when trust project option is activated
if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent.isNull() ) )
mValidExtent = false;
}
void QgsVectorLayer::setExtent( const QgsRectangle &r )
@ -798,6 +803,14 @@ QgsRectangle QgsVectorLayer::extent() const
if ( !isSpatial() )
return rect;
if ( !mValidExtent && mLazyExtent && mDataProvider && !mDataProvider->hasMetadata() && mReadExtentFromXml && !mXmlExtent.isNull() )
{
mExtent = mXmlExtent;
mValidExtent = true;
mLazyExtent = false;
}
if ( !mValidExtent && mLazyExtent && mDataProvider )
{
// get the extent
@ -1428,6 +1441,16 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, const QgsReadWriteCont
setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
// read extent
if ( mReadExtentFromXml )
{
QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
if ( !extentNode.isNull() )
{
mXmlExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
}
}
return mValid; // should be true if read successfully
} // void QgsVectorLayer::readXml
@ -1476,12 +1499,28 @@ void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &ba
bool QgsVectorLayer::setDataProvider( QString const &provider )
{
mProviderKey = provider; // XXX is this necessary? Usually already set
// primary key unicity is tested at construction time, so it has to be set
// before initializing postgres provider
QString checkUnicityKey = QStringLiteral( "checkPrimaryKeyUnicity" );
QString dataSource = mDataSource;
if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
{
QgsDataSourceUri uri( dataSource );
if ( uri.hasParam( checkUnicityKey ) )
uri.removeParam( checkUnicityKey );
uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
dataSource = uri.uri( false );
}
// XXX when execution gets here.
//XXX - This was a dynamic cast but that kills the Windows
// version big-time with an abnormal termination error
delete mDataProvider;
mDataProvider = ( QgsVectorDataProvider * )( QgsProviderRegistry::instance()->createProvider( provider, mDataSource ) );
mDataProvider = ( QgsVectorDataProvider * )( QgsProviderRegistry::instance()->createProvider( provider, dataSource ) );
if ( !mDataProvider )
{
QgsDebugMsg( " unable to get data provider" );
@ -1500,7 +1539,7 @@ bool QgsVectorLayer::setDataProvider( QString const &provider )
}
// TODO: Check if the provider has the capability to send fullExtentCalculated
connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, &QgsVectorLayer::updateExtents );
connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
// get and store the feature type
mWkbType = mDataProvider->wkbType();
@ -1537,7 +1576,11 @@ bool QgsVectorLayer::setDataProvider( QString const &provider )
QgsDebugMsg( "Beautified layer name " + name() );
// deal with unnecessary schema qualification to make v.in.ogr happy
mDataSource = mDataProvider->dataSourceUri();
// and remove unnecessary key
QgsDataSourceUri dataProviderUri( mDataProvider->dataSourceUri() );
if ( dataProviderUri.hasParam( checkUnicityKey ) )
dataProviderUri.removeParam( checkUnicityKey );
mDataSource = dataProviderUri.uri( false );
}
else if ( mProviderKey == QLatin1String( "osm" ) )
{
@ -4418,3 +4461,13 @@ QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties
return labeling;
}
void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )
{
mReadExtentFromXml = readExtentFromXml;
}
bool QgsVectorLayer::readExtentFromXml() const
{
return mReadExtentFromXml;
}

View File

@ -389,10 +389,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* \param baseName The name used to represent the layer in the legend
* \param providerLib The name of the data provider, e.g., "memory", "postgres"
* \param loadDefaultStyleFlag whether to load the default style
* \param readExtentFromXml Read extent from XML if true or let provider determine it if false
*
*/
QgsVectorLayer( const QString &path = QString(), const QString &baseName = QString(),
const QString &providerLib = "ogr", bool loadDefaultStyleFlag = true );
const QString &providerLib = "ogr", bool loadDefaultStyleFlag = true,
bool readExtentFromXml = false );
virtual ~QgsVectorLayer();
@ -1604,6 +1606,24 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
void setEditFormConfig( const QgsEditFormConfig &editFormConfig );
/**
* Flag allowing to indicate if the extent has to be read from the XML
* document when data source has no metadata or if the data provider has
* to determine it.
*
* \since QGIS 3.0
*/
void setReadExtentFromXml( bool readExtentFromXml );
/**
* Returns true if the extent is read from the XML document when data
* source has no metadata, false if it's the data provider which determines
* it.
*
* \since QGIS 3.0
*/
bool readExtentFromXml() const;
public slots:
/**
@ -1651,8 +1671,10 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
/** Update the extents for the layer. This is necessary if features are
* added/deleted or the layer has been subsetted.
*
* \param force true to update layer extent even if it's read from xml by default, false otherwise
*/
virtual void updateExtents();
virtual void updateExtents( bool force = false );
/**
* Make layer editable.
@ -2041,6 +2063,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! True while an undo command is active
bool mEditCommandActive;
bool mReadExtentFromXml;
QgsRectangle mXmlExtent;
QgsFeatureIds mDeletedFids;
QgsAttributeTableConfig mAttributeTableConfig;

View File

@ -37,6 +37,7 @@
#include "qgspostgrestransaction.h"
#include "qgslogger.h"
#include "qgsfeedback.h"
#include "qgssettings.h"
#ifdef HAVE_GUI
#include "qgspgsourceselect.h"
@ -114,6 +115,18 @@ QgsPostgresProvider::QgsPostgresProvider( QString const &uri )
mRequestedSrid = mUri.srid();
mRequestedGeomType = mUri.wkbType();
if ( mUri.hasParam( QStringLiteral( "checkPrimaryKeyUnicity" ) ) )
{
if ( mUri.param( QStringLiteral( "checkPrimaryKeyUnicity" ) ).compare( "0" ) == 0 )
{
mCheckPrimaryKeyUnicity = false;
}
else
{
mCheckPrimaryKeyUnicity = true;
}
}
if ( mSchemaName.isEmpty() && mTableName.startsWith( '(' ) && mTableName.endsWith( ')' ) )
{
mIsQuery = true;
@ -1285,11 +1298,9 @@ bool QgsPostgresProvider::determinePrimaryKey()
// If the relation is a view try to find a suitable column to use as
// the primary key.
sql = QStringLiteral( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
res = connectionRO()->PQexec( sql );
QString type = res.PQgetvalue( 0, 0 );
QgsPostgresProvider::Relkind type = relkind();
if ( type == QLatin1String( "r" ) ) // the relation is a table
if ( type == Relkind::OrdinaryTable )
{
QgsDebugMsg( "Relation is a table. Checking to see if it has an oid column." );
@ -1324,13 +1335,15 @@ bool QgsPostgresProvider::determinePrimaryKey()
}
}
}
else if ( type == QLatin1String( "v" ) || type == QLatin1String( "m" ) ) // the relation is a view
else if ( type == Relkind::View || type == Relkind::MaterializedView )
{
determinePrimaryKeyFromUriKeyColumn();
}
else
{
QgsMessageLog::logMessage( tr( "Unexpected relation type '%1'." ).arg( type ), tr( "PostGIS" ) );
const QMetaEnum metaEnum( QMetaEnum::fromType<Relkind>() );
QString typeName = metaEnum.valueToKey( type );
QgsMessageLog::logMessage( tr( "Unexpected relation type '%1'." ).arg( typeName ), tr( "PostGIS" ) );
}
}
else
@ -1485,7 +1498,13 @@ void QgsPostgresProvider::determinePrimaryKeyFromUriKeyColumn()
if ( !mPrimaryKeyAttrs.isEmpty() )
{
if ( mUseEstimatedMetadata || uniqueData( primaryKey ) )
bool unique = true;
if ( mCheckPrimaryKeyUnicity )
{
unique = uniqueData( primaryKey );
}
if ( mUseEstimatedMetadata || unique )
{
mPrimaryKeyType = PktFidMap; // Map by default
if ( mPrimaryKeyAttrs.size() == 1 )
@ -4247,6 +4266,63 @@ QgsAttrPalIndexNameHash QgsPostgresProvider::palAttributeIndexNames() const
return mAttrPalIndexName;
}
QgsPostgresProvider::Relkind QgsPostgresProvider::relkind() const
{
QString sql = QStringLiteral( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
QString type = res.PQgetvalue( 0, 0 );
QgsPostgresProvider::Relkind kind = Relkind::Unknown;
if ( type == QLatin1String( "r" ) )
{
kind = Relkind::OrdinaryTable;
}
else if ( type == QLatin1String( "i" ) )
{
kind = Relkind::Index;
}
else if ( type == QLatin1String( "s" ) )
{
kind = Relkind::Sequence;
}
else if ( type == QLatin1String( "v" ) )
{
kind = Relkind::View;
}
else if ( type == QLatin1String( "m" ) )
{
kind = Relkind::MaterializedView;
}
else if ( type == QLatin1String( "c" ) )
{
kind = Relkind::CompositeType;
}
else if ( type == QLatin1String( "t" ) )
{
kind = Relkind::ToastTable;
}
else if ( type == QLatin1String( "f" ) )
{
kind = Relkind::ForeignTable;
}
return kind;
}
bool QgsPostgresProvider::hasMetadata() const
{
bool hasMetadata = true;
QgsPostgresProvider::Relkind kind = relkind();
if ( kind == Relkind::View || kind == Relkind::MaterializedView )
{
hasMetadata = false;
}
return hasMetadata;
}
/**
* Class factory to return a pointer to a newly created
* QgsPostgresProvider object

View File

@ -48,6 +48,19 @@ class QgsPostgresProvider : public QgsVectorDataProvider
Q_OBJECT
public:
enum Relkind
{
Unknown,
OrdinaryTable, // r
Index, // i
Sequence, // s
View, // v
MaterializedView, // m
CompositeType, // c
ToastTable, // t
ForeignTable // f
};
Q_ENUM( Relkind );
/** Import a vector layer into the database
* \param options options for provider, specified via a map of option name
@ -184,6 +197,17 @@ class QgsPostgresProvider : public QgsVectorDataProvider
virtual QList<QgsRelation> discoverRelations( const QgsVectorLayer *self, const QList<QgsVectorLayer *> &layers ) const override;
virtual QgsAttrPalIndexNameHash palAttributeIndexNames() const override;
/** Returns true if the data source has metadata, false otherwise. For
* example, if the kind of relation for the layer is a view or a
* materialized view, then no metadata are associated with the data
* source.
*
* \returns true if data source has metadata, false otherwise.
*
* \since QGIS 3.0
*/
virtual bool hasMetadata() const override;
signals:
/**
@ -206,6 +230,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
void repaintRequested();
private:
Relkind relkind() const;
bool declareCursor( const QString &cursorName,
const QgsAttributeList &fetchAttributes,
@ -407,6 +432,8 @@ class QgsPostgresProvider : public QgsVectorDataProvider
void setTransaction( QgsTransaction *transaction ) override;
QHash<int, QString> mDefaultValues;
bool mCheckPrimaryKeyUnicity = true;
};

View File

@ -2491,6 +2491,16 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="mTrustProjectCheckBox">
<property name="toolTip">
<string>Speed up project loading by skipping data checks. Useful in qgis server context or project with huge database views or materialized views.</string>
</property>
<property name="text">
<string>Trust project when data source has no metadata</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mTab_Variables">

View File

@ -28,11 +28,14 @@ from qgis.core import (
NULL,
QgsVectorLayerUtils,
QgsSettings,
QgsTransactionGroup
QgsTransactionGroup,
QgsReadWriteContext,
QgsRectangle
)
from qgis.gui import QgsGui
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir
from qgis.testing import start_app, unittest
from qgis.PyQt.QtXml import QDomDocument
from utilities import unitTestDataPath
from providertestbase import ProviderTestCase
@ -718,6 +721,94 @@ class TestPyQgsPostgresProvider(unittest.TestCase, ProviderTestCase):
self.assertEqual(desclist, [])
self.assertEqual(errmsg, "")
def testHasMetadata(self):
# views don't have metadata
vl = QgsVectorLayer('{} table="qgis_test"."{}" key="pk" sql='.format(self.dbconn, 'bikes_view'), "bikes_view", "postgres")
self.assertTrue(vl.isValid())
self.assertFalse(vl.dataProvider().hasMetadata())
# ordinary tables have metadata
vl = QgsVectorLayer('%s table="qgis_test"."someData" sql=' % (self.dbconn), "someData", "postgres")
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().hasMetadata())
def testReadExtentOnView(self):
# vector layer based on view
vl0 = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data_view" (geom) sql=', 'test', 'postgres')
self.assertTrue(vl0.isValid())
self.assertFalse(vl0.dataProvider().hasMetadata())
# set a custom extent
originalExtent = vl0.extent()
customExtent = QgsRectangle(-80, 80, -70, 90)
vl0.setExtent(customExtent)
# write xml
doc = QDomDocument("testdoc")
elem = doc.createElement("maplayer")
self.assertTrue(vl0.writeLayerXml(elem, doc, QgsReadWriteContext()))
# read xml with the custom extent. It should not be used by default
vl1 = QgsVectorLayer()
vl1.readLayerXml(elem, QgsReadWriteContext())
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.extent(), originalExtent)
# read xml with custom extent with readExtent option. Extent read from
# xml document should be used because we have a view
vl2 = QgsVectorLayer()
vl2.setReadExtentFromXml(True)
vl2.readLayerXml(elem, QgsReadWriteContext())
self.assertTrue(vl2.isValid())
self.assertEqual(vl2.extent(), customExtent)
# but a force update on extent should allow retrieveing the data
# provider extent
vl2.updateExtents()
vl2.readLayerXml(elem, QgsReadWriteContext())
self.assertEqual(vl2.extent(), customExtent)
vl2.updateExtents(force=True)
vl2.readLayerXml(elem, QgsReadWriteContext())
self.assertEqual(vl2.extent(), originalExtent)
def testReadExtentOnTable(self):
# vector layer based on a standard table
vl0 = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', 'test', 'postgres')
self.assertTrue(vl0.isValid())
self.assertTrue(vl0.dataProvider().hasMetadata())
# set a custom extent
originalExtent = vl0.extent()
customExtent = QgsRectangle(-80, 80, -70, 90)
vl0.setExtent(customExtent)
# write xml
doc = QDomDocument("testdoc")
elem = doc.createElement("maplayer")
self.assertTrue(vl0.writeLayerXml(elem, doc, QgsReadWriteContext()))
# read xml with the custom extent. It should not be used by default
vl1 = QgsVectorLayer()
vl1.readLayerXml(elem, QgsReadWriteContext())
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.extent(), originalExtent)
# read xml with custom extent with readExtent option. Extent read from
# xml document should NOT be used because we don't have a view or a
# materialized view
vl2 = QgsVectorLayer()
vl2.setReadExtentFromXml(True)
vl2.readLayerXml(elem, QgsReadWriteContext())
self.assertTrue(vl2.isValid())
self.assertEqual(vl2.extent(), originalExtent)
class TestPyQgsPostgresProviderCompoundKey(unittest.TestCase, ProviderTestCase):

View File

@ -47,6 +47,11 @@ CREATE TABLE qgis_test."some_poly_data" (
geom public.geometry(Polygon,4326)
);
CREATE OR REPLACE VIEW qgis_test.some_poly_data_view
AS
SELECT *
FROM qgis_test.some_poly_data;
--
-- TOC entry 4068 (class 0 OID 377761)
-- Dependencies: 171