X Tutup
// created on 10/5/2002 at 23:01 // Npgsql.NpgsqlConnection.cs // // Author: // Francisco Jr. (fxjrlists@yahoo.com.br) // // Copyright (C) 2002 The Npgsql Development Team // npgsql-general@gborg.postgresql.org // http://gborg.postgresql.org/project/npgsql/projdisplay.php // // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose, without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph and the following two paragraphs appear in all copies. // // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. using System; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Net.Security; using System.Reflection; using System.Resources; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Transactions; using Mono.Security.Protocol.Tls; using IsolationLevel = System.Data.IsolationLevel; #if WITHDESIGN #endif namespace Npgsql { /// /// Represents the method that handles the Notice events. /// /// The source of the event. /// A NpgsqlNoticeEventArgs that contains the event data. public delegate void NoticeEventHandler(Object sender, NpgsqlNoticeEventArgs e); /// /// Represents the method that handles the Notification events. /// /// The source of the event. /// A NpgsqlNotificationEventArgs that contains the event data. public delegate void NotificationEventHandler(Object sender, NpgsqlNotificationEventArgs e); /// /// This class represents a connection to a /// PostgreSQL server. /// #if WITHDESIGN [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))] #endif public sealed class NpgsqlConnection : DbConnection, ICloneable { // Logging related values private static readonly String CLASSNAME = MethodBase.GetCurrentMethod().DeclaringType.Name; private static readonly ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType); // Parsed connection string cache private static readonly Cache cache = new Cache(); /// /// Occurs on NoticeResponses from the PostgreSQL backend. /// public event NoticeEventHandler Notice; internal NoticeEventHandler NoticeDelegate; /// /// Occurs on NotificationResponses from the PostgreSQL backend. /// public event NotificationEventHandler Notification; internal NotificationEventHandler NotificationDelegate; /// /// Called to provide client certificates for SSL handshake. /// public event ProvideClientCertificatesCallback ProvideClientCertificatesCallback; internal ProvideClientCertificatesCallback ProvideClientCertificatesCallbackDelegate; /// /// Mono.Security.Protocol.Tls.CertificateSelectionCallback delegate. /// [Obsolete("CertificateSelectionCallback, CertificateValidationCallback and PrivateKeySelectionCallback have been replaced with ValidateRemoteCertificateCallback.")] public event CertificateSelectionCallback CertificateSelectionCallback; internal CertificateSelectionCallback CertificateSelectionCallbackDelegate; /// /// Mono.Security.Protocol.Tls.CertificateValidationCallback delegate. /// [Obsolete("CertificateSelectionCallback, CertificateValidationCallback and PrivateKeySelectionCallback have been replaced with ValidateRemoteCertificateCallback.")] public event CertificateValidationCallback CertificateValidationCallback; internal CertificateValidationCallback CertificateValidationCallbackDelegate; /// /// Mono.Security.Protocol.Tls.PrivateKeySelectionCallback delegate. /// [Obsolete("CertificateSelectionCallback, CertificateValidationCallback and PrivateKeySelectionCallback have been replaced with ValidateRemoteCertificateCallback.")] public event PrivateKeySelectionCallback PrivateKeySelectionCallback; internal PrivateKeySelectionCallback PrivateKeySelectionCallbackDelegate; /// /// Called to validate server's certificate during SSL handshake /// public event ValidateRemoteCertificateCallback ValidateRemoteCertificateCallback; internal ValidateRemoteCertificateCallback ValidateRemoteCertificateCallbackDelegate; // Set this when disposed is called. private bool disposed = false; // Used when we closed the connector due to an error, but are pretending it's open. private bool _fakingOpen; // Used when the connection is closed but an TransactionScope is still active // (the actual close is postponed until the scope ends) private bool _postponingClose; private bool _postponingDispose; // Strong-typed ConnectionString values private NpgsqlConnectionStringBuilder settings; // Connector being used for the active connection. private NpgsqlConnector connector = null; private NpgsqlPromotableSinglePhaseNotification promotable = null; // A cached copy of the result of `settings.ConnectionString` private string _connectionString; /// /// Initializes a new instance of the /// NpgsqlConnection class. /// public NpgsqlConnection() : this(String.Empty) { } private void Init() { NoticeDelegate = new NoticeEventHandler(OnNotice); NotificationDelegate = new NotificationEventHandler(OnNotification); ProvideClientCertificatesCallbackDelegate = new ProvideClientCertificatesCallback(DefaultProvideClientCertificatesCallback); CertificateValidationCallbackDelegate = new CertificateValidationCallback(DefaultCertificateValidationCallback); CertificateSelectionCallbackDelegate = new CertificateSelectionCallback(DefaultCertificateSelectionCallback); PrivateKeySelectionCallbackDelegate = new PrivateKeySelectionCallback(DefaultPrivateKeySelectionCallback); ValidateRemoteCertificateCallbackDelegate = new ValidateRemoteCertificateCallback(DefaultValidateRemoteCertificateCallback); // Fix authentication problems. See https://bugzilla.novell.com/show_bug.cgi?id=MONO77559 and // http://pgfoundry.org/forum/message.php?msg_id=1002377 for more info. RSACryptoServiceProvider.UseMachineKeyStore = true; promotable = new NpgsqlPromotableSinglePhaseNotification(this); } /// /// Initializes a new instance of the /// NpgsqlConnection class /// and sets the ConnectionString. /// /// The connection used to open the PostgreSQL database. public NpgsqlConnection(String ConnectionString) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()"); LoadConnectionStringBuilder(ConnectionString); Init(); } /// /// Initializes a new instance of the /// NpgsqlConnection class /// and sets the ConnectionString. /// /// The connection used to open the PostgreSQL database. public NpgsqlConnection(NpgsqlConnectionStringBuilder ConnectionString) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()"); LoadConnectionStringBuilder(ConnectionString); Init(); } /// /// Gets or sets the string used to connect to a PostgreSQL database. /// Valid values are: ///
    ///
  • /// Server: Address/Name of Postgresql Server; ///
  • ///
  • /// Port: Port to connect to; ///
  • ///
  • /// Protocol: Protocol version to use, instead of automatic; Integer 2 or 3; ///
  • ///
  • /// Database: Database name. Defaults to user name if not specified; ///
  • ///
  • /// User Id: User name; ///
  • ///
  • /// Password: Password for clear text authentication; ///
  • ///
  • /// SSL: True or False. Controls whether to attempt a secure connection. Default = False; ///
  • ///
  • /// Pooling: True or False. Controls whether connection pooling is used. Default = True; ///
  • ///
  • /// MinPoolSize: Min size of connection pool; ///
  • ///
  • /// MaxPoolSize: Max size of connection pool; ///
  • ///
  • /// Timeout: Time to wait for connection open in seconds. Default is 15. ///
  • ///
  • /// CommandTimeout: Time to wait for command to finish execution before throw an exception. In seconds. Default is 20. ///
  • ///
  • /// Sslmode: Mode for ssl connection control. Can be Prefer, Require, Allow or Disable. Default is Disable. Check user manual for explanation of values. ///
  • ///
  • /// ConnectionLifeTime: Time to wait before closing unused connections in the pool in seconds. Default is 15. ///
  • ///
  • /// SyncNotification: Specifies if Npgsql should use synchronous notifications. ///
  • ///
  • /// SearchPath: Changes search path to specified and public schemas. ///
  • ///
