From c31abacf6572464204324236ed05c0253f986beb Mon Sep 17 00:00:00 2001 From: Alexey Karandashev Date: Tue, 18 Jul 2023 16:30:10 +0200 Subject: [PATCH] Refactor ConnectionConfigurator out of PostgresConn. --- src/core/CMakeLists.txt | 1 + src/core/qgssqlconnectionconfigurator.cpp | 43 +++ src/core/qgssqlconnectionconfigurator.h | 263 ++++++++++++++++++ src/gui/qgsmanageconnectionsdialog.cpp | 86 +++--- .../postgres/qgscolumntypethread.cpp | 1 + src/providers/postgres/qgspgnewconnection.cpp | 107 ++++--- src/providers/postgres/qgspgsourceselect.cpp | 1 + src/providers/postgres/qgspgtablemodel.cpp | 4 +- src/providers/postgres/qgspgtablemodel.h | 4 +- src/providers/postgres/qgspostgresconn.cpp | 153 +--------- src/providers/postgres/qgspostgresconn.h | 16 +- .../postgres/qgspostgresdataitems.cpp | 19 +- .../qgspostgresproviderconnection.cpp | 78 +++--- .../postgres/qgspostgresproviderconnection.h | 3 +- .../test_qgsproviderconnection_postgres.py | 16 +- 15 files changed, 458 insertions(+), 337 deletions(-) create mode 100644 src/core/qgssqlconnectionconfigurator.cpp create mode 100644 src/core/qgssqlconnectionconfigurator.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 501f438c6ceb..901223891702 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -529,6 +529,7 @@ set(QGIS_CORE_SRCS qgsspatialindex.cpp qgsspatialindexkdbush.cpp qgsspatialindexutils.cpp + qgssqlconnectionconfigurator.cpp qgssqlexpressioncompiler.cpp qgssqliteexpressioncompiler.cpp qgssqlstatement.cpp diff --git a/src/core/qgssqlconnectionconfigurator.cpp b/src/core/qgssqlconnectionconfigurator.cpp new file mode 100644 index 000000000000..cbb9588f82cb --- /dev/null +++ b/src/core/qgssqlconnectionconfigurator.cpp @@ -0,0 +1,43 @@ +/*************************************************************************** + qgspostgresconnectionconfigurator.cpp - connection configurator class for + PostgeSQL based connectors. + ------------------- + begin : 2023/06/06 + copyright : (C) 2023 by Alexey Karandashev + email : reflectored at pm dot me + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgssqlconnectionconfigurator.h" + +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sService = new QgsSettingsEntryString( QStringLiteral( "service" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sHost = new QgsSettingsEntryString( QStringLiteral( "host" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sPort = new QgsSettingsEntryString( QStringLiteral( "port" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sDatabase = new QgsSettingsEntryString( QStringLiteral( "database" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sSessionRole = new QgsSettingsEntryString( QStringLiteral( "session_role" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sUsername = new QgsSettingsEntryString( QStringLiteral( "username" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sPassword = new QgsSettingsEntryString( QStringLiteral( "password" ), sTreeConnections ); +const QgsSettingsEntryEnumFlag *QgsPostgreSqlConnectionSettings::sSslMode = new QgsSettingsEntryEnumFlag( QStringLiteral( "sslmode" ), sTreeConnections, QgsDataSourceUri::SslPrefer ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sPublicOnly = new QgsSettingsEntryBool( QStringLiteral( "publicOnly" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly = new QgsSettingsEntryBool( QStringLiteral( "geometryColumnsOnly" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sDontResolveType = new QgsSettingsEntryBool( QStringLiteral( "dontResolveType" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables = new QgsSettingsEntryBool( QStringLiteral( "allowGeometrylessTables" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sEstimatedMetadata = new QgsSettingsEntryBool( QStringLiteral( "estimatedMetadata" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sSaveUsername = new QgsSettingsEntryBool( QStringLiteral( "saveUsername" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sSavePassword = new QgsSettingsEntryBool( QStringLiteral( "savePassword" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sOldSave = new QgsSettingsEntryBool( QStringLiteral( "save" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sProjectsInDatabase = new QgsSettingsEntryBool( QStringLiteral( "projectsInDatabase" ), sTreeConnections ); +const QgsSettingsEntryString *QgsPostgreSqlConnectionSettings::sAuthCfg = new QgsSettingsEntryString( QStringLiteral( "authcfg" ), sTreeConnections ); +const QgsSettingsEntryStringList *QgsPostgreSqlConnectionSettings::sKeys = new QgsSettingsEntryStringList( QStringLiteral( "keys" ), sTreeConnections ); +const QgsSettingsEntryBool *QgsPostgreSqlConnectionSettings::sMetadataInDatabase = new QgsSettingsEntryBool( QStringLiteral( "metadataInDatabase" ), sTreeConnections ); +const QgsSettingsEntryInteger *QgsPostgreSqlConnectionSettings::sDefaultTimeout = new QgsSettingsEntryInteger( QStringLiteral( "default_timeout" ), sTreeConnections, 30 ); +const QString QgsPostgreSqlConnectionSettings::mConnectionTypeName = "PostgreSQL"; +const QString QgsPostgreSqlConnectionSettings::mConnectionTypePort = "5432"; diff --git a/src/core/qgssqlconnectionconfigurator.h b/src/core/qgssqlconnectionconfigurator.h new file mode 100644 index 000000000000..abb4d0eac5f2 --- /dev/null +++ b/src/core/qgssqlconnectionconfigurator.h @@ -0,0 +1,263 @@ +/*************************************************************************** + qgspostgresconnectionconfigurator.h - connection configurator class for + PostgeSQL based connectors. + ------------------- + begin : 2023/06/06 + copyright : (C) 2023 by Alexey Karandashev + email : reflectored at pm dot me + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 QGSSQLCONNECTIONCONFIGURATOR_H +#define QGSSQLCONNECTIONCONFIGURATOR_H +#define SIP_NO_FILE + +#include +#include +#include + +#include "qgsdatasourceuri.h" +#include "qgssettingsentryenumflag.h" +#include "qgssettingsentryimpl.h" +#include "qgssettingstree.h" +#include "qgssettings.h" + +/** + * \ingroup core + * \brief Global PostgreSQL provider connection settings. + * \since QGIS 3.32 + */ +class CORE_EXPORT QgsPostgreSqlConnectionSettings SIP_SKIP +{ + public: + static inline QgsSettingsTreeNamedListNode *sTreeConnections = QgsSettingsTree::sTreeConnections->createNamedListNode( "PostgreSQL", Qgis::SettingsTreeNodeOption::NamedListSelectedItemSetting ); + static const QgsSettingsEntryString *sService; + static const QgsSettingsEntryString *sHost; + static const QgsSettingsEntryString *sPort; + static const QgsSettingsEntryString *sDatabase; + static const QgsSettingsEntryString *sSessionRole; + static const QgsSettingsEntryString *sUsername; + static const QgsSettingsEntryString *sPassword; + static const QgsSettingsEntryEnumFlag *sSslMode; + static const QgsSettingsEntryBool *sPublicOnly; + static const QgsSettingsEntryBool *sGeometryColumnsOnly; + static const QgsSettingsEntryBool *sDontResolveType; + static const QgsSettingsEntryBool *sAllowGeometrylessTables; + static const QgsSettingsEntryBool *sEstimatedMetadata; + static const QgsSettingsEntryBool *sSaveUsername; + static const QgsSettingsEntryBool *sSavePassword; + static const QgsSettingsEntryBool *sOldSave; + static const QgsSettingsEntryBool *sProjectsInDatabase; + static const QgsSettingsEntryString *sAuthCfg; + static const QgsSettingsEntryStringList *sKeys; + static const QgsSettingsEntryBool *sMetadataInDatabase; + static const QgsSettingsEntryInteger *sDefaultTimeout; + static const QString mConnectionTypeName; + static const QString mConnectionTypePort; +}; + +/** + * \ingroup core + * \brief A template implementation of A SQL based provider connection configurator. + * \since QGIS 3.32 + */ +template +class CORE_EXPORT QgsSqlConnectionConfigurator SIP_SKIP +{ + public: + + /** + * \returns QStringList of the provider's connections. + */ + static QStringList connectionList() + { + return T::sTreeConnections->items(); + } + + /** + * \returns QString of the provider's selected connection. + */ + static QString selectedConnection() + { + return T::sTreeConnections->selectedItem(); + } + + /** + * Selects a connection for the provider. + * + * \param name the name of the connection to be selected. + */ + static void setSelectedConnection( const QString &name ) + { + T::sTreeConnections->setSelectedItem( name ); + } + + /** + * Generate a URI for the given connection. + * + * \param connectionName of the connection. + * + * \returns QgsDataSourceUri a URI of the connection. + */ + static QgsDataSourceUri connUri( const QString &connectionName ) + { + QgsDebugMsgLevel( "theConnName = " + connectionName, 2 ); + + const QString service = T::sService->value( connectionName ); + const QString host = T::sHost->value( connectionName ); + QString port = T::sPort->value( connectionName ); + if ( port.length() == 0 ) + { + port = T::mConnectionTypePort; + } + const QString database = T::sDatabase->value( connectionName ); + + const bool estimatedMetadata = useEstimatedMetadata( connectionName ); + QgsDataSourceUri::SslMode sslmode = T::sSslMode->valueWithDefaultOverride( QgsDataSourceUri::SslPrefer, connectionName ); + + QString username; + QString password; + if ( T::sSaveUsername->value( connectionName ) ) + { + username = T::sUsername->value( connectionName ); + } + + if ( T::sSavePassword->value( connectionName ) ) + { + password = T::sPassword->value( connectionName ); + } + + // Old save setting + if ( T::sOldSave->exists( connectionName ) ) + { + username = T::sUsername->value( connectionName ); + + if ( T::sOldSave->value( connectionName ) ) + { + password = T::sPassword->value( connectionName ); + } + } + + const QString authcfg = T::sAuthCfg->value( connectionName ); + + QgsDataSourceUri uri; + if ( !service.isEmpty() ) + { + uri.setConnection( service, database, username, password, sslmode, authcfg ); + } + else + { + uri.setConnection( host, port, database, username, password, sslmode, authcfg ); + } + uri.setUseEstimatedMetadata( estimatedMetadata ); + + return uri; + } + + /** + * Returns the publicOnly setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff public schema only setting is TRUE. + */ + static bool publicSchemaOnly( const QString &connectionName ) + { + return T::sPublicOnly->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Returns the geometryColumnsOnly setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff geometry columns only setting is TRUE. + */ + static bool geometryColumnsOnly( const QString &connectionName ) + { + + return T::sGeometryColumnsOnly->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Returns the dontResolveType setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff don't resolve type setting is TRUE. + */ + static bool dontResolveType( const QString &connectionName ) + { + + return T::sDontResolveType->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Returns the useEstimatedMetadata setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff use estimated metadata setting is TRUE. + */ + static bool useEstimatedMetadata( const QString &connectionName ) + { + + return T::sEstimatedMetadata->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Returns the allowGeometrylessTables setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff allow geometryless tables setting is TRUE. + */ + static bool allowGeometrylessTables( const QString &connectionName ) + { + return T::sAllowGeometrylessTables->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Returns the allowProjectsInDatabase setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff allow projects in database setting is TRUE. + */ + static bool allowProjectsInDatabase( const QString &connectionName ) + { + return T::sProjectsInDatabase->valueWithDefaultOverride( false, connectionName ); + } + + /** + * Delete a connection for the provider. + * + * \param connectionName of the connection. + */ + static void deleteConnection( const QString &connectionName ) + { + T::sTreeConnections->deleteItem( connectionName ); + } + + /** + * Returns the metadataInDatabase setting for the connection. + * + * \param connectionName of the connection. + * + * \returns TRUE iff metadata in database setting is TRUE. + */ + static bool allowMetadataInDatabase( const QString &connectionName ) + { + return T::sMetadataInDatabase->valueWithDefaultOverride( false, connectionName ); + } +}; + +#endif diff --git a/src/gui/qgsmanageconnectionsdialog.cpp b/src/gui/qgsmanageconnectionsdialog.cpp index 8e36133f49f4..899c139a4fdf 100644 --- a/src/gui/qgsmanageconnectionsdialog.cpp +++ b/src/gui/qgsmanageconnectionsdialog.cpp @@ -24,6 +24,7 @@ #include "qgsmanageconnectionsdialog.h" #include "qgshttpheaders.h" #include "qgsowsconnection.h" +#include "qgssqlconnectionconfigurator.h" #include "qgsvectortileconnection.h" #include "qgssettingsentryimpl.h" #include "qgssettingsentryenumflag.h" @@ -257,8 +258,7 @@ bool QgsManageConnectionsDialog::populateConnections() connections = QgsOwsConnection::sTreeOwsConnections->items( {QStringLiteral( "wcs" )} ); break; case PostGIS: - settings.beginGroup( QStringLiteral( "/PostgreSQL/connections" ) ); - connections = settings.childGroups(); + connections = QgsPostgreSqlConnectionSettings::sTreeConnections->items(); break; case MSSQL: settings.beginGroup( QStringLiteral( "/MSSQL/connections" ) ); @@ -506,37 +506,35 @@ QDomDocument QgsManageConnectionsDialog::savePgConnections( const QStringList &c root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); - const QgsSettings settings; - QString path; for ( int i = 0; i < connections.count(); ++i ) { - path = "/PostgreSQL/connections/" + connections[ i ]; + const QString connectionName = connections[i]; QDomElement el = doc.createElement( QStringLiteral( "postgis" ) ); - el.setAttribute( QStringLiteral( "name" ), connections[ i ] ); - el.setAttribute( QStringLiteral( "host" ), settings.value( path + "/host" ).toString() ); - el.setAttribute( QStringLiteral( "port" ), settings.value( path + "/port" ).toString() ); - el.setAttribute( QStringLiteral( "database" ), settings.value( path + "/database" ).toString() ); - el.setAttribute( QStringLiteral( "service" ), settings.value( path + "/service" ).toString() ); - el.setAttribute( QStringLiteral( "sslmode" ), settings.value( path + "/sslmode", "1" ).toString() ); - el.setAttribute( QStringLiteral( "estimatedMetadata" ), settings.value( path + "/estimatedMetadata", "0" ).toString() ); - el.setAttribute( QStringLiteral( "projectsInDatabase" ), settings.value( path + "/projectsInDatabase", "0" ).toString() ); - el.setAttribute( QStringLiteral( "dontResolveType" ), settings.value( path + "/dontResolveType", "0" ).toString() ); - el.setAttribute( QStringLiteral( "allowGeometrylessTables" ), settings.value( path + "/allowGeometrylessTables", "0" ).toString() ); - el.setAttribute( QStringLiteral( "geometryColumnsOnly" ), settings.value( path + "/geometryColumnsOnly", "0" ).toString() ); - el.setAttribute( QStringLiteral( "publicOnly" ), settings.value( path + "/publicOnly", "0" ).toString() ); + el.setAttribute( QStringLiteral( "name" ), connectionName ); + el.setAttribute( QStringLiteral( "host" ), QgsPostgreSqlConnectionSettings::sHost->value( connectionName ) ); + el.setAttribute( QStringLiteral( "port" ), QgsPostgreSqlConnectionSettings::sPort->value( connectionName ) ); + el.setAttribute( QStringLiteral( "database" ), QgsPostgreSqlConnectionSettings::sDatabase->value( connectionName ) ); + el.setAttribute( QStringLiteral( "service" ), QgsPostgreSqlConnectionSettings::sService->value( connectionName ) ); + el.setAttribute( QStringLiteral( "sslmode" ), QgsPostgreSqlConnectionSettings::sSslMode->valueWithDefaultOverride( QgsDataSourceUri::SslMode::SslDisable, connectionName ) ); + el.setAttribute( QStringLiteral( "estimatedMetadata" ), QgsPostgreSqlConnectionSettings::sEstimatedMetadata->valueWithDefaultOverride( "0", connectionName ) ); + el.setAttribute( QStringLiteral( "projectsInDatabase" ), QgsPostgreSqlConnectionSettings::sProjectsInDatabase->valueWithDefaultOverride( "0", connectionName ) ); + el.setAttribute( QStringLiteral( "dontResolveType" ), QgsPostgreSqlConnectionSettings::sDontResolveType->valueWithDefaultOverride( "0", connectionName ) ); + el.setAttribute( QStringLiteral( "allowGeometrylessTables" ), QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables->valueWithDefaultOverride( "0", connectionName ) ); + el.setAttribute( QStringLiteral( "geometryColumnsOnly" ), QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly->valueWithDefaultOverride( "0", connectionName ) ); + el.setAttribute( QStringLiteral( "publicOnly" ), QgsPostgreSqlConnectionSettings::sPublicOnly->valueWithDefaultOverride( "0", connectionName ) ); - el.setAttribute( QStringLiteral( "saveUsername" ), settings.value( path + "/saveUsername", "false" ).toString() ); + el.setAttribute( QStringLiteral( "saveUsername" ), QgsPostgreSqlConnectionSettings::sSaveUsername->valueWithDefaultOverride( false, connectionName ) ); - if ( settings.value( path + "/saveUsername", "false" ).toString() == QLatin1String( "true" ) ) + if ( QgsPostgreSqlConnectionSettings::sSaveUsername->valueWithDefaultOverride( false, connectionName ) ) { - el.setAttribute( QStringLiteral( "username" ), settings.value( path + "/username" ).toString() ); + el.setAttribute( QStringLiteral( "username" ), QgsPostgreSqlConnectionSettings::sUsername->value( connectionName ) ); } - el.setAttribute( QStringLiteral( "savePassword" ), settings.value( path + "/savePassword", "false" ).toString() ); + el.setAttribute( QStringLiteral( "savePassword" ), QgsPostgreSqlConnectionSettings::sSavePassword->valueWithDefaultOverride( "false", connectionName ) ); - if ( settings.value( path + "/savePassword", "false" ).toString() == QLatin1String( "true" ) ) + if ( QgsPostgreSqlConnectionSettings::sSavePassword->valueWithDefaultOverride( false, connectionName ) ) { - el.setAttribute( QStringLiteral( "password" ), settings.value( path + "/password" ).toString() ); + el.setAttribute( QStringLiteral( "password" ), QgsPostgreSqlConnectionSettings::sPassword->value( connectionName ) ); } root.appendChild( el ); @@ -976,9 +974,7 @@ void QgsManageConnectionsDialog::loadPgConnections( const QDomDocument &doc, con QString connectionName; QgsSettings settings; - settings.beginGroup( QStringLiteral( "/PostgreSQL/connections" ) ); - QStringList keys = settings.childGroups(); - settings.endGroup(); + QStringList keys = QgsPostgreSqlConnectionSettings::sTreeConnections->items(); QDomElement child = root.firstChildElement(); bool prompt = true; bool overwrite = true; @@ -1034,32 +1030,28 @@ void QgsManageConnectionsDialog::loadPgConnections( const QDomDocument &doc, con keys << connectionName; } - //no dups detected or overwrite is allowed - settings.beginGroup( "/PostgreSQL/connections/" + connectionName ); - - settings.setValue( QStringLiteral( "/host" ), child.attribute( QStringLiteral( "host" ) ) ); - settings.setValue( QStringLiteral( "/port" ), child.attribute( QStringLiteral( "port" ) ) ); - settings.setValue( QStringLiteral( "/database" ), child.attribute( QStringLiteral( "database" ) ) ); + QgsPostgreSqlConnectionSettings::sHost->setValue( child.attribute( QStringLiteral( "host" ) ), connectionName ); + QgsPostgreSqlConnectionSettings::sPort->setValue( child.attribute( QStringLiteral( "port" ) ), connectionName ); + QgsPostgreSqlConnectionSettings::sDatabase->setValue( child.attribute( QStringLiteral( "database" ) ), connectionName ); if ( child.hasAttribute( QStringLiteral( "service" ) ) ) { - settings.setValue( QStringLiteral( "/service" ), child.attribute( QStringLiteral( "service" ) ) ); + QgsPostgreSqlConnectionSettings::sService->setValue( child.attribute( QStringLiteral( "service" ) ), connectionName ); } else { - settings.setValue( QStringLiteral( "/service" ), "" ); - } - settings.setValue( QStringLiteral( "/sslmode" ), child.attribute( QStringLiteral( "sslmode" ) ) ); - settings.setValue( QStringLiteral( "/estimatedMetadata" ), child.attribute( QStringLiteral( "estimatedMetadata" ) ) ); - settings.setValue( QStringLiteral( "/projectsInDatabase" ), child.attribute( QStringLiteral( "projectsInDatabase" ), 0 ) ); - settings.setValue( QStringLiteral( "/dontResolveType" ), child.attribute( QStringLiteral( "dontResolveType" ), 0 ) ); - settings.setValue( QStringLiteral( "/allowGeometrylessTables" ), child.attribute( QStringLiteral( "allowGeometrylessTables" ), 0 ) ); - settings.setValue( QStringLiteral( "/geometryColumnsOnly" ), child.attribute( QStringLiteral( "geometryColumnsOnly" ), 0 ) ); - settings.setValue( QStringLiteral( "/publicOnly" ), child.attribute( QStringLiteral( "publicOnly" ), 0 ) ); - settings.setValue( QStringLiteral( "/saveUsername" ), child.attribute( QStringLiteral( "saveUsername" ) ) ); - settings.setValue( QStringLiteral( "/username" ), child.attribute( QStringLiteral( "username" ) ) ); - settings.setValue( QStringLiteral( "/savePassword" ), child.attribute( QStringLiteral( "savePassword" ) ) ); - settings.setValue( QStringLiteral( "/password" ), child.attribute( QStringLiteral( "password" ) ) ); - settings.endGroup(); + QgsPostgreSqlConnectionSettings::sService->setValue( "", connectionName ); + } + QgsPostgreSqlConnectionSettings::sSslMode->setValue( QgsDataSourceUri::decodeSslMode( child.attribute( QStringLiteral( "sslmode" ) ) ), connectionName ); + QgsPostgreSqlConnectionSettings::sEstimatedMetadata->setValue( child.attribute( QStringLiteral( "estimatedMetadata" ) ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sProjectsInDatabase->setValue( child.attribute( QStringLiteral( "projectsInDatabase" ), "0" ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sDontResolveType->setValue( child.attribute( QStringLiteral( "dontResolveType" ), "0" ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables->setValue( child.attribute( QStringLiteral( "allowGeometrylessTables" ), "0" ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly->setValue( child.attribute( QStringLiteral( "geometryColumnsOnly" ), "0" ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sPublicOnly->setValue( child.attribute( QStringLiteral( "publicOnly" ), "0" ) == "0", connectionName ); + QgsPostgreSqlConnectionSettings::sSaveUsername->setValue( child.attribute( QStringLiteral( "saveUsername" ) ) == "true", connectionName ); + QgsPostgreSqlConnectionSettings::sUsername->setValue( child.attribute( QStringLiteral( "username" ) ), connectionName ); + QgsPostgreSqlConnectionSettings::sSavePassword->setValue( child.attribute( QStringLiteral( "savePassword" ) ) == "false", connectionName ); + QgsPostgreSqlConnectionSettings::sPassword->setValue( child.attribute( QStringLiteral( "password" ) ), connectionName ); child = child.nextSiblingElement(); } diff --git a/src/providers/postgres/qgscolumntypethread.cpp b/src/providers/postgres/qgscolumntypethread.cpp index f389a5b2dde6..c6646107a4e7 100644 --- a/src/providers/postgres/qgscolumntypethread.cpp +++ b/src/providers/postgres/qgscolumntypethread.cpp @@ -16,6 +16,7 @@ email : jef at norbit dot de ***************************************************************************/ #include "qgscolumntypethread.h" +#include "qgspostgresconn.h" #include "qgspostgresconnpool.h" #include "qgslogger.h" diff --git a/src/providers/postgres/qgspgnewconnection.cpp b/src/providers/postgres/qgspgnewconnection.cpp index 3d906b001455..9e25d050cb9f 100644 --- a/src/providers/postgres/qgspgnewconnection.cpp +++ b/src/providers/postgres/qgspgnewconnection.cpp @@ -29,6 +29,7 @@ #include "qgspostgresconn.h" #include "qgssettings.h" #include "qgsgui.h" +#include "qgssqlconnectionconfigurator.h" QgsPgNewConnection::QgsPgNewConnection( QWidget *parent, const QString &connName, Qt::WindowFlags fl ) : QDialog( parent, fl ) @@ -65,55 +66,54 @@ QgsPgNewConnection::QgsPgNewConnection( QWidget *parent, const QString &connName // populate the fields with the stored setting parameters QgsSettings settings; - QString key = "/PostgreSQL/connections/" + connName; - txtService->setText( settings.value( key + "/service" ).toString() ); - txtHost->setText( settings.value( key + "/host" ).toString() ); - QString port = settings.value( key + "/port" ).toString(); + txtService->setText( QgsPostgreSqlConnectionSettings::sService->value( connName ) ); + txtHost->setText( QgsPostgreSqlConnectionSettings::sHost->value( connName ) ); + QString port = QgsPostgreSqlConnectionSettings::sPort->value( connName ); if ( port.length() == 0 ) { - port = QStringLiteral( "5432" ); + port = QgsPostgreSqlConnectionSettings::mConnectionTypePort; } txtPort->setText( port ); - txtDatabase->setText( settings.value( key + "/database" ).toString() ); - txtSessionRole->setText( settings.value( key + "/session_role" ).toString() ); - cb_publicSchemaOnly->setChecked( settings.value( key + "/publicOnly", false ).toBool() ); - cb_geometryColumnsOnly->setChecked( settings.value( key + "/geometryColumnsOnly", true ).toBool() ); - cb_dontResolveType->setChecked( settings.value( key + "/dontResolveType", false ).toBool() ); - cb_allowGeometrylessTables->setChecked( settings.value( key + "/allowGeometrylessTables", false ).toBool() ); + txtDatabase->setText( QgsPostgreSqlConnectionSettings::sDatabase->value( connName ) ); + txtSessionRole->setText( QgsPostgreSqlConnectionSettings::sSessionRole->value( connName ) ); + cb_publicSchemaOnly->setChecked( QgsPostgreSqlConnectionSettings::sPublicOnly->value( connName ) ); + cb_geometryColumnsOnly->setChecked( QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly->value( connName ) ); + cb_dontResolveType->setChecked( QgsPostgreSqlConnectionSettings::sDontResolveType->value( connName ) ); + cb_allowGeometrylessTables->setChecked( QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables->value( connName ) ); // Ensure that cb_publicSchemaOnly is set correctly cb_geometryColumnsOnly_clicked(); - cb_useEstimatedMetadata->setChecked( settings.value( key + "/estimatedMetadata", false ).toBool() ); - cb_projectsInDatabase->setChecked( settings.value( key + "/projectsInDatabase", false ).toBool() ); - cb_metadataInDatabase->setChecked( settings.value( key + "/metadataInDatabase", false ).toBool() ); + cb_useEstimatedMetadata->setChecked( QgsPostgreSqlConnectionSettings::sEstimatedMetadata->value( connName ) ); + cb_projectsInDatabase->setChecked( QgsPostgreSqlConnectionSettings::sProjectsInDatabase->value( connName ) ); + cb_metadataInDatabase->setChecked( QgsPostgreSqlConnectionSettings::sMetadataInDatabase->value( connName ) ); - cbxSSLmode->setCurrentIndex( cbxSSLmode->findData( settings.enumValue( key + "/sslmode", QgsDataSourceUri::SslPrefer ) ) ); + cbxSSLmode->setCurrentIndex( cbxSSLmode->findData( QgsPostgreSqlConnectionSettings::sSslMode->value( connName ) ) ); - if ( settings.value( key + "/saveUsername" ).toString() == QLatin1String( "true" ) ) + if ( QgsPostgreSqlConnectionSettings::sOldSave->value( connName ) ) { - mAuthSettings->setUsername( settings.value( key + "/username" ).toString() ); + mAuthSettings->setUsername( QgsPostgreSqlConnectionSettings::sUsername->value( connName ) ); mAuthSettings->setStoreUsernameChecked( true ); } - if ( settings.value( key + "/savePassword" ).toString() == QLatin1String( "true" ) ) + if ( QgsPostgreSqlConnectionSettings::sOldSave->value( connName ) ) { - mAuthSettings->setPassword( settings.value( key + "/password" ).toString() ); + mAuthSettings->setPassword( QgsPostgreSqlConnectionSettings::sPassword->value( connName ) ); mAuthSettings->setStorePasswordChecked( true ); } // Old save setting - if ( settings.contains( key + "/save" ) ) + if ( QgsPostgreSqlConnectionSettings::sOldSave->value( connName ) ) { - mAuthSettings->setUsername( settings.value( key + "/username" ).toString() ); + mAuthSettings->setUsername( QgsPostgreSqlConnectionSettings::sUsername->value( connName ) ); mAuthSettings->setStoreUsernameChecked( !mAuthSettings->username().isEmpty() ); - if ( settings.value( key + "/save" ).toString() == QLatin1String( "true" ) ) - mAuthSettings->setPassword( settings.value( key + "/password" ).toString() ); + if ( QgsPostgreSqlConnectionSettings::sOldSave->value( connName ) ) + mAuthSettings->setPassword( QgsPostgreSqlConnectionSettings::sPassword->value( connName ) ); mAuthSettings->setStorePasswordChecked( true ); } - QString authcfg = settings.value( key + "/authcfg" ).toString(); + const QString authcfg = QgsPostgreSqlConnectionSettings::sAuthCfg->value( connName ); mAuthSettings->setConfigId( authcfg ); txtName->setText( connName ); @@ -124,9 +124,8 @@ QgsPgNewConnection::QgsPgNewConnection( QWidget *parent, const QString &connName //! Autoconnected SLOTS void QgsPgNewConnection::accept() { - QgsSettings settings; - QString baseKey = QStringLiteral( "/PostgreSQL/connections/" ); - settings.setValue( baseKey + "selected", txtName->text() ); + const QString currentConnection = txtName->text(); + QgsPostgresConn::setSelectedConnection( currentConnection ); bool hasAuthConfigID = !mAuthSettings->configId().isEmpty(); testConnection(); @@ -140,46 +139,44 @@ void QgsPgNewConnection::accept() } // warn if entry was renamed to an existing connection - if ( ( mOriginalConnName.isNull() || mOriginalConnName.compare( txtName->text(), Qt::CaseInsensitive ) != 0 ) && - ( settings.contains( baseKey + txtName->text() + "/service" ) || - settings.contains( baseKey + txtName->text() + "/host" ) ) && + if ( ( mOriginalConnName.isNull() || mOriginalConnName.compare( currentConnection, Qt::CaseInsensitive ) != 0 ) && + ( QgsPostgreSqlConnectionSettings::sService->exists( currentConnection ) || + QgsPostgreSqlConnectionSettings::sHost->exists( currentConnection ) ) && QMessageBox::question( this, tr( "Save Connection" ), - tr( "Should the existing connection %1 be overwritten?" ).arg( txtName->text() ), + tr( "Should the existing connection %1 be overwritten?" ).arg( currentConnection ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel ) { return; } // on rename delete the original entry first - if ( !mOriginalConnName.isNull() && mOriginalConnName != txtName->text() ) + if ( !mOriginalConnName.isNull() && mOriginalConnName != currentConnection ) { - settings.remove( baseKey + mOriginalConnName ); - settings.sync(); + QgsPostgresConn::deleteConnection( mOriginalConnName ); } - baseKey += txtName->text(); - settings.setValue( baseKey + "/service", txtService->text() ); - settings.setValue( baseKey + "/host", txtHost->text() ); - settings.setValue( baseKey + "/port", txtPort->text() ); - settings.setValue( baseKey + "/database", txtDatabase->text() ); - settings.setValue( baseKey + "/session_role", txtSessionRole->text() ); - settings.setValue( baseKey + "/username", mAuthSettings->storeUsernameIsChecked( ) ? mAuthSettings->username() : QString() ); - settings.setValue( baseKey + "/password", mAuthSettings->storePasswordIsChecked( ) && !hasAuthConfigID ? mAuthSettings->password() : QString() ); - settings.setValue( baseKey + "/authcfg", mAuthSettings->configId() ); - settings.setValue( baseKey + "/publicOnly", cb_publicSchemaOnly->isChecked() ); - settings.setValue( baseKey + "/geometryColumnsOnly", cb_geometryColumnsOnly->isChecked() ); - settings.setValue( baseKey + "/dontResolveType", cb_dontResolveType->isChecked() ); - settings.setValue( baseKey + "/allowGeometrylessTables", cb_allowGeometrylessTables->isChecked() ); - settings.setValue( baseKey + "/sslmode", cbxSSLmode->currentData().toInt() ); - settings.setValue( baseKey + "/saveUsername", mAuthSettings->storeUsernameIsChecked( ) ? "true" : "false" ); - settings.setValue( baseKey + "/savePassword", mAuthSettings->storePasswordIsChecked( ) && !hasAuthConfigID ? "true" : "false" ); - settings.setValue( baseKey + "/estimatedMetadata", cb_useEstimatedMetadata->isChecked() ); - settings.setValue( baseKey + "/projectsInDatabase", cb_projectsInDatabase->isChecked() ); - settings.setValue( baseKey + "/metadataInDatabase", cb_metadataInDatabase->isChecked() ); + QgsPostgreSqlConnectionSettings::sService->setValue( txtService->text(), currentConnection ); + QgsPostgreSqlConnectionSettings::sHost->setValue( txtHost->text(), currentConnection ); + QgsPostgreSqlConnectionSettings::sPort->setValue( txtPort->text(), currentConnection ); + QgsPostgreSqlConnectionSettings::sDatabase->setValue( txtDatabase->text(), currentConnection ); + QgsPostgreSqlConnectionSettings::sSessionRole->setValue( txtSessionRole->text(), currentConnection ); + QgsPostgreSqlConnectionSettings::sUsername->setValue( mAuthSettings->storeUsernameIsChecked( ) ? mAuthSettings->username() : QString(), currentConnection ); + QgsPostgreSqlConnectionSettings::sPassword->setValue( mAuthSettings->storePasswordIsChecked( ) && !hasAuthConfigID ? mAuthSettings->password() : QString(), currentConnection ); + QgsPostgreSqlConnectionSettings::sAuthCfg->setValue( mAuthSettings->configId(), currentConnection ); + QgsPostgreSqlConnectionSettings::sPublicOnly->setValue( cb_publicSchemaOnly->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly->setValue( cb_geometryColumnsOnly->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sDontResolveType->setValue( cb_dontResolveType->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables->setValue( cb_allowGeometrylessTables->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sSslMode->setValue( ( QgsDataSourceUri::SslMode )cbxSSLmode->currentData().toInt(), currentConnection ); + QgsPostgreSqlConnectionSettings::sSaveUsername->setValue( mAuthSettings->storeUsernameIsChecked( ), currentConnection ); + QgsPostgreSqlConnectionSettings::sSavePassword->setValue( mAuthSettings->storePasswordIsChecked( ) && !hasAuthConfigID ? true : false, currentConnection ); + QgsPostgreSqlConnectionSettings::sEstimatedMetadata->setValue( cb_useEstimatedMetadata->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sProjectsInDatabase->setValue( cb_projectsInDatabase->isChecked(), currentConnection ); + QgsPostgreSqlConnectionSettings::sMetadataInDatabase->setValue( cb_metadataInDatabase->isChecked(), currentConnection ); // remove old save setting - settings.remove( baseKey + "/save" ); + QgsPostgreSqlConnectionSettings::sOldSave->remove( currentConnection ); QVariantMap configuration; configuration.insert( "publicOnly", cb_publicSchemaOnly->isChecked() ); @@ -195,7 +192,7 @@ void QgsPgNewConnection::accept() QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "postgres" ) ); - std::unique_ptr< QgsPostgresProviderConnection > providerConnection( qgis::down_cast( providerMetadata->createConnection( txtName->text() ) ) ); + std::unique_ptr< QgsPostgresProviderConnection > providerConnection( qgis::down_cast( providerMetadata->createConnection( currentConnection ) ) ); providerConnection->setUri( QgsPostgresConn::connUri( txtName->text() ).uri( false ) ); providerConnection->setConfiguration( configuration ); providerMetadata->saveConnection( providerConnection.get(), txtName->text() ); diff --git a/src/providers/postgres/qgspgsourceselect.cpp b/src/providers/postgres/qgspgsourceselect.cpp index 199c015134ae..5cb61596947f 100644 --- a/src/providers/postgres/qgspgsourceselect.cpp +++ b/src/providers/postgres/qgspgsourceselect.cpp @@ -21,6 +21,7 @@ email : sherman at mrcc.com #include "qgslogger.h" #include "qgsdbfilterproxymodel.h" #include "qgsapplication.h" +#include "qgspostgresconn.h" #include "qgspostgresprovider.h" #include "qgspgnewconnection.h" #include "qgsmanageconnectionsdialog.h" diff --git a/src/providers/postgres/qgspgtablemodel.cpp b/src/providers/postgres/qgspgtablemodel.cpp index bb43bc33a6b5..7fb557c0a81f 100644 --- a/src/providers/postgres/qgspgtablemodel.cpp +++ b/src/providers/postgres/qgspgtablemodel.cpp @@ -163,7 +163,7 @@ void QgsPgTableModel::addTableEntry( const QgsPostgresLayerProperty &layerProper pkItem->setData( layerProperty.pkCols, Qt::UserRole + 1 ); - QStringList defPk( QgsSettings().value( QStringLiteral( "/PostgreSQL/connections/%1/keys/%2/%3" ).arg( mConnName, layerProperty.schemaName, layerProperty.tableName ), QStringList() ).toStringList() ); + QStringList defPk( QgsPostgreSqlConnectionSettings::sKeys->valueWithDefaultOverride( QStringList(), { mConnectionName, layerProperty.schemaName, layerProperty.tableName } ) ); if ( !layerProperty.pkCols.isEmpty() && defPk.isEmpty() ) { @@ -509,7 +509,7 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, const QString &conn cols << QgsPostgresConn::quotedIdentifier( col ); } - QgsSettings().setValue( QStringLiteral( "/PostgreSQL/connections/%1/keys/%2/%3" ).arg( mConnName, schemaName, tableName ), QVariant( qgis::setToList( s1 ) ) ); + QgsPostgreSqlConnectionSettings::sKeys->setValue( qgis::setToList( s1 ), { mConnectionName, schemaName, tableName } ); uri.setDataSource( schemaName, tableName, geomColumnName, sql, cols.join( ',' ) ); uri.setUseEstimatedMetadata( useEstimatedMetadata ); diff --git a/src/providers/postgres/qgspgtablemodel.h b/src/providers/postgres/qgspgtablemodel.h index 0d26d579a603..bab7ba260a5d 100644 --- a/src/providers/postgres/qgspgtablemodel.h +++ b/src/providers/postgres/qgspgtablemodel.h @@ -67,13 +67,13 @@ class QgsPgTableModel : public QgsAbstractDbTableModel QString layerURI( const QModelIndex &index, const QString &connInfo, bool useEstimatedMetadata ); - void setConnectionName( const QString &connName ) { mConnName = connName; } + void setConnectionName( const QString &connName ) { mConnectionName = connName; } private: //! Number of tables in the model int mTableCount = 0; //! connection name - QString mConnName; + QString mConnectionName; QStringList mColumns; }; diff --git a/src/providers/postgres/qgspostgresconn.cpp b/src/providers/postgres/qgspostgresconn.cpp index 7ff031a96946..fcee88e0e3c6 100644 --- a/src/providers/postgres/qgspostgresconn.cpp +++ b/src/providers/postgres/qgspostgresconn.cpp @@ -21,6 +21,7 @@ #include "qgsdatasourceuri.h" #include "qgsmessagelog.h" #include "qgscredentials.h" +#include "qgssqlconnectionconfigurator.h" #include "qgsvectordataprovider.h" #include "qgswkbtypes.h" #include "qgssettings.h" @@ -47,8 +48,6 @@ #include #endif -const int PG_DEFAULT_TIMEOUT = 30; - QgsPoolPostgresConn::QgsPoolPostgresConn( const QString &connInfo ) : mPgConn( QgsPostgresConnPool::instance()->acquireConnection( connInfo ) ) { @@ -237,8 +236,7 @@ QgsPostgresConn::QgsPostgresConn( const QString &conninfo, bool readOnly, bool s if ( !connectString.contains( QStringLiteral( "connect_timeout=" ) ) ) { // add default timeout - QgsSettings settings; - int timeout = settings.value( QStringLiteral( "PostgreSQL/default_timeout" ), PG_DEFAULT_TIMEOUT, QgsSettings::Providers ).toInt(); + int timeout = QgsPostgreSqlConnectionSettings::sDefaultTimeout->defaultValue(); connectString += QStringLiteral( " connect_timeout=%1" ).arg( timeout ); } @@ -2602,153 +2600,6 @@ Qgis::WkbType QgsPostgresConn::wkbTypeFromGeomType( Qgis::GeometryType geomType return Qgis::WkbType::Unknown; } -QStringList QgsPostgresConn::connectionList() -{ - QgsSettings settings; - settings.beginGroup( QStringLiteral( "PostgreSQL/connections" ) ); - return settings.childGroups(); -} - -QString QgsPostgresConn::selectedConnection() -{ - QgsSettings settings; - return settings.value( QStringLiteral( "PostgreSQL/connections/selected" ) ).toString(); -} - -void QgsPostgresConn::setSelectedConnection( const QString &name ) -{ - QgsSettings settings; - return settings.setValue( QStringLiteral( "PostgreSQL/connections/selected" ), name ); -} - -QgsDataSourceUri QgsPostgresConn::connUri( const QString &connName ) -{ - QgsDebugMsgLevel( "theConnName = " + connName, 2 ); - - QgsSettings settings; - - QString key = "/PostgreSQL/connections/" + connName; - - QString service = settings.value( key + "/service" ).toString(); - QString host = settings.value( key + "/host" ).toString(); - QString port = settings.value( key + "/port" ).toString(); - if ( port.length() == 0 ) - { - port = QStringLiteral( "5432" ); - } - QString database = settings.value( key + "/database" ).toString(); - - bool estimatedMetadata = useEstimatedMetadata( connName ); - QgsDataSourceUri::SslMode sslmode = settings.enumValue( key + "/sslmode", QgsDataSourceUri::SslPrefer ); - - QString username; - QString password; - if ( settings.value( key + "/saveUsername" ).toString() == QLatin1String( "true" ) ) - { - username = settings.value( key + "/username" ).toString(); - } - - if ( settings.value( key + "/savePassword" ).toString() == QLatin1String( "true" ) ) - { - password = settings.value( key + "/password" ).toString(); - } - - // Old save setting - if ( settings.contains( key + "/save" ) ) - { - username = settings.value( key + "/username" ).toString(); - - if ( settings.value( key + "/save" ).toString() == QLatin1String( "true" ) ) - { - password = settings.value( key + "/password" ).toString(); - } - } - - QString authcfg = settings.value( key + "/authcfg" ).toString(); - - QgsDataSourceUri uri; - if ( !service.isEmpty() ) - { - uri.setConnection( service, database, username, password, sslmode, authcfg ); - } - else - { - uri.setConnection( host, port, database, username, password, sslmode, authcfg ); - } - uri.setUseEstimatedMetadata( estimatedMetadata ); - - return uri; -} - -bool QgsPostgresConn::publicSchemaOnly( const QString &connName ) -{ - QgsSettings settings; - return settings.value( "/PostgreSQL/connections/" + connName + "/publicOnly", false ).toBool(); -} - -bool QgsPostgresConn::geometryColumnsOnly( const QString &connName ) -{ - QgsSettings settings; - - return settings.value( "/PostgreSQL/connections/" + connName + "/geometryColumnsOnly", false ).toBool(); -} - -bool QgsPostgresConn::dontResolveType( const QString &connName ) -{ - QgsSettings settings; - - return settings.value( "/PostgreSQL/connections/" + connName + "/dontResolveType", false ).toBool(); -} - -bool QgsPostgresConn::useEstimatedMetadata( const QString &connName ) -{ - QgsSettings settings; - - return settings.value( "/PostgreSQL/connections/" + connName + "/estimatedMetadata", false ).toBool(); -} - - -bool QgsPostgresConn::allowGeometrylessTables( const QString &connName ) -{ - QgsSettings settings; - return settings.value( "/PostgreSQL/connections/" + connName + "/allowGeometrylessTables", false ).toBool(); -} - -bool QgsPostgresConn::allowProjectsInDatabase( const QString &connName ) -{ - QgsSettings settings; - return settings.value( "/PostgreSQL/connections/" + connName + "/projectsInDatabase", false ).toBool(); -} - -void QgsPostgresConn::deleteConnection( const QString &connName ) -{ - QgsSettings settings; - - QString key = "/PostgreSQL/connections/" + connName; - settings.remove( key + "/service" ); - settings.remove( key + "/host" ); - settings.remove( key + "/port" ); - settings.remove( key + "/database" ); - settings.remove( key + "/username" ); - settings.remove( key + "/password" ); - settings.remove( key + "/sslmode" ); - settings.remove( key + "/publicOnly" ); - settings.remove( key + "/geometryColumnsOnly" ); - settings.remove( key + "/allowGeometrylessTables" ); - settings.remove( key + "/estimatedMetadata" ); - settings.remove( key + "/saveUsername" ); - settings.remove( key + "/savePassword" ); - settings.remove( key + "/save" ); - settings.remove( key + "/authcfg" ); - settings.remove( key + "/keys" ); - settings.remove( key ); -} - -bool QgsPostgresConn::allowMetadataInDatabase( const QString &connName ) -{ - QgsSettings settings; - return settings.value( "/PostgreSQL/connections/" + connName + "/metadataInDatabase", false ).toBool(); -} bool QgsPostgresConn::cancel() { diff --git a/src/providers/postgres/qgspostgresconn.h b/src/providers/postgres/qgspostgresconn.h index e69e715ce09d..c74786384efe 100644 --- a/src/providers/postgres/qgspostgresconn.h +++ b/src/providers/postgres/qgspostgresconn.h @@ -25,6 +25,7 @@ #include #include "qgis.h" +#include "qgssqlconnectionconfigurator.h" #include "qgsdatasourceuri.h" #include "qgswkbtypes.h" #include "qgsconfig.h" @@ -171,7 +172,7 @@ constexpr int sPostgresConQueryLogFilePrefixLength = CMAKE_SOURCE_DIR[sizeof( CM #define LoggedPQexec(_class, query) PQexec( query, true, true, _class, QGS_QUERY_LOG_ORIGIN_PG_CON ) #define LoggedPQexecNoLogError(_class, query ) PQexec( query, false, true, _class, QGS_QUERY_LOG_ORIGIN_PG_CON ) -class QgsPostgresConn : public QObject +class QgsPostgresConn : public QObject, public QgsSqlConnectionConfigurator { Q_OBJECT @@ -412,19 +413,6 @@ class QgsPostgresConn : public QObject static Qgis::WkbType wkbTypeFromGeomType( Qgis::GeometryType geomType ); static Qgis::WkbType wkbTypeFromOgcWkbType( unsigned int ogcWkbType ); - static QStringList connectionList(); - static QString selectedConnection(); - static void setSelectedConnection( const QString &connName ); - static QgsDataSourceUri connUri( const QString &connName ); - static bool publicSchemaOnly( const QString &connName ); - static bool geometryColumnsOnly( const QString &connName ); - static bool dontResolveType( const QString &connName ); - static bool useEstimatedMetadata( const QString &connName ); - static bool allowGeometrylessTables( const QString &connName ); - static bool allowProjectsInDatabase( const QString &connName ); - static void deleteConnection( const QString &connName ); - static bool allowMetadataInDatabase( const QString &connName ); - //! A connection needs to be locked when it uses transactions, see QgsPostgresConn::{begin,commit,rollback} void lock() { mLock.lock(); } void unlock() { mLock.unlock(); } diff --git a/src/providers/postgres/qgspostgresdataitems.cpp b/src/providers/postgres/qgspostgresdataitems.cpp index c8e9e644e058..25b345528ce3 100644 --- a/src/providers/postgres/qgspostgresdataitems.cpp +++ b/src/providers/postgres/qgspostgresdataitems.cpp @@ -362,27 +362,22 @@ QString QgsPGLayerItem::comments() const QString QgsPGLayerItem::createUri() { - QgsPGConnectionItem *connItem = qobject_cast( parent() ? parent()->parent() : nullptr ); + QgsPGConnectionItem *connectionItem = qobject_cast( parent() ? parent()->parent() : nullptr ); - if ( !connItem ) + if ( !connectionItem ) { QgsDebugError( QStringLiteral( "connection item not found." ) ); return QString(); } - const QString &connName = connItem->name(); + const QString &connectionName = connectionItem->name(); - QgsDataSourceUri uri( QgsPostgresConn::connUri( connName ).connectionInfo( false ) ); + QgsDataSourceUri uri( QgsPostgresConn::connUri( connectionName ).connectionInfo( false ) ); - const QgsSettings &settings = QgsSettings(); - QString basekey = QStringLiteral( "/PostgreSQL/connections/%1" ).arg( connName ); + QStringList defPk( QgsPostgreSqlConnectionSettings::sKeys->valueWithDefaultOverride( + !mLayerProperty.pkCols.isEmpty() ? QStringList( mLayerProperty.pkCols.at( 0 ) ) : QStringList(), { connectionName, mLayerProperty.schemaName, mLayerProperty.tableName } ) ); - QStringList defPk( settings.value( - QStringLiteral( "%1/keys/%2/%3" ).arg( basekey, mLayerProperty.schemaName, mLayerProperty.tableName ), - QVariant( !mLayerProperty.pkCols.isEmpty() ? QStringList( mLayerProperty.pkCols.at( 0 ) ) : QStringList() ) - ).toStringList() ); - - const bool useEstimatedMetadata = QgsPostgresConn::useEstimatedMetadata( connName ); + const bool useEstimatedMetadata = QgsPostgresConn::useEstimatedMetadata( connectionName ); uri.setUseEstimatedMetadata( useEstimatedMetadata ); QStringList cols; diff --git a/src/providers/postgres/qgspostgresproviderconnection.cpp b/src/providers/postgres/qgspostgresproviderconnection.cpp index a205996cc93f..d6e9516723b0 100644 --- a/src/providers/postgres/qgspostgresproviderconnection.cpp +++ b/src/providers/postgres/qgspostgresproviderconnection.cpp @@ -22,6 +22,7 @@ #include "qgsexception.h" #include "qgsapplication.h" #include "qgsfeedback.h" +#include "qgssettingsentry.h" #include "qgsvectorlayer.h" #include #include @@ -34,48 +35,39 @@ extern "C" } // From configuration -const QStringList QgsPostgresProviderConnection::CONFIGURATION_PARAMETERS = +const QList> QgsPostgresProviderConnection::CONFIGURATION_BOOL_PARAMETERS = + std::initializer_list> { - QStringLiteral( "publicOnly" ), - QStringLiteral( "geometryColumnsOnly" ), - QStringLiteral( "dontResolveType" ), - QStringLiteral( "allowGeometrylessTables" ), - QStringLiteral( "saveUsername" ), - QStringLiteral( "savePassword" ), - QStringLiteral( "estimatedMetadata" ), - QStringLiteral( "projectsInDatabase" ), - QStringLiteral( "metadataInDatabase" ), + {QStringLiteral( "publicOnly" ), QgsPostgreSqlConnectionSettings::sEstimatedMetadata}, + {QStringLiteral( "geometryColumnsOnly" ), QgsPostgreSqlConnectionSettings::sGeometryColumnsOnly}, + {QStringLiteral( "dontResolveType" ), QgsPostgreSqlConnectionSettings::sDontResolveType}, + {QStringLiteral( "allowGeometrylessTables" ), QgsPostgreSqlConnectionSettings::sAllowGeometrylessTables}, + {QStringLiteral( "saveUsername" ), QgsPostgreSqlConnectionSettings::sSaveUsername}, + {QStringLiteral( "savePassword" ), QgsPostgreSqlConnectionSettings::sSavePassword}, + {QStringLiteral( "estimatedMetadata" ), QgsPostgreSqlConnectionSettings::sEstimatedMetadata}, + {QStringLiteral( "projectsInDatabase" ), QgsPostgreSqlConnectionSettings::sProjectsInDatabase}, + {QStringLiteral( "metadataInDatabase" ), QgsPostgreSqlConnectionSettings::sMetadataInDatabase} }; -const QString QgsPostgresProviderConnection::SETTINGS_BASE_KEY = QStringLiteral( "/PostgreSQL/connections/" ); - -QgsPostgresProviderConnection::QgsPostgresProviderConnection( const QString &name ) - : QgsAbstractDatabaseProviderConnection( name ) +QgsPostgresProviderConnection::QgsPostgresProviderConnection( const QString &connectionName ) + : QgsAbstractDatabaseProviderConnection( connectionName ) { mProviderKey = QStringLiteral( "postgres" ); // Remove the sql and table empty parts const thread_local QRegularExpression removePartsRe { R"raw(\s*sql=\s*|\s*table=""\s*)raw" }; - setUri( QgsPostgresConn::connUri( name ).uri( false ).replace( removePartsRe, QString() ) ); - - QgsSettings settings; - settings.beginGroup( SETTINGS_BASE_KEY ); - settings.beginGroup( name ); + setUri( QgsPostgresConn::connUri( connectionName ).uri( false ).replace( removePartsRe, QString() ) ); QVariantMap config; - for ( const QString &p : std::as_const( CONFIGURATION_PARAMETERS ) ) + for ( auto& [settingName, setting] : std::as_const( CONFIGURATION_BOOL_PARAMETERS ) ) { - const QVariant val = settings.value( p ); - if ( val.isValid() ) + if ( setting->exists( connectionName ) ) { - config.insert( p, val ); + config.insert( settingName, setting->value( connectionName ) ); } } - settings.endGroup(); - settings.endGroup(); - setConfiguration( config ); setDefaultCapabilities(); } @@ -763,36 +755,30 @@ QStringList QgsPostgresProviderConnection::schemas( ) const } -void QgsPostgresProviderConnection::store( const QString &name ) const +void QgsPostgresProviderConnection::store( const QString &connectionName ) const { // TODO: move this to class configuration? // delete the original entry first - remove( name ); - - QgsSettings settings; - settings.beginGroup( SETTINGS_BASE_KEY ); - settings.beginGroup( name ); + remove( connectionName ); // From URI const QgsDataSourceUri dsUri { uri() }; - settings.setValue( "service", dsUri.service() ); - settings.setValue( "host", dsUri.host() ); - settings.setValue( "port", dsUri.port() ); - settings.setValue( "database", dsUri.database() ); - settings.setValue( "username", dsUri.username() ); - settings.setValue( "password", dsUri.password() ); - settings.setValue( "authcfg", dsUri.authConfigId() ); - settings.setEnumValue( "sslmode", dsUri.sslMode() ); - - for ( const auto &p : std::as_const( CONFIGURATION_PARAMETERS ) ) + QgsPostgreSqlConnectionSettings::sService->setValue( dsUri.service(), connectionName ); + QgsPostgreSqlConnectionSettings::sHost->setValue( dsUri.host(), connectionName ); + QgsPostgreSqlConnectionSettings::sPort->setValue( dsUri.port(), connectionName ); + QgsPostgreSqlConnectionSettings::sDatabase->setValue( dsUri.database(), connectionName ); + QgsPostgreSqlConnectionSettings::sUsername->setValue( dsUri.username(), connectionName ); + QgsPostgreSqlConnectionSettings::sPassword->setValue( dsUri.password(), connectionName ); + QgsPostgreSqlConnectionSettings::sAuthCfg->setValue( dsUri.authConfigId(), connectionName ); + QgsPostgreSqlConnectionSettings::sSslMode->setValue( dsUri.sslMode(), connectionName ); + + for ( auto& [settingName, setting] : std::as_const( CONFIGURATION_BOOL_PARAMETERS ) ) { - if ( configuration().contains( p ) ) + if ( configuration().contains( settingName ) ) { - settings.setValue( p, configuration().value( p ) ); + setting->setValue( configuration().value( settingName ).toBool(), connectionName ); } } - settings.endGroup(); - settings.endGroup(); } void QgsPostgresProviderConnection::remove( const QString &name ) const diff --git a/src/providers/postgres/qgspostgresproviderconnection.h b/src/providers/postgres/qgspostgresproviderconnection.h index 930f53c4faee..0eefea2a7f3f 100644 --- a/src/providers/postgres/qgspostgresproviderconnection.h +++ b/src/providers/postgres/qgspostgresproviderconnection.h @@ -82,8 +82,7 @@ class QgsPostgresProviderConnection : public QgsAbstractDatabaseProviderConnecti SqlVectorLayerOptions sqlOptions( const QString &layerSource ) override; QList searchLayerMetadata( const QgsMetadataSearchContext &searchContext, const QString &searchString, const QgsRectangle &geographicExtent, QgsFeedback *feedback ) const override; - static const QStringList CONFIGURATION_PARAMETERS; - static const QString SETTINGS_BASE_KEY; + static const QList> CONFIGURATION_BOOL_PARAMETERS; private: diff --git a/tests/src/python/test_qgsproviderconnection_postgres.py b/tests/src/python/test_qgsproviderconnection_postgres.py index 82eb6aafac9b..5d1bbc1d91d6 100644 --- a/tests/src/python/test_qgsproviderconnection_postgres.py +++ b/tests/src/python/test_qgsproviderconnection_postgres.py @@ -23,6 +23,7 @@ QgsProviderRegistry, QgsRasterLayer, QgsSettings, + QgsSettingsTree, QgsVectorLayer, QgsWkbTypes, ) @@ -82,12 +83,15 @@ def test_postgis_connections_from_uri(self): def test_sslmode_store(self): """Test that sslmode is stored as a string in the settings""" md = QgsProviderRegistry.instance().providerMetadata('postgres') - conn = md.createConnection('database=\'mydb\' username=\'myuser\' password=\'mypasswd\' sslmode=verify-ca', {}) - conn.store('my_sslmode_test') - settings = QgsSettings() - settings.beginGroup('/PostgreSQL/connections/my_sslmode_test') - self.assertEqual(settings.value("sslmode"), 'SslVerifyCa') - self.assertEqual(settings.enumValue("sslmode", QgsDataSourceUri.SslPrefer), QgsDataSourceUri.SslVerifyCa) + conn = md.createConnection( + 'database=\'mydb\' username=\'myuser\' password=\'mypasswd\' sslmode=verify-ca', + {}) + connection_name = 'my_sslmode_test' + conn.store(connection_name) + self.assertEqual( + QgsSettingsTree.node("connections").childNode( + "PostgreSQL").childSetting('sslmode').valueAsVariant(connection_name), + QgsDataSourceUri.SslVerifyCa) def test_postgis_geometry_filter(self): """Make sure the postgres provider only returns one matching geometry record and no polygons etc."""