mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-16 00:06:09 -05:00
Merge pull request #55924 from elpaso/bugfix-gh55726-restore-default-metadata
Restore default metadata from DB
This commit is contained in:
commit
1850b9b2e6
@ -25,6 +25,7 @@ QgsProviderMetadata.ProviderMetadataCapabilities = lambda flags=0: QgsProviderMe
|
|||||||
QgsProviderMetadata.FileBasedUris = QgsProviderMetadata.ProviderCapability.FileBasedUris
|
QgsProviderMetadata.FileBasedUris = QgsProviderMetadata.ProviderCapability.FileBasedUris
|
||||||
QgsProviderMetadata.SaveLayerMetadata = QgsProviderMetadata.ProviderCapability.SaveLayerMetadata
|
QgsProviderMetadata.SaveLayerMetadata = QgsProviderMetadata.ProviderCapability.SaveLayerMetadata
|
||||||
QgsProviderMetadata.ParallelCreateProvider = QgsProviderMetadata.ProviderCapability.ParallelCreateProvider
|
QgsProviderMetadata.ParallelCreateProvider = QgsProviderMetadata.ProviderCapability.ParallelCreateProvider
|
||||||
|
QgsProviderMetadata.LoadLayerMetadata = QgsProviderMetadata.ProviderCapability.LoadLayerMetadata
|
||||||
QgsProviderMetadata.ProviderCapabilities = lambda flags=0: QgsProviderMetadata.ProviderCapability(flags)
|
QgsProviderMetadata.ProviderCapabilities = lambda flags=0: QgsProviderMetadata.ProviderCapability(flags)
|
||||||
QgsProviderMetadata.ProviderMetadataCapability.__bool__ = lambda flag: bool(_force_int(flag))
|
QgsProviderMetadata.ProviderMetadataCapability.__bool__ = lambda flag: bool(_force_int(flag))
|
||||||
QgsProviderMetadata.ProviderMetadataCapability.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)
|
QgsProviderMetadata.ProviderMetadataCapability.__eq__ = lambda flag1, flag2: _force_int(flag1) == _force_int(flag2)
|
||||||
|
|||||||
@ -158,6 +158,7 @@ library object.
|
|||||||
FileBasedUris,
|
FileBasedUris,
|
||||||
SaveLayerMetadata,
|
SaveLayerMetadata,
|
||||||
ParallelCreateProvider,
|
ParallelCreateProvider,
|
||||||
|
LoadLayerMetadata,
|
||||||
};
|
};
|
||||||
typedef QFlags<QgsProviderMetadata::ProviderCapability> ProviderCapabilities;
|
typedef QFlags<QgsProviderMetadata::ProviderCapability> ProviderCapabilities;
|
||||||
|
|
||||||
@ -680,6 +681,21 @@ Saves ``metadata`` to the layer corresponding to the specified ``uri``.
|
|||||||
|
|
||||||
|
|
||||||
.. versionadded:: 3.20
|
.. versionadded:: 3.20
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found /Out/ ) throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Loads layer metadata for the specified ``layerUri``.
|
||||||
|
|
||||||
|
:param layerUri: uri of layer to load metadata for
|
||||||
|
|
||||||
|
:return: - layer metadata
|
||||||
|
- found: set to ``True`` if metadata was found, ``False`` otherwise
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: if the provider does not support loading layer metadata for the
|
||||||
|
specified ``layerUri``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
%End
|
%End
|
||||||
|
|
||||||
virtual bool createDb( const QString &dbPath, QString &errCause );
|
virtual bool createDb( const QString &dbPath, QString &errCause );
|
||||||
|
|||||||
@ -322,6 +322,25 @@ Saves ``metadata`` to the layer corresponding to the specified ``uri``.
|
|||||||
.. versionadded:: 3.20
|
.. versionadded:: 3.20
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &providerKey, const QString &uri, bool &found /Out/ ) throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Loads metadata for the layer corresponding to the specified ``uri``.
|
||||||
|
|
||||||
|
:param providerKey: identifier of the provider
|
||||||
|
:param uri: uri of layer to load metadata for
|
||||||
|
|
||||||
|
:return: - The layer metadata or empty metadata if not found.
|
||||||
|
- found: will be set to ``True`` if metadata was found, or ``False`` if no metadata was found
|
||||||
|
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: if the provider does not support loading layer metadata for the
|
||||||
|
specified ``uri``.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
|
%End
|
||||||
|
|
||||||
|
|
||||||
bool createDb( const QString &providerKey, const QString &dbPath, QString &errCause );
|
bool createDb( const QString &providerKey, const QString &dbPath, QString &errCause );
|
||||||
%Docstring
|
%Docstring
|
||||||
Creates database by the provider on the path
|
Creates database by the provider on the path
|
||||||
|
|||||||
@ -158,6 +158,7 @@ library object.
|
|||||||
FileBasedUris,
|
FileBasedUris,
|
||||||
SaveLayerMetadata,
|
SaveLayerMetadata,
|
||||||
ParallelCreateProvider,
|
ParallelCreateProvider,
|
||||||
|
LoadLayerMetadata,
|
||||||
};
|
};
|
||||||
typedef QFlags<QgsProviderMetadata::ProviderCapability> ProviderCapabilities;
|
typedef QFlags<QgsProviderMetadata::ProviderCapability> ProviderCapabilities;
|
||||||
|
|
||||||
@ -680,6 +681,21 @@ Saves ``metadata`` to the layer corresponding to the specified ``uri``.
|
|||||||
|
|
||||||
|
|
||||||
.. versionadded:: 3.20
|
.. versionadded:: 3.20
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found /Out/ ) throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Loads layer metadata for the specified ``layerUri``.
|
||||||
|
|
||||||
|
:param layerUri: uri of layer to load metadata for
|
||||||
|
|
||||||
|
:return: - layer metadata
|
||||||
|
- found: set to ``True`` if metadata was found, ``False`` otherwise
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: if the provider does not support loading layer metadata for the
|
||||||
|
specified ``layerUri``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
%End
|
%End
|
||||||
|
|
||||||
virtual bool createDb( const QString &dbPath, QString &errCause );
|
virtual bool createDb( const QString &dbPath, QString &errCause );
|
||||||
|
|||||||
@ -322,6 +322,25 @@ Saves ``metadata`` to the layer corresponding to the specified ``uri``.
|
|||||||
.. versionadded:: 3.20
|
.. versionadded:: 3.20
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &providerKey, const QString &uri, bool &found /Out/ ) throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Loads metadata for the layer corresponding to the specified ``uri``.
|
||||||
|
|
||||||
|
:param providerKey: identifier of the provider
|
||||||
|
:param uri: uri of layer to load metadata for
|
||||||
|
|
||||||
|
:return: - The layer metadata or empty metadata if not found.
|
||||||
|
- found: will be set to ``True`` if metadata was found, or ``False`` if no metadata was found
|
||||||
|
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: if the provider does not support loading layer metadata for the
|
||||||
|
specified ``uri``.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
|
%End
|
||||||
|
|
||||||
|
|
||||||
bool createDb( const QString &providerKey, const QString &dbPath, QString &errCause );
|
bool createDb( const QString &providerKey, const QString &dbPath, QString &errCause );
|
||||||
%Docstring
|
%Docstring
|
||||||
Creates database by the provider on the path
|
Creates database by the provider on the path
|
||||||
|
|||||||
@ -32,6 +32,7 @@ email : nyall dot dawson at gmail dot com
|
|||||||
#include "qgsgdalutils.h"
|
#include "qgsgdalutils.h"
|
||||||
#include "qgsproviderregistry.h"
|
#include "qgsproviderregistry.h"
|
||||||
#include "qgsvectorfilewriter.h"
|
#include "qgsvectorfilewriter.h"
|
||||||
|
#include "qgsvectorlayer.h"
|
||||||
|
|
||||||
#include <gdal.h>
|
#include <gdal.h>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@ -654,6 +655,117 @@ bool QgsOgrProviderMetadata::saveLayerMetadata( const QString &uri, const QgsLay
|
|||||||
throw QgsNotSupportedException( QObject::tr( "Storing metadata for the specified uri is not supported" ) );
|
throw QgsNotSupportedException( QObject::tr( "Storing metadata for the specified uri is not supported" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsOgrProviderMetadata::loadLayerMetadata( const QString &layerUri, bool &found )
|
||||||
|
{
|
||||||
|
QgsLayerMetadata metadata;
|
||||||
|
found = false;
|
||||||
|
const QVariantMap parts = decodeUri( layerUri );
|
||||||
|
const QString path = parts.value( QStringLiteral( "path" ) ).toString();
|
||||||
|
QString errorMessage;
|
||||||
|
|
||||||
|
if ( !path.isEmpty() && QFileInfo::exists( path ) )
|
||||||
|
{
|
||||||
|
const QFileInfo fi( path );
|
||||||
|
// if it is a gpkg, try reading metadata
|
||||||
|
if ( fi.suffix().compare( QLatin1String( "gpkg" ), Qt::CaseInsensitive ) == 0 )
|
||||||
|
{
|
||||||
|
const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
|
||||||
|
QgsOgrLayerUniquePtr userLayer;
|
||||||
|
userLayer = QgsOgrProviderUtils::getLayer( path, true, QStringList(), layerName, errorMessage, true );
|
||||||
|
if ( userLayer )
|
||||||
|
{
|
||||||
|
// try to read metadata from gpkg_metadata table
|
||||||
|
QString sql = QStringLiteral( "SELECT metadata FROM gpkg_metadata LEFT JOIN gpkg_metadata_reference ON "
|
||||||
|
"(gpkg_metadata_reference.table_name = %1 AND gpkg_metadata.id = gpkg_metadata_reference.md_file_id) "
|
||||||
|
"WHERE md_standard_uri = %2 and reference_scope = %3" ).arg(
|
||||||
|
QgsSqliteUtils::quotedString( layerName ),
|
||||||
|
QgsSqliteUtils::quotedString( QStringLiteral( "http://mrcc.com/qgis.dtd" ) ),
|
||||||
|
QgsSqliteUtils::quotedString( QStringLiteral( "table" ) ) );
|
||||||
|
if ( QgsOgrLayerUniquePtr l = userLayer->ExecuteSQL( sql.toUtf8().constData() ) )
|
||||||
|
{
|
||||||
|
// retrieve row id
|
||||||
|
gdal::ogr_feature_unique_ptr f( l->GetNextFeature() );
|
||||||
|
if ( f )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
QVariant res = QgsOgrUtils::getOgrFeatureAttribute( f.get(), QgsField( QString(), QVariant::String ), 0, nullptr, &ok );
|
||||||
|
if ( ok )
|
||||||
|
{
|
||||||
|
QDomDocument document;
|
||||||
|
QString metadataXml = res.toString();
|
||||||
|
if ( document.setContent( metadataXml ) )
|
||||||
|
{
|
||||||
|
if ( !metadata.readMetadataXml( document.documentElement() ) )
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from gpkg_contents but do not override whatever was set in the previous step
|
||||||
|
// (this is to support old geopackages which do not have metadata in gpkg_metadata)
|
||||||
|
|
||||||
|
if ( metadata.title().isEmpty() || metadata.abstract().isEmpty() )
|
||||||
|
{
|
||||||
|
QRecursiveMutex *mutex = nullptr;
|
||||||
|
// Returns native OGRLayerH object with the mutex to lock when using it
|
||||||
|
OGRLayerH hLayer = userLayer->getHandleAndMutex( mutex );
|
||||||
|
QMutexLocker locker( mutex );
|
||||||
|
|
||||||
|
// These are special keys which get stored into the gpkg_contents table
|
||||||
|
if ( metadata.abstract().isEmpty() )
|
||||||
|
{
|
||||||
|
const char *description = GDALGetMetadataItem( hLayer, "DESCRIPTION", nullptr );
|
||||||
|
if ( description )
|
||||||
|
{
|
||||||
|
metadata.setAbstract( QString( description ) );
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( metadata.title().isEmpty() )
|
||||||
|
{
|
||||||
|
const char *identifier = GDALGetMetadataItem( hLayer, "IDENTIFIER", nullptr );
|
||||||
|
if ( identifier )
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
metadata.setIdentifier( QString( identifier ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to read metadata from .qmd sidecar file
|
||||||
|
const QFileInfo fi( path );
|
||||||
|
const QString qmdFileName = fi.dir().filePath( fi.completeBaseName() + QStringLiteral( ".qmd" ) );
|
||||||
|
QFile qmdFile( qmdFileName );
|
||||||
|
if ( qmdFile.open( QFile::ReadOnly ) )
|
||||||
|
{
|
||||||
|
QDomDocument document;
|
||||||
|
if ( document.setContent( &qmdFile ) )
|
||||||
|
{
|
||||||
|
if ( !metadata.readMetadataXml( document.documentElement() ) )
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw QgsNotSupportedException( QObject::tr( "Loading metadata for the specified uri is not supported" ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QgsTransaction *QgsOgrProviderMetadata::createTransaction( const QString &connString )
|
QgsTransaction *QgsOgrProviderMetadata::createTransaction( const QString &connString )
|
||||||
{
|
{
|
||||||
@ -1201,7 +1313,7 @@ void QgsOgrProviderMetadata::saveConnection( const QgsAbstractProviderConnection
|
|||||||
|
|
||||||
QgsProviderMetadata::ProviderCapabilities QgsOgrProviderMetadata::providerCapabilities() const
|
QgsProviderMetadata::ProviderCapabilities QgsOgrProviderMetadata::providerCapabilities() const
|
||||||
{
|
{
|
||||||
return FileBasedUris | SaveLayerMetadata;
|
return FileBasedUris | SaveLayerMetadata | LoadLayerMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
///@endcond
|
///@endcond
|
||||||
|
|||||||
@ -73,6 +73,7 @@ class QgsOgrProviderMetadata final: public QgsProviderMetadata
|
|||||||
QStringList &descriptions, QString &errCause ) override;
|
QStringList &descriptions, QString &errCause ) override;
|
||||||
QString getStyleById( const QString &uri, const QString &styleId, QString &errCause ) override;
|
QString getStyleById( const QString &uri, const QString &styleId, QString &errCause ) override;
|
||||||
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) final;
|
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) final;
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found ) override;
|
||||||
|
|
||||||
// -----
|
// -----
|
||||||
QgsTransaction *createTransaction( const QString &connString ) override;
|
QgsTransaction *createTransaction( const QString &connString ) override;
|
||||||
@ -85,9 +86,9 @@ class QgsOgrProviderMetadata final: public QgsProviderMetadata
|
|||||||
void saveConnection( const QgsAbstractProviderConnection *connection, const QString &name ) override;
|
void saveConnection( const QgsAbstractProviderConnection *connection, const QString &name ) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
QgsAbstractProviderConnection *createConnection( const QString &uri, const QVariantMap &configuration ) override;
|
QgsAbstractProviderConnection *createConnection( const QString &uri, const QVariantMap &configuration ) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -297,6 +297,11 @@ bool QgsProviderMetadata::saveLayerMetadata( const QString &, const QgsLayerMeta
|
|||||||
throw QgsNotSupportedException( QObject::tr( "Provider %1 does not support writing layer metadata" ).arg( key() ) );
|
throw QgsNotSupportedException( QObject::tr( "Provider %1 does not support writing layer metadata" ).arg( key() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsProviderMetadata::loadLayerMetadata( const QString &, bool & )
|
||||||
|
{
|
||||||
|
throw QgsNotSupportedException( QObject::tr( "Provider %1 does not support reading layer metadata" ).arg( key() ) );
|
||||||
|
}
|
||||||
|
|
||||||
bool QgsProviderMetadata::createDb( const QString &, QString &errCause )
|
bool QgsProviderMetadata::createDb( const QString &, QString &errCause )
|
||||||
{
|
{
|
||||||
errCause = QObject::tr( "Provider %1 has no %2 method" ).arg( key(), QStringLiteral( "createDb" ) );
|
errCause = QObject::tr( "Provider %1 has no %2 method" ).arg( key(), QStringLiteral( "createDb" ) );
|
||||||
|
|||||||
@ -203,6 +203,7 @@ class CORE_EXPORT QgsProviderMetadata : public QObject
|
|||||||
FileBasedUris = 1 << 0, //!< Indicates that the provider can utilize URIs which are based on paths to files (as opposed to database or internet paths)
|
FileBasedUris = 1 << 0, //!< Indicates that the provider can utilize URIs which are based on paths to files (as opposed to database or internet paths)
|
||||||
SaveLayerMetadata = 1 << 1, //!< Indicates that the provider supports saving native layer metadata (since QGIS 3.20)
|
SaveLayerMetadata = 1 << 1, //!< Indicates that the provider supports saving native layer metadata (since QGIS 3.20)
|
||||||
ParallelCreateProvider = 1 << 2, //!< Indicates that the provider supports parallel creation, that is, can be created on another thread than the main thread (since QGIS 3.32)
|
ParallelCreateProvider = 1 << 2, //!< Indicates that the provider supports parallel creation, that is, can be created on another thread than the main thread (since QGIS 3.32)
|
||||||
|
LoadLayerMetadata = 1 << 3, //!< Indicates that the provider supports loading native layer metadata (since QGIS 3.36)
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS( ProviderCapabilities, ProviderCapability )
|
Q_DECLARE_FLAGS( ProviderCapabilities, ProviderCapability )
|
||||||
|
|
||||||
@ -700,6 +701,17 @@ class CORE_EXPORT QgsProviderMetadata : public QObject
|
|||||||
*/
|
*/
|
||||||
virtual bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
virtual bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads layer metadata for the specified \a layerUri.
|
||||||
|
* \param layerUri uri of layer to load metadata for
|
||||||
|
* \param found set to TRUE if metadata was found, FALSE otherwise
|
||||||
|
* \returns layer metadata
|
||||||
|
* \throws QgsNotSupportedException if the provider does not support loading layer metadata for the
|
||||||
|
* specified \a layerUri.
|
||||||
|
* \since QGIS 3.36
|
||||||
|
*/
|
||||||
|
virtual QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates database by the provider on the path
|
* Creates database by the provider on the path
|
||||||
* \since QGIS 3.10
|
* \since QGIS 3.10
|
||||||
|
|||||||
@ -845,6 +845,16 @@ bool QgsProviderRegistry::saveLayerMetadata( const QString &providerKey, const Q
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsProviderRegistry::loadLayerMetadata( const QString &providerKey, const QString &uri, bool &found )
|
||||||
|
{
|
||||||
|
if ( QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey ) )
|
||||||
|
return meta->loadLayerMetadata( uri, found );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw QgsNotSupportedException( QObject::tr( "Unable to load %1 provider" ).arg( providerKey ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool QgsProviderRegistry::createDb( const QString &providerKey, const QString &dbPath, QString &errCause )
|
bool QgsProviderRegistry::createDb( const QString &providerKey, const QString &dbPath, QString &errCause )
|
||||||
{
|
{
|
||||||
QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
|
QgsProviderMetadata *meta = findMetadata_( mProviders, providerKey );
|
||||||
|
|||||||
@ -334,6 +334,23 @@ class CORE_EXPORT QgsProviderRegistry
|
|||||||
*/
|
*/
|
||||||
bool saveLayerMetadata( const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
bool saveLayerMetadata( const QString &providerKey, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads metadata for the layer corresponding to the specified \a uri.
|
||||||
|
*
|
||||||
|
* \param providerKey identifier of the provider
|
||||||
|
* \param uri uri of layer to load metadata for
|
||||||
|
* \param found will be set to TRUE if metadata was found, or FALSE if no metadata was found
|
||||||
|
*
|
||||||
|
* \returns The layer metadata or empty metadata if not found.
|
||||||
|
*
|
||||||
|
* \throws QgsNotSupportedException if the provider does not support loading layer metadata for the
|
||||||
|
* specified \a uri.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.36
|
||||||
|
*/
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &providerKey, const QString &uri, bool &found SIP_OUT ) SIP_THROW( QgsNotSupportedException );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates database by the provider on the path
|
* Creates database by the provider on the path
|
||||||
* \since QGIS 3.10
|
* \since QGIS 3.10
|
||||||
|
|||||||
@ -1314,6 +1314,27 @@ QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
|
|||||||
{
|
{
|
||||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||||
|
|
||||||
|
|
||||||
|
if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType() ) )
|
||||||
|
{
|
||||||
|
if ( metadata->providerCapabilities() & QgsProviderMetadata::ProviderCapability::LoadLayerMetadata )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const QgsLayerMetadata metadata { QgsProviderRegistry::instance()->loadLayerMetadata( providerType(), mDataSource, resultFlag ) };
|
||||||
|
if ( resultFlag )
|
||||||
|
{
|
||||||
|
mMetadata = metadata;
|
||||||
|
return tr( "Successfully loaded default layer metadata" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( QgsNotSupportedException & )
|
||||||
|
{
|
||||||
|
// fallback to loadNamedMetadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return loadNamedMetadata( metadataUri(), resultFlag );
|
return loadNamedMetadata( metadataUri(), resultFlag );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -139,7 +139,7 @@ void QgsLayerPropertiesDialog::loadDefaultMetadata()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool defaultLoadedFlag = false;
|
bool defaultLoadedFlag = false;
|
||||||
const QString message = mLayer->loadNamedMetadata( mLayer->metadataUri(), defaultLoadedFlag );
|
const QString message = mLayer->loadDefaultMetadata( defaultLoadedFlag );
|
||||||
//reset if the default metadata was loaded OK only
|
//reset if the default metadata was loaded OK only
|
||||||
if ( defaultLoadedFlag )
|
if ( defaultLoadedFlag )
|
||||||
{
|
{
|
||||||
|
|||||||
@ -221,36 +221,14 @@ QgsPostgresProvider::QgsPostgresProvider( QString const &uri, const ProviderOpti
|
|||||||
|
|
||||||
mLayerExtent.setNull();
|
mLayerExtent.setNull();
|
||||||
|
|
||||||
// Try to load metadata
|
// Try to load metadata from DB
|
||||||
const QString schemaQuery = QStringLiteral( "SELECT table_schema FROM information_schema.tables WHERE table_name = 'qgis_layer_metadata'" );
|
bool metadataLoadedFromDb = false;
|
||||||
QgsPostgresResult res( mConnectionRO->LoggedPQexec( "QgsPostgresProvider", schemaQuery ) );
|
QgsLayerMetadata metadataFromDb { QgsPostgresProviderMetadataUtils::loadLayerMetadata( Qgis::LayerType::Vector, uri, metadataLoadedFromDb ) };
|
||||||
if ( res.PQntuples( ) > 0 )
|
|
||||||
{
|
|
||||||
const QString schemaName = res.PQgetvalue( 0, 0 );
|
|
||||||
// TODO: also filter CRS?
|
|
||||||
const QString selectQuery = QStringLiteral( R"SQL(
|
|
||||||
SELECT
|
|
||||||
qmd
|
|
||||||
FROM %4.qgis_layer_metadata
|
|
||||||
WHERE
|
|
||||||
f_table_schema=%1
|
|
||||||
AND f_table_name=%2
|
|
||||||
AND f_geometry_column %3
|
|
||||||
AND layer_type='vector'
|
|
||||||
)SQL" )
|
|
||||||
.arg( QgsPostgresConn::quotedValue( mUri.schema() ) )
|
|
||||||
.arg( QgsPostgresConn::quotedValue( mUri.table() ) )
|
|
||||||
.arg( mUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "=%1" ).arg( QgsPostgresConn::quotedValue( mUri.geometryColumn() ) ) )
|
|
||||||
.arg( QgsPostgresConn::quotedIdentifier( schemaName ) );
|
|
||||||
|
|
||||||
QgsPostgresResult res( mConnectionRO->LoggedPQexec( "QgsPostgresProvider", selectQuery ) );
|
if ( metadataLoadedFromDb )
|
||||||
if ( res.PQntuples() > 0 )
|
{
|
||||||
{
|
mLayerMetadata = metadataFromDb;
|
||||||
QgsLayerMetadata metadata;
|
QgsMessageLog::logMessage( tr( "PostgreSQL layer metadata loaded from DB." ), tr( "PostGIS" ) );
|
||||||
QDomDocument doc;
|
|
||||||
doc.setContent( res.PQgetvalue( 0, 0 ) );
|
|
||||||
mLayerMetadata.readMetadataXml( doc.documentElement() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the primary key
|
// set the primary key
|
||||||
@ -6132,8 +6110,13 @@ bool QgsPostgresProviderMetadata::saveLayerMetadata( const QString &uri, const Q
|
|||||||
return QgsPostgresProviderMetadataUtils::saveLayerMetadata( Qgis::LayerType::Vector, uri, metadata, errorMessage );
|
return QgsPostgresProviderMetadataUtils::saveLayerMetadata( Qgis::LayerType::Vector, uri, metadata, errorMessage );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsPostgresProviderMetadata::loadLayerMetadata( const QString &layerUri, bool &found )
|
||||||
|
{
|
||||||
|
return QgsPostgresProviderMetadataUtils::loadLayerMetadata( Qgis::LayerType::Vector, layerUri, found );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QgsProviderMetadata::ProviderCapabilities QgsPostgresProviderMetadata::providerCapabilities() const
|
QgsProviderMetadata::ProviderCapabilities QgsPostgresProviderMetadata::providerCapabilities() const
|
||||||
{
|
{
|
||||||
return QgsProviderMetadata::ProviderCapability::SaveLayerMetadata | QgsProviderMetadata::ProviderCapability::ParallelCreateProvider;
|
return QgsProviderMetadata::ProviderCapability::SaveLayerMetadata | QgsProviderMetadata::ProviderCapability::LoadLayerMetadata | QgsProviderMetadata::ProviderCapability::ParallelCreateProvider;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -606,6 +606,7 @@ class QgsPostgresProviderMetadata final: public QgsProviderMetadata
|
|||||||
QString encodeUri( const QVariantMap &parts ) const override;
|
QString encodeUri( const QVariantMap &parts ) const override;
|
||||||
QList< Qgis::LayerType > supportedLayerTypes() const override;
|
QList< Qgis::LayerType > supportedLayerTypes() const override;
|
||||||
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) override;
|
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) override;
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found ) override;
|
||||||
QgsProviderMetadata::ProviderCapabilities providerCapabilities() const override;
|
QgsProviderMetadata::ProviderCapabilities providerCapabilities() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -337,3 +337,79 @@ bool QgsPostgresProviderMetadataUtils::saveLayerMetadata( const Qgis::LayerType
|
|||||||
|
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsPostgresProviderMetadataUtils::loadLayerMetadata( const Qgis::LayerType &layerType, const QString &layerUri, bool &found )
|
||||||
|
{
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
|
||||||
|
QgsLayerMetadata metadata;
|
||||||
|
|
||||||
|
QgsDataSourceUri dsUri( layerUri );
|
||||||
|
|
||||||
|
QString layerTypeString;
|
||||||
|
|
||||||
|
if ( layerType == Qgis::LayerType::Vector )
|
||||||
|
{
|
||||||
|
layerTypeString = QStringLiteral( "vector" );
|
||||||
|
}
|
||||||
|
else if ( layerType == Qgis::LayerType::Raster )
|
||||||
|
{
|
||||||
|
layerTypeString = QStringLiteral( "raster" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unsupported!
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsPostgresConn *conn = QgsPostgresConn::connectDb( dsUri, false );
|
||||||
|
if ( !conn )
|
||||||
|
{
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dsUri.database().isEmpty() ) // typically when a service file is used
|
||||||
|
{
|
||||||
|
dsUri.setDatabase( conn->currentDatabase() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load metadata
|
||||||
|
QString schemaName { dsUri.schema().isEmpty() ? QStringLiteral( "public" ) : dsUri.schema() };
|
||||||
|
const QString schemaQuery = QStringLiteral( "SELECT table_schema FROM information_schema.tables WHERE table_name = 'qgis_layer_metadata'" );
|
||||||
|
QgsPostgresResult res( conn->LoggedPQexec( "QgsPostgresProviderMetadataUtils", schemaQuery ) );
|
||||||
|
const bool metadataTableFound { res.PQntuples( ) > 0 };
|
||||||
|
if ( metadataTableFound )
|
||||||
|
{
|
||||||
|
schemaName = res.PQgetvalue( 0, 0 ) ;
|
||||||
|
const QString schemaName = res.PQgetvalue( 0, 0 );
|
||||||
|
// TODO: also filter CRS?
|
||||||
|
const QString selectQuery = QStringLiteral( R"SQL(
|
||||||
|
SELECT
|
||||||
|
qmd
|
||||||
|
FROM %4.qgis_layer_metadata
|
||||||
|
WHERE
|
||||||
|
f_table_schema=%1
|
||||||
|
AND f_table_name=%2
|
||||||
|
AND f_geometry_column %3
|
||||||
|
AND layer_type='%5'
|
||||||
|
)SQL" )
|
||||||
|
.arg( QgsPostgresConn::quotedValue( dsUri.schema() ) )
|
||||||
|
.arg( QgsPostgresConn::quotedValue( dsUri.table() ) )
|
||||||
|
.arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "=%1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) )
|
||||||
|
.arg( QgsPostgresConn::quotedIdentifier( schemaName ) )
|
||||||
|
.arg( layerType == Qgis::LayerType::Raster ? QStringLiteral( "raster" ) : QStringLiteral( "vector" ) );
|
||||||
|
|
||||||
|
QgsPostgresResult res( conn->LoggedPQexec( "QgsPostgresProvider", selectQuery ) );
|
||||||
|
if ( res.PQntuples() > 0 )
|
||||||
|
{
|
||||||
|
QDomDocument doc;
|
||||||
|
doc.setContent( res.PQgetvalue( 0, 0 ) );
|
||||||
|
metadata.readMetadataXml( doc.documentElement() );
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|||||||
@ -32,6 +32,11 @@ class QgsPostgresProviderMetadataUtils
|
|||||||
|
|
||||||
static QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &uri, const QString &searchString, const QgsRectangle &geographicExtent, QgsFeedback *feedback );
|
static QList<QgsLayerMetadataProviderResult> searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &uri, const QString &searchString, const QgsRectangle &geographicExtent, QgsFeedback *feedback );
|
||||||
static bool saveLayerMetadata( const Qgis::LayerType &layerType, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage );
|
static bool saveLayerMetadata( const Qgis::LayerType &layerType, const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage );
|
||||||
|
|
||||||
|
// Load metadata for a layer
|
||||||
|
static QgsLayerMetadata loadLayerMetadata( const Qgis::LayerType &layerType, const QString &layerUri, bool &found );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // QGSPOSTGRESPROVIDERMETADATAUTILS_H
|
#endif // QGSPOSTGRESPROVIDERMETADATAUTILS_H
|
||||||
|
|||||||
@ -117,39 +117,26 @@ QgsPostgresRasterProvider::QgsPostgresRasterProvider( const QString &uri, const
|
|||||||
QStringLiteral( "PostGIS" ), Qgis::MessageLevel::Warning );
|
QStringLiteral( "PostGIS" ), Qgis::MessageLevel::Warning );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load metadata
|
// Try to load metadata from DB
|
||||||
const QString schemaQuery = QStringLiteral( "SELECT table_schema FROM information_schema.tables WHERE table_name = 'qgis_layer_metadata'" );
|
bool metadataLoadedFromDb = false;
|
||||||
QgsPostgresResult res( mConnectionRO->LoggedPQexec( "QgsPostgresRasterProvider", schemaQuery ) );
|
QgsLayerMetadata metadataFromDb { QgsPostgresProviderMetadataUtils::loadLayerMetadata( Qgis::LayerType::Raster, uri, metadataLoadedFromDb ) };
|
||||||
if ( res.PQntuples( ) > 0 )
|
|
||||||
{
|
|
||||||
const QString schemaName = res.PQgetvalue( 0, 0 );
|
|
||||||
// TODO: also filter CRS?
|
|
||||||
const QString selectQuery = QStringLiteral( R"SQL(
|
|
||||||
SELECT
|
|
||||||
qmd
|
|
||||||
FROM %4.qgis_layer_metadata
|
|
||||||
WHERE
|
|
||||||
f_table_schema=%1
|
|
||||||
AND f_table_name=%2
|
|
||||||
AND f_geometry_column %3
|
|
||||||
AND layer_type='raster'
|
|
||||||
)SQL" )
|
|
||||||
.arg( QgsPostgresConn::quotedValue( mUri.schema() ) )
|
|
||||||
.arg( QgsPostgresConn::quotedValue( mUri.table() ) )
|
|
||||||
.arg( mUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "=%1" ).arg( QgsPostgresConn::quotedValue( mUri.geometryColumn() ) ) )
|
|
||||||
.arg( QgsPostgresConn::quotedIdentifier( schemaName ) );
|
|
||||||
|
|
||||||
QgsPostgresResult res( mConnectionRO->LoggedPQexec( "QgsPostgresRasterProvider", selectQuery ) );
|
if ( metadataLoadedFromDb )
|
||||||
if ( res.PQntuples() > 0 )
|
{
|
||||||
{
|
mLayerMetadata = metadataFromDb;
|
||||||
QgsLayerMetadata metadata;
|
QgsMessageLog::logMessage( tr( "PostgreSQL layer metadata loaded from DB." ), tr( "PostGIS" ) );
|
||||||
QDomDocument doc;
|
|
||||||
doc.setContent( res.PQgetvalue( 0, 0 ) );
|
|
||||||
mLayerMetadata.readMetadataXml( doc.documentElement() );
|
|
||||||
QgsMessageLog::logMessage( tr( "PostgreSQL raster layer metadata loaded from the database." ), tr( "PostGIS" ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the primary key
|
||||||
|
if ( !determinePrimaryKey() )
|
||||||
|
{
|
||||||
|
QgsMessageLog::logMessage( tr( "PostgreSQL layer has no primary key." ), tr( "PostGIS" ) );
|
||||||
|
mValid = false;
|
||||||
|
disconnectDb();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
mLayerMetadata.setType( QStringLiteral( "dataset" ) );
|
mLayerMetadata.setType( QStringLiteral( "dataset" ) );
|
||||||
mLayerMetadata.setCrs( crs() );
|
mLayerMetadata.setCrs( crs() );
|
||||||
|
|
||||||
@ -778,9 +765,14 @@ bool QgsPostgresRasterProviderMetadata::saveLayerMetadata( const QString &uri, c
|
|||||||
return QgsPostgresProviderMetadataUtils::saveLayerMetadata( Qgis::LayerType::Raster, uri, metadata, errorMessage );
|
return QgsPostgresProviderMetadataUtils::saveLayerMetadata( Qgis::LayerType::Raster, uri, metadata, errorMessage );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayerMetadata QgsPostgresRasterProviderMetadata::loadLayerMetadata( const QString &layerUri, bool &found )
|
||||||
|
{
|
||||||
|
return QgsPostgresProviderMetadataUtils::loadLayerMetadata( Qgis::LayerType::Raster, layerUri, found );
|
||||||
|
}
|
||||||
|
|
||||||
QgsProviderMetadata::ProviderCapabilities QgsPostgresRasterProviderMetadata::providerCapabilities() const
|
QgsProviderMetadata::ProviderCapabilities QgsPostgresRasterProviderMetadata::providerCapabilities() const
|
||||||
{
|
{
|
||||||
return QgsProviderMetadata::ProviderCapability::SaveLayerMetadata;
|
return QgsProviderMetadata::ProviderCapability::SaveLayerMetadata | QgsProviderMetadata::ProviderCapability::LoadLayerMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsPostgresRasterProvider *QgsPostgresRasterProviderMetadata::createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
|
QgsPostgresRasterProvider *QgsPostgresRasterProviderMetadata::createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
|
||||||
|
|||||||
@ -267,6 +267,7 @@ class QgsPostgresRasterProviderMetadata: public QgsProviderMetadata
|
|||||||
QString encodeUri( const QVariantMap &parts ) const override;
|
QString encodeUri( const QVariantMap &parts ) const override;
|
||||||
QList< Qgis::LayerType > supportedLayerTypes() const override;
|
QList< Qgis::LayerType > supportedLayerTypes() const override;
|
||||||
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) override;
|
bool saveLayerMetadata( const QString &uri, const QgsLayerMetadata &metadata, QString &errorMessage ) override;
|
||||||
|
QgsLayerMetadata loadLayerMetadata( const QString &layerUri, bool &found ) override;
|
||||||
QgsProviderMetadata::ProviderCapabilities providerCapabilities() const override;
|
QgsProviderMetadata::ProviderCapabilities providerCapabilities() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -135,3 +135,12 @@ class LayerMetadataProviderTestBase():
|
|||||||
self.assertEqual(len(results.metadata()), 1)
|
self.assertEqual(len(results.metadata()), 1)
|
||||||
results = md_provider.search(QgsMetadataSearchContext(), 'cat2')
|
results = md_provider.search(QgsMetadataSearchContext(), 'cat2')
|
||||||
self.assertEqual(len(results.metadata()), 1)
|
self.assertEqual(len(results.metadata()), 1)
|
||||||
|
|
||||||
|
# Test load from DB (used by restore from default)
|
||||||
|
self.test_layer = self.getLayer()
|
||||||
|
self.assertTrue(self.test_layer.isValid())
|
||||||
|
|
||||||
|
self.assertTrue(bool(md.providerCapabilities() & QgsProviderMetadata.ProviderCapability.LoadLayerMetadata))
|
||||||
|
m2, found = md.loadLayerMetadata(layer_uri)
|
||||||
|
self.assertTrue(found)
|
||||||
|
self.assertEqual(m2, m)
|
||||||
|
|||||||
@ -156,7 +156,7 @@ class TestPyQgsPostgresProviderLatency(QgisTestCase):
|
|||||||
settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading')
|
settings = QgsSettingsTree.node('core').childSetting('provider-parallel-loading')
|
||||||
settings.setVariantValue(False)
|
settings.setVariantValue(False)
|
||||||
|
|
||||||
davg = 8.67
|
davg = 9.11
|
||||||
dmin = round(davg - 0.2, 2)
|
dmin = round(davg - 0.2, 2)
|
||||||
dmax = round(davg + 0.3, 2)
|
dmax = round(davg + 0.3, 2)
|
||||||
error_string = 'expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)'
|
error_string = 'expected from {0}s to {1}s, got {2}s\nHINT: set davg={2} to pass the test :)'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user