diff --git a/src/Npgsql/NpgsqlConnection.cs b/src/Npgsql/NpgsqlConnection.cs index ac1df9a132..aa27a2c5d0 100644 --- a/src/Npgsql/NpgsqlConnection.cs +++ b/src/Npgsql/NpgsqlConnection.cs @@ -134,6 +134,9 @@ public sealed class NpgsqlConnection : DbConnection, ICloneable private NpgsqlPromotableSinglePhaseNotification promotable = null; + // A cached copy of the result of `settings.ConnectionString` + private string _connectionString; + /// /// Initializes a new instance of the @@ -154,18 +157,8 @@ public NpgsqlConnection(String ConnectionString) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()"); - NpgsqlConnectionStringBuilder builder = cache[ConnectionString]; - if (builder == null) - { - settings = new NpgsqlConnectionStringBuilder(ConnectionString); - } - else - { - settings = builder.Clone(); - } - - LogConnectionString(); - + LoadConnectionStringBuilder(ConnectionString); + NoticeDelegate = new NoticeEventHandler(OnNotice); NotificationDelegate = new NotificationEventHandler(OnNotification); @@ -246,9 +239,14 @@ public NpgsqlConnection(String ConnectionString) [Editor(typeof(ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))] #endif - public override String ConnectionString - { - get { return settings.ConnectionString; } + public override String ConnectionString + { + get + { + if (string.IsNullOrEmpty(_connectionString)) + RefreshConnectionString(); + return settings.ConnectionString; + } set { // Connection string is used as the key to the connector. Because of this, @@ -264,7 +262,7 @@ public override String ConnectionString { settings = builder.Clone(); } - LogConnectionString(); + LoadConnectionStringBuilder(value); } } @@ -606,7 +604,10 @@ public override void ChangeDatabase(String dbName) Close(); - settings[Keywords.Database] = dbName; + // Mutating the current `settings` object would invalidate the cached instance, so work on a copy instead. + settings = settings.Clone(); + settings[Keywords.Database] = dbName; + _connectionString = null; Open(); } @@ -781,6 +782,14 @@ internal void OnNotification(object O, NpgsqlNotificationEventArgs E) } } + /// + /// Returns a copy of the NpgsqlConnectionStringBuilder that contains the parsed connection string values. + /// + internal NpgsqlConnectionStringBuilder CopyConnectionStringBuilder() + { + return settings.Clone(); + } + /// /// The connector object connected to the backend. /// @@ -930,12 +939,40 @@ private NpgsqlPromotableSinglePhaseNotification Promotable /// private void LogConnectionString() { + if (LogLevel.Debug >= NpgsqlEventLog.Level) + return; + foreach (string key in settings.Keys) { NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, key, settings[key]); } } + /// + /// Sets the `settings` ConnectionStringBuilder based on the given `connectionString` + /// + /// The connection string to load the builder from + private void LoadConnectionStringBuilder(string connectionString) + { + settings = cache[connectionString]; + if (settings == null) + { + settings = new NpgsqlConnectionStringBuilder(connectionString); + cache[connectionString] = settings; + } + + RefreshConnectionString(); + LogConnectionString(); + } + + /// + /// Refresh the cached _connectionString whenever the builder settings change + /// + private void RefreshConnectionString() + { + _connectionString = settings.ConnectionString; + } + private void CheckConnectionOpen() { if (disposed) diff --git a/src/Npgsql/NpgsqlConnector.cs b/src/Npgsql/NpgsqlConnector.cs index 92b6778e87..7906711dba 100644 --- a/src/Npgsql/NpgsqlConnector.cs +++ b/src/Npgsql/NpgsqlConnector.cs @@ -165,12 +165,12 @@ internal SSPIHandler SSPI set { _sspi = value; } } -#endif - - public NpgsqlConnector(NpgsqlConnection Connection) - : this(Connection.ConnectionStringValues.Clone(), Connection.Pooling, false) - {} - +#endif + + public NpgsqlConnector(NpgsqlConnection Connection) + : this(Connection.CopyConnectionStringBuilder(), Connection.Pooling, false) + {} + /// /// Constructor. ///