///
/// The connection string that includes the server name, /// the database name, and other parameters needed to establish /// the initial connection. The default value is an empty string. /// #if WITHDESIGN [RefreshProperties(RefreshProperties.All), DefaultValue(""), RecommendedAsConfigurable(true)] [NpgsqlSysDescription("Description_ConnectionString", typeof(NpgsqlConnection)), Category("Data")] [Editor(typeof(ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))] #endif 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, // we cannot change it while we own a connector. CheckConnectionClosed(); NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value); NpgsqlConnectionStringBuilder builder = cache[value]; if (builder == null) { settings = new NpgsqlConnectionStringBuilder(value); } else { settings = builder.Clone(); } LoadConnectionStringBuilder(value); } } /// /// Backend server host name. /// [Browsable(true)] public String Host { get { return settings.Host; } } /// /// Backend server port. /// [Browsable(true)] public Int32 Port { get { return settings.Port; } } /// /// If true, the connection will attempt to use SSL. /// [Browsable(true)] public Boolean SSL { get { return settings.SSL; } } public Boolean UseSslStream { get { return NpgsqlConnector.UseSslStream; } set { NpgsqlConnector.UseSslStream = value; } } /// /// Gets the time to wait while trying to establish a connection /// before terminating the attempt and generating an error. /// /// The time (in seconds) to wait for a connection to open. The default value is 15 seconds. #if WITHDESIGN [NpgsqlSysDescription("Description_ConnectionTimeout", typeof(NpgsqlConnection))] #endif public override Int32 ConnectionTimeout { get { return settings.Timeout; } } /// /// Gets the time to wait while trying to execute a command /// before terminating the attempt and generating an error. /// /// The time (in seconds) to wait for a command to complete. The default value is 20 seconds. public Int32 CommandTimeout { get { return settings.CommandTimeout; } } /// /// Gets the time to wait before closing unused connections in the pool if the count /// of all connections exeeds MinPoolSize. /// /// /// If connection pool contains unused connections for ConnectionLifeTime seconds, /// the half of them will be closed. If there will be unused connections in a second /// later then again the half of them will be closed and so on. /// This strategy provide smooth change of connection count in the pool. /// /// The time (in seconds) to wait. The default value is 15 seconds. public Int32 ConnectionLifeTime { get { return settings.ConnectionLifeTime; } } /// /// Gets the name of the current database or the database to be used after a connection is opened. /// /// The name of the current database or the name of the database to be /// used after a connection is opened. The default value is the empty string. #if WITHDESIGN [NpgsqlSysDescription("Description_Database", typeof(NpgsqlConnection))] #endif public override String Database { get { return settings.Database; } } /// /// Whether datareaders are loaded in their entirety (for compatibility with earlier code). /// public bool PreloadReader { get { return settings.PreloadReader; } } /// /// Gets the database server name. /// public override string DataSource { get { return settings.Host; } } /// /// Gets flag indicating if we are using Synchronous notification or not. /// The default value is false. /// public Boolean SyncNotification { get { return settings.SyncNotification; } } /// /// Gets the current state of the connection. /// /// A bitwise combination of the ConnectionState values. The default is Closed. [Browsable(false)] public ConnectionState FullState { get { //CheckNotDisposed(); if (connector != null && !disposed) { return connector.State; } else { return ConnectionState.Closed; } } } /// /// Gets whether the current state of the connection is Open or Closed /// /// ConnectionState.Open or ConnectionState.Closed [Browsable(false)] public override ConnectionState State { get { return (FullState & ConnectionState.Open) == ConnectionState.Open ? ConnectionState.Open : ConnectionState.Closed; } } /// /// Compatibility version. /// public Version NpgsqlCompatibilityVersion { get { return settings.Compatible; } } /// /// Version of the PostgreSQL backend. /// This can only be called when there is an active connection. /// [Browsable(false)] public Version PostgreSqlVersion { get { CheckConnectionOpen(); return connector.ServerVersion; } } /// /// PostgreSQL server version. /// public override string ServerVersion { get { return PostgreSqlVersion.ToString(); } } /// /// Protocol version in use. /// This can only be called when there is an active connection. /// Always retuna Version3 /// [Browsable(false)] public ProtocolVersion BackendProtocolVersion { get { CheckConnectionOpen(); return ProtocolVersion.Version3; } } /// /// Process id of backend server. /// This can only be called when there is an active connection. /// [Browsable(false)] public Int32 ProcessID { get { CheckConnectionOpen(); return connector.BackEndKeyData.ProcessID; } } /// /// Report whether the backend is expecting standard conformant strings. /// In version 8.1, Postgres began reporting this value (false), but did not actually support standard conformant strings. /// In version 8.2, Postgres began supporting standard conformant strings, but defaulted this flag to false. /// As of version 9.1, this flag defaults to true. /// [Browsable(false)] public Boolean UseConformantStrings { get { CheckConnectionOpen(); return connector.NativeToBackendTypeConverterOptions.UseConformantStrings; } } /// /// Report whether the backend understands the string literal E prefix (>= 8.1). /// [Browsable(false)] public Boolean Supports_E_StringPrefix { get { CheckConnectionOpen(); return connector.NativeToBackendTypeConverterOptions.Supports_E_StringPrefix; } } /// /// Report whether the backend understands the hex byte format (>= 9.0). /// [Browsable(false)] public Boolean SupportsHexByteFormat { get { CheckConnectionOpen(); return connector.NativeToBackendTypeConverterOptions.SupportsHexByteFormat; } } /// /// Begins a database transaction with the specified isolation level. /// /// The isolation level under which the transaction should run. /// An DbTransaction /// object representing the new transaction. /// /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend. /// There's no support for nested transactions. /// protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginDbTransaction", isolationLevel); return BeginTransaction(isolationLevel); } /// /// Begins a database transaction. /// /// A NpgsqlTransaction /// object representing the new transaction. /// /// Currently there's no support for nested transactions. /// public new NpgsqlTransaction BeginTransaction() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction"); return this.BeginTransaction(IsolationLevel.ReadCommitted); } /// /// Begins a database transaction with the specified isolation level. /// /// The isolation level under which the transaction should run. /// A NpgsqlTransaction /// object representing the new transaction. /// /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend. /// There's no support for nested transactions. /// public new NpgsqlTransaction BeginTransaction(IsolationLevel level) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level); CheckConnectionOpen(); if (connector.Transaction != null) { throw new InvalidOperationException(resman.GetString("Exception_NoNestedTransactions")); } return new NpgsqlTransaction(this, level); } /// /// Opens a database connection with the property settings specified by the /// ConnectionString. /// public override void Open() { // If we're postponing a close (see doc on this variable), the connection is already // open and can be silently reused if (_postponingClose) return; CheckConnectionClosed(); NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open"); // Check if there is any missing argument. if (!settings.ContainsKey(Keywords.Host)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.Host)); } if (!settings.ContainsKey(Keywords.UserName) && !settings.ContainsKey(Keywords.IntegratedSecurity)) { throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), NpgsqlConnectionStringBuilder.GetKeyName(Keywords.UserName)); } // Get a Connector, either from the pool or creating one ourselves. if (Pooling) { connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this); } else { connector = new NpgsqlConnector(this); connector.ProvideClientCertificatesCallback += ProvideClientCertificatesCallbackDelegate; connector.CertificateSelectionCallback += CertificateSelectionCallbackDelegate; connector.CertificateValidationCallback += CertificateValidationCallbackDelegate; connector.PrivateKeySelectionCallback += PrivateKeySelectionCallbackDelegate; connector.ValidateRemoteCertificateCallback += ValidateRemoteCertificateCallbackDelegate; connector.Open(); } connector.Notice += NoticeDelegate; connector.Notification += NotificationDelegate; if (SyncNotification) { connector.AddNotificationThread(); } if (Enlist) { Promotable.Enlist(Transaction.Current); } this.OnStateChange (new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open)); } /// /// This method changes the current database by disconnecting from the actual /// database and connecting to the specified. /// /// The name of the database to use in place of the current database. public override void ChangeDatabase(String dbName) { CheckNotDisposed(); NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeDatabase", dbName); if (dbName == null) { throw new ArgumentNullException("dbName"); } if (string.IsNullOrEmpty(dbName)) { throw new ArgumentOutOfRangeException("dbName", dbName, String.Format(resman.GetString("Exception_InvalidDbName"))); } String oldDatabaseName = Database; Close(); // 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(); } internal void EmergencyClose() { _fakingOpen = true; } /// /// Releases the connection to the database. If the connection is pooled, it will be /// made available for re-use. If it is non-pooled, the actual connection will be shutdown. /// public override void Close() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close"); if (connector == null) return; if (promotable != null && promotable.InLocalTransaction) { _postponingClose = true; return; } ReallyClose(); } private void ReallyClose() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReallyClose"); _postponingClose = false; // clear the way for another promotable transaction promotable = null; connector.Notification -= NotificationDelegate; connector.Notice -= NoticeDelegate; if (SyncNotification) { connector.RemoveNotificationThread(); } if (Pooling) { NpgsqlConnectorPool.ConnectorPoolMgr.ReleaseConnector(this, connector); } else { Connector.ProvideClientCertificatesCallback -= ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback -= CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback -= CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback -= PrivateKeySelectionCallbackDelegate; Connector.ValidateRemoteCertificateCallback -= ValidateRemoteCertificateCallbackDelegate; if (Connector.Transaction != null) { Connector.Transaction.Cancel(); } Connector.Close(); } connector = null; this.OnStateChange (new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed)); } /// /// When a connection is closed within an enclosing TransactionScope and the transaction /// hasn't been promoted, we defer the actual closing until the scope ends. /// internal void PromotableLocalTransactionEnded() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "PromotableLocalTransactionEnded"); if (_postponingDispose) Dispose(true); else if (_postponingClose) ReallyClose(); } /// /// Creates and returns a DbCommand /// object associated with the IDbConnection. /// /// A DbCommand object. protected override DbCommand CreateDbCommand() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateDbCommand"); return CreateCommand(); } /// /// Creates and returns a NpgsqlCommand /// object associated with the NpgsqlConnection. /// /// A NpgsqlCommand object. public new NpgsqlCommand CreateCommand() { CheckNotDisposed(); NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateCommand"); return new NpgsqlCommand("", this); } /// /// Releases all resources used by the /// NpgsqlConnection. /// /// true when called from Dispose(); /// false when being called from the finalizer. protected override void Dispose(bool disposing) { if (disposed) return; _postponingDispose = false; if (disposing) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose"); Close(); if (_postponingClose) { _postponingDispose = true; return; } } base.Dispose(disposing); disposed = true; } /// /// Create a new connection based on this one. /// /// A new NpgsqlConnection object. Object ICloneable.Clone() { return Clone(); } /// /// Create a new connection based on this one. /// /// A new NpgsqlConnection object. public NpgsqlConnection Clone() { CheckNotDisposed(); NpgsqlConnection C = new NpgsqlConnection(ConnectionString); C.Notice += this.Notice; if (connector != null) { C.Open(); } return C; } // // Internal methods and properties // internal void OnNotice(object O, NpgsqlNoticeEventArgs E) { if (Notice != null) { Notice(this, E); } } internal void OnNotification(object O, NpgsqlNotificationEventArgs E) { if (Notification != null) { Notification(this, 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. /// internal NpgsqlConnector Connector { get { return connector; } } /// /// Gets the NpgsqlConnectionStringBuilder containing the parsed connection string values. /// internal NpgsqlConnectionStringBuilder ConnectionStringValues { get { return settings; } } /// /// User name. /// internal String UserName { get { return settings.UserName; } } /// /// Use extended types. /// public bool UseExtendedTypes { get { bool ext = settings.UseExtendedTypes; return ext; } } /// /// Password. /// internal byte[] Password { get { return settings.PasswordAsByteArray; } } /// /// Determine if connection pooling will be used for this connection. /// internal Boolean Pooling { get { return (settings.Pooling && (settings.MaxPoolSize > 0)); } } internal Int32 MinPoolSize { get { return settings.MinPoolSize; } } internal Int32 MaxPoolSize { get { return settings.MaxPoolSize; } } internal Int32 Timeout { get { return settings.Timeout; } } internal Boolean Enlist { get { return settings.Enlist; } } // // Event handlers // /// /// Default SSL CertificateSelectionCallback implementation. /// internal X509Certificate DefaultCertificateSelectionCallback(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates) { if (CertificateSelectionCallback != null) { return CertificateSelectionCallback(clientCertificates, serverCertificate, targetHost, serverRequestedCertificates); } else { return null; } } /// /// Default SSL CertificateValidationCallback implementation. /// internal bool DefaultCertificateValidationCallback(X509Certificate certificate, int[] certificateErrors) { if (CertificateValidationCallback != null) { return CertificateValidationCallback(certificate, certificateErrors); } else { return true; } } /// /// Default SSL PrivateKeySelectionCallback implementation. /// internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(X509Certificate certificate, string targetHost) { if (PrivateKeySelectionCallback != null) { return PrivateKeySelectionCallback(certificate, targetHost); } else { return null; } } /// /// Default SSL ProvideClientCertificatesCallback implementation. /// internal void DefaultProvideClientCertificatesCallback(X509CertificateCollection certificates) { if (ProvideClientCertificatesCallback != null) { ProvideClientCertificatesCallback(certificates); } } /// /// Default SSL ValidateRemoteCertificateCallback implementation. /// internal bool DefaultValidateRemoteCertificateCallback(X509Certificate cert, X509Chain chain, SslPolicyErrors errors) { if (ValidateRemoteCertificateCallback != null) { return ValidateRemoteCertificateCallback(cert, chain, errors); } else { return true; } } // // Private methods and properties // private NpgsqlPromotableSinglePhaseNotification Promotable { get { return promotable ?? (promotable = new NpgsqlPromotableSinglePhaseNotification(this)); } } /// /// Write each key/value pair in the connection string to the log. /// 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) { NpgsqlConnectionStringBuilder newSettings = cache[connectionString]; if (newSettings == null) { newSettings = new NpgsqlConnectionStringBuilder(connectionString); cache[connectionString] = newSettings; } LoadConnectionStringBuilder(newSettings); } /// /// Sets the `settings` ConnectionStringBuilder based on the given `connectionString` /// /// The connection string to load the builder from private void LoadConnectionStringBuilder(NpgsqlConnectionStringBuilder connectionString) { // Clone the settings, because if Integrated Security is enabled, user ID can be different settings = connectionString.Clone(); // Set the UserName explicitly to freeze any Integrated Security-determined names if (settings.IntegratedSecurity) settings.UserName = settings.UserName; RefreshConnectionString(); LogConnectionString(); } /// /// Refresh the cached _connectionString whenever the builder settings change /// private void RefreshConnectionString() { _connectionString = settings.ConnectionString; } private void CheckConnectionOpen() { if (disposed) { throw new ObjectDisposedException(CLASSNAME); } if (_fakingOpen) { if (connector != null) { try { Close(); } catch { } } Open(); _fakingOpen = false; } if (_postponingClose || connector == null) { throw new InvalidOperationException(resman.GetString("Exception_ConnNotOpen")); } } private void CheckConnectionClosed() { if (disposed) { throw new ObjectDisposedException(CLASSNAME); } if (connector != null) { throw new InvalidOperationException(resman.GetString("Exception_ConnOpen")); } } private void CheckNotDisposed() { if (disposed) { throw new ObjectDisposedException(CLASSNAME); } } /// /// Returns the supported collections /// public override DataTable GetSchema() { return NpgsqlSchema.GetMetaDataCollections(); } /// /// Returns the schema collection specified by the collection name. /// /// The collection name. /// The collection specified. public override DataTable GetSchema(string collectionName) { return GetSchema(collectionName, null); } /// /// Returns the schema collection specified by the collection name filtered by the restrictions. /// /// The collection name. /// /// The restriction values to filter the results. A description of the restrictions is contained /// in the Restrictions collection. /// /// The collection specified. public override DataTable GetSchema(string collectionName, string[] restrictions) { using (var tempConn = new NpgsqlConnection(ConnectionString)) { switch (collectionName) { case "MetaDataCollections": return NpgsqlSchema.GetMetaDataCollections(); case "Restrictions": return NpgsqlSchema.GetRestrictions(); case "DataSourceInformation": return NpgsqlSchema.GetDataSourceInformation(); case "DataTypes": throw new NotSupportedException(); case "ReservedWords": return NpgsqlSchema.GetReservedWords(); // custom collections for npgsql case "Databases": return NpgsqlSchema.GetDatabases(tempConn, restrictions); case "Tables": return NpgsqlSchema.GetTables(tempConn, restrictions); case "Columns": return NpgsqlSchema.GetColumns(tempConn, restrictions); case "Views": return NpgsqlSchema.GetViews(tempConn, restrictions); case "Users": return NpgsqlSchema.GetUsers(tempConn, restrictions); case "Indexes": return NpgsqlSchema.GetIndexes(tempConn, restrictions); case "IndexColumns": return NpgsqlSchema.GetIndexColumns(tempConn, restrictions); case "ForeignKeys": return NpgsqlSchema.GetForeignKeys(tempConn, restrictions); default: throw new ArgumentOutOfRangeException("collectionName", collectionName, "Invalid collection name"); } } } /// /// Clear connection pool. /// public void ClearPool() { NpgsqlConnectorPool.ConnectorPoolMgr.ClearPool(this); } /// /// Clear all connection pools. /// public static void ClearAllPools() { NpgsqlConnectorPool.ConnectorPoolMgr.ClearAllPools(); } /// /// Enlist transation. /// /// public override void EnlistTransaction(Transaction transaction) { Promotable.Enlist(transaction); } #if NET35 /// /// DB provider factory. /// protected override DbProviderFactory DbProviderFactory { get { return NpgsqlFactory.Instance; } } #endif } }
X Tutup