Fix operator != handling of LHS null
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlConnection.cs
1 // created on 10/5/2002 at 23:01
2 // Npgsql.NpgsqlConnection.cs
3 //
4 // Author:
5 //      Francisco Jr. (fxjrlists@yahoo.com.br)
6 //
7 //      Copyright (C) 2002 The Npgsql Development Team
8 //      npgsql-general@gborg.postgresql.org
9 //      http://gborg.postgresql.org/project/npgsql/projdisplay.php
10 //
11 //
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 // Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26 using System;
27 using System.ComponentModel;
28 using System.Data;
29 using System.Text;
30 using System.Collections;
31 using System.Resources;
32 using System.Security.Cryptography;
33 using System.Security.Cryptography.X509Certificates;
34
35 using Mono.Security.Protocol.Tls;
36
37 using NpgsqlTypes;
38
39 #if WITHDESIGN
40 using Npgsql.Design;
41 #endif
42
43 namespace Npgsql
44 {
45     /// <summary>
46     /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notice</see> events.
47     /// </summary>
48     /// <param name="e">A <see cref="Npgsql.NpgsqlNoticeEventArgs">NpgsqlNoticeEventArgs</see> that contains the event data.</param>
49     public delegate void NoticeEventHandler(Object sender, NpgsqlNoticeEventArgs e);
50
51     /// <summary>
52     /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notification</see> events.
53     /// </summary>
54     /// <param name="sender">The source of the event.</param>
55     /// <param name="e">A <see cref="Npgsql.NpgsqlNotificationEventArgs">NpgsqlNotificationEventArgs</see> that contains the event data.</param>
56     public delegate void NotificationEventHandler(Object sender, NpgsqlNotificationEventArgs e);
57
58     /// <summary>
59     /// This class represents a connection to a
60     /// PostgreSQL server.
61     /// </summary>
62     #if WITHDESIGN
63     [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))]
64     #endif
65     
66     public sealed class NpgsqlConnection : Component, IDbConnection, ICloneable
67     {
68         // Logging related values
69         private static readonly String CLASSNAME = "NpgsqlConnection";
70         private static ResourceManager resman = new System.Resources.ResourceManager(typeof(NpgsqlConnection));
71
72         /// <summary>
73         /// Occurs on NoticeResponses from the PostgreSQL backend.
74         /// </summary>
75         public event NoticeEventHandler                            Notice;
76         internal NoticeEventHandler                    NoticeDelegate;
77
78         /// <summary>
79         /// Occurs on NotificationResponses from the PostgreSQL backend.
80         /// </summary>
81         public event NotificationEventHandler          Notification;
82         internal NotificationEventHandler              NotificationDelegate;
83
84         /// <summary>
85         /// Mono.Security.Protocol.Tls.CertificateSelectionCallback delegate.
86         /// </summary>
87         public event CertificateSelectionCallback      CertificateSelectionCallback;
88         internal CertificateSelectionCallback          CertificateSelectionCallbackDelegate;
89
90         /// <summary>
91         /// Mono.Security.Protocol.Tls.CertificateValidationCallback delegate.
92         /// </summary>
93         public event CertificateValidationCallback     CertificateValidationCallback;
94         internal CertificateValidationCallback         CertificateValidationCallbackDelegate;
95
96         /// <summary>
97         /// Mono.Security.Protocol.Tls.PrivateKeySelectionCallback delegate.
98         /// </summary>
99         public event PrivateKeySelectionCallback       PrivateKeySelectionCallback;
100         internal PrivateKeySelectionCallback           PrivateKeySelectionCallbackDelegate;
101
102         // Set this when disposed is called.
103         private bool                                   disposed = false;
104
105         // Connection string values.
106         private NpgsqlConnectionString                 connection_string;
107
108         // Connector being used for the active connection.
109         private NpgsqlConnector                        connector = null;
110
111
112         /// <summary>
113         /// Initializes a new instance of the
114         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class.
115         /// </summary>
116         public NpgsqlConnection() : this(String.Empty)
117         {}
118
119         /// <summary>
120         /// Initializes a new instance of the
121         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class
122         /// and sets the <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
123         /// </summary>
124         /// <param name="ConnectionString">The connection used to open the PostgreSQL database.</param>
125         public NpgsqlConnection(String ConnectionString)
126         {
127             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()");
128             
129             connection_string = NpgsqlConnectionString.ParseConnectionString(ConnectionString);
130             LogConnectionString();
131
132             NoticeDelegate = new NoticeEventHandler(OnNotice);
133             NotificationDelegate = new NotificationEventHandler(OnNotification);
134
135             CertificateValidationCallbackDelegate = new CertificateValidationCallback(DefaultCertificateValidationCallback);
136             CertificateSelectionCallbackDelegate = new CertificateSelectionCallback(DefaultCertificateSelectionCallback);
137             PrivateKeySelectionCallbackDelegate = new PrivateKeySelectionCallback(DefaultPrivateKeySelectionCallback);
138         }
139
140         /// <summary>
141         /// Gets or sets the string used to connect to a PostgreSQL database.
142         /// Valid values are:
143         /// <ul>
144         /// <li>
145         /// Server:             Address/Name of Postgresql Server;
146         /// </li>
147         /// <li>
148         /// Port:               Port to connect to;
149         /// </li>
150         /// <li>
151         /// Protocol:           Protocol version to use, instead of automatic; Integer 2 or 3;
152         /// </li>
153         /// <li>
154         /// Database:           Database name. Defaults to user name if not specified;
155         /// </li>
156         /// <li>
157         
158         /// User Id:            User name;
159         /// </li>
160         /// <li>
161         
162         /// Password:           Password for clear text authentication;
163         /// </li>
164         /// <li>
165         
166         /// SSL:                True or False. Controls whether to attempt a secure connection. Default = False;
167         /// </li>
168         /// <li>
169         
170         /// Pooling:            True or False. Controls whether connection pooling is used. Default = True;
171         /// </li>
172         /// <li>
173         
174         /// MinPoolSize:        Min size of connection pool;
175         /// </li>
176         /// <li>
177         
178         /// MaxPoolSize:        Max size of connection pool;
179         /// </li>
180         /// <li>
181         
182         /// Encoding:           Encoding to be used; Can be ASCII or UNICODE. Default is ASCII. Use UNICODE if you are having problems with accents.
183         /// </li>
184         /// <li>
185         
186         /// Timeout:            Time to wait for connection open in seconds. Default is 15.
187         /// </li>
188         /// <li>
189         
190         /// CommandTimeout:     Time to wait for command to finish execution before throw an exception. In seconds. Default is 20.
191         /// </li>
192         /// <li>
193         
194         /// Sslmode:            Mode for ssl connection control. Can be Prefer, Require, Allow or Disable. Default is Disable. Check user manual for explanation of values.
195         /// </li>
196         
197         /// <li>
198         
199         /// ConnectionLifeTime: Time to wait before closing unused connections in the pool in seconds. Default is 15.
200         /// </li>
201         /// <li>
202         
203         /// SyncNotification:   Specifies if Npgsql should use synchronous notifications.
204         /// </li>
205         /// </ul>
206         
207         
208         /// </summary>
209         /// <value>The connection string that includes the server name,
210         /// the database name, and other parameters needed to establish
211         /// the initial connection. The default value is an empty string.
212         /// </value>
213         
214         #if WITHDESIGN
215         [RefreshProperties(RefreshProperties.All), DefaultValue(""), RecommendedAsConfigurable(true)]
216         [NpgsqlSysDescription("Description_ConnectionString", typeof(NpgsqlConnection)), Category("Data")]
217         [Editor(typeof(ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
218         #endif
219         
220         public String ConnectionString {
221             get
222             {
223                 return connection_string.ToString();
224             }
225             set
226             {
227                 // Connection string is used as the key to the connector.  Because of this,
228                 // we cannot change it while we own a connector.
229                 CheckConnectionClosed();
230                 NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value);
231                 connection_string = NpgsqlConnectionString.ParseConnectionString(value);
232                 LogConnectionString();
233             }
234         }
235
236         /// <summary>
237         /// Backend server host name.
238         /// </summary>
239         [Browsable(true)]
240         public String Host {
241             get
242             {
243                 return connection_string.ToString(ConnectionStringKeys.Host);
244             }
245         }
246
247         /// <summary>
248         /// Backend server port.
249         /// </summary>
250         [Browsable(true)]
251         public Int32 Port {
252             get
253             {
254                 return connection_string.ToInt32(ConnectionStringKeys.Port, ConnectionStringDefaults.Port);
255             }
256         }
257
258         /// <summary>
259         /// If true, the connection will attempt to use SSL.
260         /// </summary>
261         [Browsable(true)]
262         public Boolean SSL {
263             get
264             {
265                 return connection_string.ToBool(ConnectionStringKeys.SSL);
266             }
267         }
268
269         /// <summary>
270         /// Gets the time to wait while trying to establish a connection
271         /// before terminating the attempt and generating an error.
272         /// </summary>
273         /// <value>The time (in seconds) to wait for a connection to open. The default value is 15 seconds.</value>
274         
275         #if WITHDESIGN
276         [NpgsqlSysDescription("Description_ConnectionTimeout", typeof(NpgsqlConnection))]
277         #endif
278         
279         public Int32 ConnectionTimeout {
280             get
281             {
282                 return connection_string.ToInt32(ConnectionStringKeys.Timeout, ConnectionStringDefaults.Timeout);
283             }
284         }
285         
286         /// <summary>
287         /// Gets the time to wait before closing unused connections in the pool if the count
288         /// of all connections exeeds MinPoolSize.
289         /// </summary>
290         /// <remarks>
291         /// If connection pool contains unused connections for ConnectionLifeTime seconds,
292         /// the half of them will be closed. If there will be unused connections in a second
293         /// later then again the half of them will be closed and so on.
294         /// This strategy provide smooth change of connection count in the pool.
295         /// </remarks>
296         /// <value>The time (in seconds) to wait. The default value is 15 seconds.</value>
297         public Int32 ConnectionLifeTime {
298             get
299             {
300                 return connection_string.ToInt32(ConnectionStringKeys.ConnectionLifeTime, ConnectionStringDefaults.ConnectionLifeTime);
301             }
302         }
303
304         ///<summary>
305         /// Gets the name of the current database or the database to be used after a connection is opened.
306         /// </summary>
307         /// <value>The name of the current database or the name of the database to be
308         /// used after a connection is opened. The default value is the empty string.</value>
309         #if WITHDESIGN
310         [NpgsqlSysDescription("Description_Database", typeof(NpgsqlConnection))]
311         #endif
312         
313         public String Database {
314             get
315             {
316                 return connection_string.ToString(ConnectionStringKeys.Database);
317             }
318         }
319         
320         /// <summary>
321         /// Gets flag indicating if we are using Synchronous notification or not.
322         /// The default value is false.
323         /// </summary>
324         public Boolean SyncNotification
325         {
326             get
327             {
328                 return connection_string.ToBool(ConnectionStringKeys.SyncNotification, ConnectionStringDefaults.SyncNotification);
329             }
330         }
331
332         /// <summary>
333         /// Gets the current state of the connection.
334         /// </summary>
335         /// <value>A bitwise combination of the <see cref="System.Data.ConnectionState">ConnectionState</see> values. The default is <b>Closed</b>.</value>
336         [Browsable(false)]
337         public ConnectionState State {
338             get
339             {
340                 CheckNotDisposed();
341
342                 if (connector != null)
343                 {
344                     return connector.State;
345                 }
346                 else
347                 {
348                     return ConnectionState.Closed;
349                 }
350             }
351         }
352
353         /// <summary>
354         /// Version of the PostgreSQL backend.
355         /// This can only be called when there is an active connection.
356         /// </summary>
357         [Browsable(false)]
358         public ServerVersion ServerVersion {
359             get
360             {
361                 CheckConnectionOpen();
362                 return connector.ServerVersion;
363             }
364         }
365
366         /// <summary>
367         /// Protocol version in use.
368         /// This can only be called when there is an active connection.
369         /// </summary>
370         [Browsable(false)]
371         public ProtocolVersion BackendProtocolVersion {
372             get
373             {
374                 CheckConnectionOpen();
375                 return connector.BackendProtocolVersion;
376             }
377         }
378
379         /// <summary>
380         /// Begins a database transaction.
381         /// </summary>
382         /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
383         /// object representing the new transaction.</returns>
384         /// <remarks>
385         /// Currently there's no support for nested transactions.
386         /// </remarks>
387         IDbTransaction IDbConnection.BeginTransaction()
388         {
389             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction");
390
391             return BeginTransaction();
392         }
393
394         /// <summary>
395         /// Begins a database transaction with the specified isolation level.
396         /// </summary>
397         /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
398         /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
399         /// object representing the new transaction.</returns>
400         /// <remarks>
401         /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
402         /// There's no support for nested transactions.
403         /// </remarks>
404         IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
405         {
406             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction", level);
407
408             return BeginTransaction(level);
409         }
410
411         /// <summary>
412         /// Begins a database transaction.
413         /// </summary>
414         /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
415         /// object representing the new transaction.</returns>
416         /// <remarks>
417         /// Currently there's no support for nested transactions.
418         /// </remarks>
419         public NpgsqlTransaction BeginTransaction()
420         {
421             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction");
422             return this.BeginTransaction(IsolationLevel.ReadCommitted);
423         }
424
425         /// <summary>
426         /// Begins a database transaction with the specified isolation level.
427         /// </summary>
428         /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
429         /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
430         /// object representing the new transaction.</returns>
431         /// <remarks>
432         /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
433         /// There's no support for nested transactions.
434         /// </remarks>
435         public NpgsqlTransaction BeginTransaction(IsolationLevel level)
436         {
437             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level);
438
439             CheckConnectionOpen();
440
441             if (connector.Transaction != null)
442             {
443                 throw new InvalidOperationException(resman.GetString("Exception_NoNestedTransactions"));
444             }
445
446             return new NpgsqlTransaction(this, level);
447         }
448
449         /// <summary>
450         /// Opens a database connection with the property settings specified by the
451         /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
452         /// </summary>
453         public void Open()
454         {
455             CheckConnectionClosed();
456
457             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
458
459             // Check if there is any missing argument.
460             if (! connection_string.Contains(ConnectionStringKeys.Host))
461                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), ConnectionStringKeys.Host);
462             if (! connection_string.Contains(ConnectionStringKeys.UserName))
463                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), ConnectionStringKeys.UserName);
464
465             // Get a Connector.  The connector returned is guaranteed to be connected and ready to go.
466             connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector (this);
467             
468             connector.Notice += NoticeDelegate;
469             connector.Notification += NotificationDelegate;
470             
471             if (SyncNotification)
472                 connector.AddNotificationThread();
473             
474         }
475
476         /// <summary>
477         /// This method changes the current database by disconnecting from the actual
478         /// database and connecting to the specified.
479         /// </summary>
480         /// <param name="dbName">The name of the database to use in place of the current database.</param>
481         public void ChangeDatabase(String dbName)
482         {
483             CheckNotDisposed();
484
485             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeDatabase", dbName);
486
487             if (dbName == null)
488                 throw new ArgumentNullException("dbName");
489
490             if (dbName == String.Empty)
491                 throw new ArgumentOutOfRangeException(String.Format(resman.GetString("Exception_InvalidDbName"), dbName), "dbName");
492
493             String oldDatabaseName = Database;
494
495             Close();
496
497             connection_string[ConnectionStringKeys.Database] = dbName;
498
499             Open();
500         }
501
502         /// <summary>
503         /// Releases the connection to the database.  If the connection is pooled, it will be
504         ///     made available for re-use.  If it is non-pooled, the actual connection will be shutdown.
505         /// </summary>
506         public void Close()
507         {
508             if (!disposed)
509             {
510                 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
511
512                 if (connector != null)
513                 {
514
515                     connector.Notification -= NotificationDelegate;
516                     connector.Notice -= NoticeDelegate;
517                     
518                     if (SyncNotification)
519                         connector.RemoveNotificationThread();
520
521                     NpgsqlConnectorPool.ConnectorPoolMgr.ReleaseConnector(this, connector);
522                     
523                     
524                     
525                     connector = null;
526                 }
527             }
528         }
529
530         /// <summary>
531         /// Creates and returns a <see cref="System.Data.IDbCommand">IDbCommand</see>
532         /// object associated with the <see cref="System.Data.IDbConnection">IDbConnection</see>.
533         /// </summary>
534         /// <returns>A <see cref="System.Data.IDbCommand">IDbCommand</see> object.</returns>
535         IDbCommand IDbConnection.CreateCommand()
536         {
537             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.CreateCommand");
538             return (NpgsqlCommand) CreateCommand();
539         }
540
541         /// <summary>
542         /// Creates and returns a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
543         /// object associated with the <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
544         /// </summary>
545         /// <returns>A <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> object.</returns>
546         public NpgsqlCommand CreateCommand()
547         {
548             CheckNotDisposed();
549
550             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateCommand");
551             return new NpgsqlCommand("", this);
552         }
553
554         /// <summary>
555         /// Releases all resources used by the
556         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
557         /// </summary>
558         /// <param name="disposing"><b>true</b> when called from Dispose();
559         /// <b>false</b> when being called from the finalizer.</param>
560         protected override void Dispose(bool disposing)
561         {
562
563             if (!disposed)
564             {
565                 if (disposing)
566                 {
567                     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
568                     Close();
569                 }
570                 else
571                 {
572                     if (State != ConnectionState.Closed)
573                     {
574                         NpgsqlEventLog.LogMsg(resman, "Log_ConnectionLeaking", LogLevel.Debug);
575                         NpgsqlConnectorPool.ConnectorPoolMgr.FixPoolCountBecauseOfConnectionDisposeFalse(this);
576                     }
577                 }
578
579                 base.Dispose (disposing);
580                 disposed = true;
581
582             }
583         }
584
585         /// <summary>
586         /// Create a new connection based on this one.
587         /// </summary>
588         /// <returns>A new NpgsqlConnection object.</returns>
589         Object ICloneable.Clone()
590         {
591             return Clone();
592         }
593
594         /// <summary>
595         /// Create a new connection based on this one.
596         /// </summary>
597         /// <returns>A new NpgsqlConnection object.</returns>
598         public NpgsqlConnection Clone()
599         {
600             CheckNotDisposed();
601
602             NpgsqlConnection C = new NpgsqlConnection(ConnectionString);
603
604             C.Notice += this.Notice;
605
606             if (connector != null)
607             {
608                 C.Open();
609             }
610
611             return C;
612         }
613
614         //
615         // Internal methods and properties
616         //
617         internal void OnNotice(object O, NpgsqlNoticeEventArgs E)
618         {
619             if (Notice != null)
620             {
621                 Notice(this, E);
622             }
623         }
624
625         internal void OnNotification(object O, NpgsqlNotificationEventArgs E)
626         {
627             if (Notification != null)
628             {
629                 Notification(this, E);
630             }
631         }
632
633         /// <summary>
634         /// The connector object connected to the backend.
635         /// </summary>
636         internal NpgsqlConnector Connector
637         {
638             get
639             {
640                 return connector;
641             }
642         }
643
644         /// <summary>
645         /// Gets the NpgsqlConnectionString containing the parsed connection string values.
646         /// </summary>
647         internal NpgsqlConnectionString ConnectionStringValues {
648             get
649             {
650                 return connection_string;
651             }
652         }
653
654         /// <summary>
655         /// User name.
656         /// </summary>
657         internal String UserName {
658             get
659             {
660                 return connection_string.ToString(ConnectionStringKeys.UserName);
661             }
662         }
663
664         /// <summary>
665         /// Password.
666         /// </summary>
667         internal String Password {
668             get
669             {
670                 return connection_string.ToString(ConnectionStringKeys.Password);
671             }
672         }
673
674         /// <summary>
675         /// Determine if connection pooling will be used for this connection.
676         /// </summary>
677         internal Boolean Pooling {
678             get
679             {
680                 return (
681                            connection_string.ToBool(ConnectionStringKeys.Pooling, ConnectionStringDefaults.Pooling) &&
682                            connection_string.ToInt32(ConnectionStringKeys.MaxPoolSize, ConnectionStringDefaults.MaxPoolSize) > 0
683                        );
684             }
685         }
686
687         internal Int32 MinPoolSize {
688             get
689             {
690                 return connection_string.ToInt32(ConnectionStringKeys.MinPoolSize, 0, MaxPoolSize, ConnectionStringDefaults.MinPoolSize);
691             }
692         }
693
694         internal Int32 MaxPoolSize {
695             get
696             {
697                 return connection_string.ToInt32(ConnectionStringKeys.MaxPoolSize, 0, 1024, ConnectionStringDefaults.MaxPoolSize);
698             }
699         }
700
701         internal Int32 Timeout {
702             get
703             {
704                 return connection_string.ToInt32(ConnectionStringKeys.Timeout, 0, 1024, ConnectionStringDefaults.Timeout);
705             }
706         }
707
708
709
710         //
711         // Event handlers
712         //
713
714         /// <summary>
715         /// Default SSL CertificateSelectionCallback implementation.
716         /// </summary>
717         internal X509Certificate DefaultCertificateSelectionCallback(
718             X509CertificateCollection      clientCertificates,
719             X509Certificate                serverCertificate,
720             string                         targetHost,
721             X509CertificateCollection      serverRequestedCertificates)
722         {
723             if (CertificateSelectionCallback != null)
724             {
725                 return CertificateSelectionCallback(clientCertificates, serverCertificate, targetHost, serverRequestedCertificates);
726             }
727             else
728             {
729                 return null;
730             }
731         }
732
733         /// <summary>
734         /// Default SSL CertificateValidationCallback implementation.
735         /// </summary>
736         internal bool DefaultCertificateValidationCallback(
737             X509Certificate       certificate,
738             int[]                 certificateErrors)
739         {
740             if (CertificateValidationCallback != null)
741             {
742                 return CertificateValidationCallback(certificate, certificateErrors);
743             }
744             else
745             {
746                 return true;
747             }
748         }
749
750         /// <summary>
751         /// Default SSL PrivateKeySelectionCallback implementation.
752         /// </summary>
753         internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(
754             X509Certificate                certificate,
755             string                         targetHost)
756         {
757             if (PrivateKeySelectionCallback != null)
758             {
759                 return PrivateKeySelectionCallback(certificate, targetHost);
760             }
761             else
762             {
763                 return null;
764             }
765         }
766
767
768
769         //
770         // Private methods and properties
771         //
772
773
774         /// <summary>
775         /// Write each key/value pair in the connection string to the log.
776         /// </summary>
777         private void LogConnectionString()
778         {
779             foreach (DictionaryEntry DE in connection_string)
780             {
781                 NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, DE.Key, DE.Value);
782             }
783         }
784
785         private void CheckConnectionOpen()
786         {
787             if (disposed)
788             {
789                 throw new ObjectDisposedException(CLASSNAME);
790             }
791
792             if (connector == null)
793             {
794                 throw new InvalidOperationException(resman.GetString("Exception_ConnNotOpen"));
795             }
796         }
797
798         private void CheckConnectionClosed()
799         {
800             if (disposed)
801             {
802                 throw new ObjectDisposedException(CLASSNAME);
803             }
804
805             if (connector != null)
806             {
807                 throw new InvalidOperationException(resman.GetString("Exception_ConnOpen"));
808             }
809         }
810
811         private void CheckNotDisposed()
812         {
813             if (disposed)
814             {
815                 throw new ObjectDisposedException(CLASSNAME);
816             }
817         }
818         
819         
820         /// <summary>
821         /// Returns the supported collections
822         /// <summary>
823         public DataTable GetSchema()
824         {
825             return NpgsqlSchema.GetMetaDataCollections();
826         }
827
828         /// <summary>
829         /// Returns the schema collection specified by the collection name.
830         /// </summary>
831         /// <param name="collectionName">The collection name.</param>
832         /// <returns>The collection specified.</returns>
833         public DataTable GetSchema(string collectionName)
834         {
835             return GetSchema(collectionName, null);
836         }
837         
838         /// <summary>
839         /// Returns the schema collection specified by the collection name filtered by the restrictions.
840         /// </summary>
841         /// <param name="collectionName">The collection name.</param>
842         /// <param name="restrictions">
843         /// The restriction values to filter the results.  A description of the restrictions is contained
844         /// in the Restrictions collection.
845         /// </param>
846         /// <returns>The collection specified.</returns>
847         public DataTable GetSchema(string collectionName, string[] restrictions)
848         {
849             switch(collectionName)
850             {
851                 case "MetaDataCollections":
852                     return NpgsqlSchema.GetMetaDataCollections();
853                 case "Restrictions":
854                     return NpgsqlSchema.GetRestrictions();
855                 case "DataSourceInformation":
856                 case "DataTypes":
857                 case "ReservedWords":
858                     throw new NotSupportedException();
859                     // custom collections for npgsql
860                 case "Databases":
861                     return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetDatabases(restrictions);
862                 case "Tables":
863                     return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetTables(restrictions);
864                 case "Columns":
865                     return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetColumns(restrictions);
866                 case "Views":
867                     return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetViews(restrictions);
868                 case "Users":
869                     return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetUsers(restrictions);
870                 default:
871                     throw new NotSupportedException();
872             }
873         }
874
875         public void ClearPool()
876         {
877             NpgsqlConnectorPool.ConnectorPoolMgr.ClearPool(this);
878         }
879
880         public void ClearAllPools()
881         {
882             NpgsqlConnectorPool.ConnectorPoolMgr.ClearAllPools();
883         }
884
885     }
886
887
888
889 }