* FileSystemInfo.cs: corrected COM visibility of UTC properties
[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.Net;
30 using System.Net.Sockets;
31 using System.IO;
32 using System.Text;
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Security.Cryptography.X509Certificates;
36 using Mono.Security.Protocol.Tls;
37 using NpgsqlTypes;
38 using Npgsql.Design;
39
40
41 namespace Npgsql
42 {
43     /// <summary>
44     /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notification</see> events.
45     /// </summary>
46     /// <param name="sender">The source of the event.</param>
47     /// <param name="e">A <see cref="Npgsql.NpgsqlNotificationEventArgs">NpgsqlNotificationEventArgs</see> that contains the event data.</param>
48     public delegate void NotificationEventHandler(Object sender, NpgsqlNotificationEventArgs e);
49
50     /// <summary>
51     /// This class represents a connection to a
52     /// PostgreSQL server.
53     /// </summary>
54     [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))]
55     public sealed class NpgsqlConnection : Component, IDbConnection, ICloneable
56     {
57         //Changed the Name of this event because events usually don't start with 'On' in the .Net-Framework
58         // (but their handlers do ;-)
59         /// <summary>
60         /// Occurs on NotificationResponses from the PostgreSQL backend.
61         /// </summary>
62         public event NotificationEventHandler Notification;
63
64         
65         // Public properties for ssl callbacks
66         public CertificateValidationCallback CertificateValidationCallback;
67         public CertificateSelectionCallback CertificateSelectionCallback;
68         public PrivateKeySelectionCallback PrivateKeySelectionCallback;
69         
70         
71         
72         private NpgsqlState                     state;
73
74         private ConnectionState connection_state;
75         private String                                  connection_string;
76         internal ListDictionary connection_string_values;
77         // some of the following constants are needed
78         // for designtime support so I made them 'internal'
79         // as I didn't want to add another interface for internal access
80         // --brar
81         // In the connection string
82         internal readonly Char CONN_DELIM       = ';';  // Delimeter
83         internal readonly Char CONN_ASSIGN      = '=';
84         internal readonly String CONN_SERVER    = "SERVER";
85         internal readonly String CONN_USERID    = "USER ID";
86         internal readonly String CONN_PASSWORD  = "PASSWORD";
87         internal readonly String CONN_DATABASE  = "DATABASE";
88         internal readonly String CONN_PORT      = "PORT";
89         internal readonly String SSL_ENABLED    = "SSL";
90         // Postgres default port
91         internal readonly String PG_PORT = "5432";
92
93         // These are for ODBC connection string compatibility
94         internal readonly String ODBC_USERID    = "UID";
95         internal readonly String ODBC_PASSWORD = "PWD";
96         
97         // These are for the connection pool
98         internal readonly String MIN_POOL_SIZE = "MINPOOLSIZE";
99         internal readonly String MAX_POOL_SIZE = "MAXPOOLSIZE";
100         
101         internal readonly String CONN_ENCODING = "ENCODING";
102         
103         internal readonly String CONN_TIMEOUT = "TIMEOUT";
104         
105
106         // Values for possible CancelRequest messages.
107         private NpgsqlBackEndKeyData backend_keydata;
108
109         // Flag for transaction status.
110         private Boolean                                                 _inTransaction = false;
111
112         // Mediator which will hold data generated from backend
113         private NpgsqlMediator  _mediator;
114
115         // Logging related values
116         private readonly String CLASSNAME = "NpgsqlConnection";
117
118         private Stream                                  stream;
119         
120         private Connector               _connector;
121         
122         private Encoding                                connection_encoding;
123
124         private Boolean                                 _supportsPrepare = false;
125
126         private String                                  _serverVersion; // Contains string returned from select version();
127
128         private Hashtable                               _oidToNameMapping;
129
130         private System.Resources.ResourceManager resman;
131
132         private Int32                   _backendProtocolVersion;
133         
134         private Int32                   _connectionTimeout;
135
136
137         /// <summary>
138         /// Initializes a new instance of the
139         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class.
140         /// </summary>
141         public NpgsqlConnection() : this(String.Empty)
142         {}
143
144         /// <summary>
145         /// Initializes a new instance of the
146         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class
147         /// and sets the <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
148         /// </summary>
149         /// <param name="ConnectionString">The connection used to open the PostgreSQL database.</param>
150         public NpgsqlConnection(String ConnectionString)
151         {
152             resman = new System.Resources.ResourceManager(this.GetType());
153             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, ConnectionString);
154
155             connection_state = ConnectionState.Closed;
156             state = NpgsqlClosedState.Instance;
157             connection_string = ConnectionString;
158             connection_string_values = new ListDictionary();
159             connection_encoding = Encoding.Default;
160             _backendProtocolVersion = ProtocolVersion.Version3;
161
162             _mediator = new NpgsqlMediator();
163             _oidToNameMapping = new Hashtable();
164             
165             _connectionTimeout = 15;
166         
167             CertificateValidationCallback = new CertificateValidationCallback(DefaultCertificateValidationCallback);
168                     
169
170             if (connection_string != String.Empty)
171                 ParseConnectionString();
172         }
173
174         
175         /// <summary>
176         /// Gets or sets the string used to open a SQL Server database.
177         /// </summary>
178         /// <value>The connection string that includes the server name,
179         /// the database name, and other parameters needed to establish
180         /// the initial connection. The default value is an empty string.
181         /// </value>
182         [RefreshProperties(RefreshProperties.All), DefaultValue(""), RecommendedAsConfigurable(true)]
183         [NpgsqlSysDescription("Description_ConnectionString", typeof(NpgsqlConnection)), Category("Data")]
184         [Editor(typeof(ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
185         public String ConnectionString {
186             get
187             {
188                 return connection_string;
189             }
190             set
191             {
192                 NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value);
193                 connection_string = value;
194                 if (connection_string != String.Empty)
195                     ParseConnectionString();
196             }
197         }
198
199         /// <summary>
200         /// Gets the time to wait while trying to establish a connection
201         /// before terminating the attempt and generating an error.
202         /// </summary>
203         /// <value>The time (in seconds) to wait for a connection to open. The default value is 15 seconds.</value>
204         [NpgsqlSysDescription("Description_ConnectionTimeout", typeof(NpgsqlConnection))]
205         public Int32 ConnectionTimeout {
206             get
207             {
208                 return _connectionTimeout;
209             }
210         }
211
212         ///<summary>
213         /// Gets the name of the current database or the database to be used after a connection is opened.
214         /// </summary>
215         /// <value>The name of the current database or the name of the database to be
216         /// used after a connection is opened. The default value is an empty string.</value>
217         [NpgsqlSysDescription("Description_Database", typeof(NpgsqlConnection))]
218         public String Database {
219             get
220             {
221                 return DatabaseName;
222             }
223         }
224
225         /// <summary>
226         /// Gets the current state of the connection.
227         /// </summary>
228         /// <value>A bitwise combination of the <see cref="System.Data.ConnectionState">ConnectionState</see> values. The default is <b>Closed</b>.</value>
229         [Browsable(false)]
230         public ConnectionState State {
231             get
232             {
233                 return connection_state;
234             }
235         }
236
237         /// <summary>
238         /// Begins a database transaction.
239         /// </summary>
240         /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
241         /// object representing the new transaction.</returns>
242         /// <remarks>
243         /// Currently there's no support for nested transactions.
244         /// </remarks>
245         IDbTransaction IDbConnection.BeginTransaction()
246         {
247             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction");
248             //throw new NotImplementedException();
249             return BeginTransaction();
250         }
251
252         /// <summary>
253         /// Begins a database transaction with the specified isolation level.
254         /// </summary>
255         /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
256         /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
257         /// object representing the new transaction.</returns>
258         /// <remarks>
259         /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
260         /// There's no support for nested transactions.
261         /// </remarks>
262         IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
263         {
264             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction", level);
265             //throw new NotImplementedException();
266             return BeginTransaction(level);
267         }
268
269
270         // I had to rename this Method from Notification to Notify due to the renaming of OnNotification to Notification
271         /// <summary>
272         /// Creates a Notification event
273         /// </summary>
274         /// <param name="e">The <see cref="Npgsql.NpgsqlNotificationEventArgs">NpgsqlNotificationEventArgs</see> that contains the event data.</param>
275         internal void Notify(NpgsqlNotificationEventArgs e)
276         {
277             if (Notification != null)
278                 Notification(this, e);
279         }
280
281         /// <summary>
282         /// Begins a database transaction.
283         /// </summary>
284         /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
285         /// object representing the new transaction.</returns>
286         /// <remarks>
287         /// Currently there's no support for nested transactions.
288         /// </remarks>
289         public NpgsqlTransaction BeginTransaction()
290         {
291             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction");
292             return this.BeginTransaction(IsolationLevel.ReadCommitted);
293         }
294
295         /// <summary>
296         /// Begins a database transaction with the specified isolation level.
297         /// </summary>
298         /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
299         /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
300         /// object representing the new transaction.</returns>
301         /// <remarks>
302         /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
303         /// There's no support for nested transactions.
304         /// </remarks>
305         public NpgsqlTransaction BeginTransaction(IsolationLevel level)
306         {
307             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level);
308
309             if (_inTransaction)
310                 throw new InvalidOperationException(resman.GetString("Exception_NoNestedTransactions"));
311
312
313             return new NpgsqlTransaction(this, level);
314         }
315
316         /// <summary>
317         /// This method changes the current database by disconnecting from the actual
318         /// database and connecting to the specified.
319         /// </summary>
320         /// <param name="dbName">The name of the database to use in place of the current database.</param>
321         public void ChangeDatabase(String dbName)
322         {
323             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeDatabase", dbName);
324             //throw new NotImplementedException();
325
326             if (dbName == null)
327                 throw new ArgumentNullException("dbName");
328
329             if (dbName == String.Empty)
330                 throw new ArgumentException(String.Format(resman.GetString("Exception_InvalidDbName"), dbName), "dbName");
331
332             if(this.connection_state != ConnectionState.Open)
333                 throw new InvalidOperationException(resman.GetString("Exception_ChangeDatabaseOnOpenConn"));
334
335             String oldDatabaseName = (String)connection_string_values[CONN_DATABASE];
336             Close();
337
338             connection_string_values[CONN_DATABASE] = dbName;
339
340             Open();
341
342
343
344         }
345
346         /// <summary>
347         /// Opens a database connection with the property settings specified by the
348         /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
349         /// </summary>
350         public void Open()
351         {
352             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
353
354             // I moved this here from ParseConnectionString as there is no need to validate the
355             // ConnectionString before we open the connection.
356             // See: http://gborg.postgresql.org/pipermail/npgsql-hackers/2003-March/000019.html
357             // In fact it makes it possible to parse incomplete ConnectionStrings for designtime support
358             // -- brar
359             //
360             // Now check if there is any missing argument.
361             if (connection_string == String.Empty)
362                 throw new InvalidOperationException(resman.GetString("Exception_ConnStrEmpty"));
363             if (connection_string_values[CONN_SERVER] == null)
364                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_SERVER);
365             if ((connection_string_values[CONN_USERID] == null) & (connection_string_values[ODBC_USERID] == null))
366                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_USERID);
367             if ((connection_string_values[CONN_PASSWORD] == null) & (connection_string_values[ODBC_PASSWORD] == null))
368                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_PASSWORD);
369             if (connection_string_values[CONN_DATABASE] == null)
370                 // Database is optional. "[...] defaults to the user name if empty"
371                 connection_string_values[CONN_DATABASE] = connection_string_values[CONN_USERID];
372             if (connection_string_values[CONN_PORT] == null)
373                 // Port is optional. Defaults to PG_PORT.
374                 connection_string_values[CONN_PORT] = PG_PORT;
375             if (connection_string_values[SSL_ENABLED] == null)
376                 connection_string_values[SSL_ENABLED] = "no";
377             if (connection_string_values[MIN_POOL_SIZE] == null)
378                 connection_string_values[MIN_POOL_SIZE] = "1";
379             if (connection_string_values[MAX_POOL_SIZE] == null)
380                 connection_string_values[MAX_POOL_SIZE] = "20";
381             if (connection_string_values[CONN_ENCODING] == null)
382                 connection_string_values[CONN_ENCODING] = "SQL_ASCII";
383             if (connection_string_values[CONN_TIMEOUT] == null)
384                 connection_string_values[CONN_TIMEOUT] = "15";                
385             
386             try
387             {
388             
389                 // Check if the connection is already open.
390                 if (connection_state == ConnectionState.Open)
391                     throw new NpgsqlException(resman.GetString("Exception_ConnOpen"));
392
393                 lock(ConnectorPool.ConnectorPoolMgr)
394                 {
395                     Connector = ConnectorPool.ConnectorPoolMgr.RequestConnector(ConnectionString, 
396                                                                                 Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]),
397                                                                                 Int32.Parse((String)connection_string_values[CONN_TIMEOUT]),
398                                                                                 false);
399                     Connector.InUse = true;
400                 }
401                 
402                 if (!Connector.IsInitialized)
403                 {
404                     
405                     // Reset state to initialize new connector in pool.
406                     CurrentState = NpgsqlClosedState.Instance;
407
408                     // Try first connect using the 3.0 protocol...
409                     CurrentState.Open(this);
410                     
411                     // Change the state of connection to open.
412                     connection_state = ConnectionState.Open;
413         
414                     // Check if there were any errors.
415                     if (_mediator.Errors.Count > 0)
416                     {
417                         // Check if there is an error of protocol not supported...
418                         // As the message can be localized, just check the initial unlocalized part of the
419                         // message. If it is an error other than protocol error, when connecting using
420                         // version 2.0 we shall catch the error again.
421                         if (((String)_mediator.Errors[0]).StartsWith("FATAL"))
422                         {
423                             // Try using the 2.0 protocol.
424                             _mediator.Reset();
425                             CurrentState = NpgsqlClosedState.Instance;
426                             BackendProtocolVersion = ProtocolVersion.Version2;
427                             CurrentState.Open(this);
428                         }
429     
430                         // Keep checking for errors...
431                         if(_mediator.Errors.Count > 0)
432                         {
433                             StringWriter sw = new StringWriter();
434                             sw.WriteLine(resman.GetString("Exception_OpenError"));
435                             uint i = 1;
436                             foreach(string error in _mediator.Errors)
437                             {
438                                 sw.WriteLine("{0}. {1}", i++, error);
439                             }
440                             CurrentState = NpgsqlClosedState.Instance;
441                             _mediator.Reset();
442                             throw new NpgsqlException(sw.ToString());
443                         }
444                     }
445     
446                     backend_keydata = _mediator.GetBackEndKeyData();
447
448                     // Get version information to enable/disable server version features.
449                     // Only for protocol 2.0.
450                     if (BackendProtocolVersion == ProtocolVersion.Version2)
451                     {
452                         NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
453                         _serverVersion = (String) command.ExecuteScalar();
454                     }
455                     
456                     // Adjust client encoding. 
457                 
458                     //NpgsqlCommand commandEncoding = new NpgsqlCommand("show client_encoding", this);
459                     //String clientEncoding = (String)commandEncoding.ExecuteScalar();
460     
461                     if (connection_string_values[CONN_ENCODING].Equals("UNICODE"))
462                         connection_encoding = Encoding.UTF8;
463                   
464                     
465                     Connector.ServerVersion = ServerVersion;
466                     Connector.BackendProtocolVersion = BackendProtocolVersion;
467                     Connector.Encoding = connection_encoding;
468                     
469                 }
470                                 
471                 // Connector was obtained from pool. 
472                 // Do a mini initialization in the state machine.
473                 
474                 connection_state = ConnectionState.Open;
475                 ServerVersion = Connector.ServerVersion;
476                 BackendProtocolVersion = Connector.BackendProtocolVersion;
477                 Encoding = Connector.Encoding;
478                 
479                 CurrentState = NpgsqlReadyState.Instance;
480                 
481                 ProcessServerVersion();
482                 _oidToNameMapping = NpgsqlTypesHelper.LoadTypesMapping(this);
483                 
484                 
485                 
486
487             }
488
489             catch(IOException e)
490             {
491                 // This exception was thrown by StartupPacket handling functions.
492                 // So, close the connection and throw the exception.
493                 // [TODO] Better exception handling. :)
494                 Close();
495
496                 throw new NpgsqlException(resman.GetString("Exception_OpenError"), e);
497             }
498
499         }
500
501         /// <summary>
502         /// Closes the connection to the database.
503         /// </summary>
504         public void Close()
505         {
506             Dispose(true);
507             
508         }
509
510         /// <summary>
511         /// Creates and returns a <see cref="System.Data.IDbCommand">IDbCommand</see>
512         /// object associated with the <see cref="System.Data.IDbConnection">IDbConnection</see>.
513         /// </summary>
514         /// <returns>A <see cref="System.Data.IDbCommand">IDbCommand</see> object.</returns>
515         IDbCommand IDbConnection.CreateCommand()
516         {
517             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.CreateCommand");
518             return (NpgsqlCommand) CreateCommand();
519         }
520
521         /// <summary>
522         /// Creates and returns a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
523         /// object associated with the <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
524         /// </summary>
525         /// <returns>A <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> object.</returns>
526         public NpgsqlCommand CreateCommand()
527         {
528             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateCommand");
529             return new NpgsqlCommand("", this);
530         }
531
532         /// <summary>
533         /// Releases the unmanaged resources used by the
534         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>
535         /// and optionally releases the managed resources.
536         /// </summary>
537         /// <param name="disposing"><b>true</b> to release both managed and unmanaged resources;
538         /// <b>false</b> to release only unmanaged resources.</param>
539         protected override void Dispose(bool disposing)
540         {
541             if (disposing)
542             {
543                 // Only if explicitly calling Close or dispose we still have access to 
544                 // managed resources.
545                 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose", disposing);
546
547                 try
548                 {
549                     if ((connection_state == ConnectionState.Open))
550                     {
551                         CurrentState.Close(this);
552                     }
553                     
554                 }
555                 catch (IOException e)
556                 {
557                     throw new NpgsqlException(resman.GetString("Exception_CloseError"), e);
558                 }
559                 finally
560                 {
561                     // Even if an exception occurs, let object in a consistent state.
562                     /*if (stream != null)
563                         stream.Close();*/
564                     connection_state = ConnectionState.Closed;
565                 }
566                                 
567             }
568             base.Dispose (disposing);
569         }
570         
571         
572         public Object Clone()
573         {
574             return new NpgsqlConnection(ConnectionString);
575         }
576
577         // Private util methods
578
579         /// <summary>
580         /// This method parses the connection string.
581         /// It translates it to a list of key-value pairs.
582         /// Valid values are:
583         /// Server              - Address/Name of Postgresql Server
584         /// Port                - Port to connect to.
585         /// Database    - Database name. Defaults to user name if not specified
586         /// User                - User name
587         /// Password    - Password for clear text authentication
588         /// MinPoolSize - Min size of connection pool
589         /// MaxPoolSize - Max size of connection pool
590         /// Encoding    - Encoding to be used
591         /// Timeout     - Time to wait for connection open. In seconds.
592         /// </summary>
593         private void ParseConnectionString()
594         {
595             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ParseConnectionString");
596
597             connection_string_values.Clear();
598
599             // Get the key-value pairs delimited by CONN_DELIM
600             String[] pairs = connection_string.Split(new Char[] {CONN_DELIM});
601
602             String[] keyvalue;
603             // Now, for each pair, get its key-value.
604             foreach(String s in pairs)
605             {
606                 // This happen when there are trailling/empty CONN_DELIMs
607                 // Just ignore them.
608                 if (s == "")
609                     continue;
610
611                 keyvalue = s.Split(new Char[] {CONN_ASSIGN});
612
613                 // Check if there is a key-value pair.
614                 if (keyvalue.Length != 2)
615                     throw new ArgumentException(resman.GetString("Exception_WrongKeyVal"), connection_string);
616
617                 // Shift the key to upper case, and substitute ODBC style keys
618                 keyvalue[0] = keyvalue[0].ToUpper();
619                 if (keyvalue[0] == ODBC_USERID)
620                     keyvalue[0] = CONN_USERID;
621                 if (keyvalue[0] == ODBC_PASSWORD)
622                     keyvalue[0] = CONN_PASSWORD;
623
624                 // Add the pair to the dictionary. The key is shifted to upper
625                 // case for case insensitivity.
626
627                 NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, keyvalue[0], keyvalue[1]);
628                 connection_string_values.Add(keyvalue[0], keyvalue[1]);
629             }
630         }
631
632
633         /// <summary>
634         /// This method is required to set all the version dependent features flags.
635         /// SupportsPrepare means the server can use prepared query plans (7.3+)
636         /// </summary>
637         private void ProcessServerVersion ()
638         {
639             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessServerVersion");
640             // FIXME: Do a better parsing of server version to avoid
641             // hardcode version numbers.
642
643             if (BackendProtocolVersion == ProtocolVersion.Version2)
644             {
645                 // With protocol version 2, only 7.3 version supports prepare.
646                 SupportsPrepare = (_serverVersion.IndexOf("PostgreSQL 7.3") != -1);
647             }
648             else
649             {
650                 // 3.0+ version is set by ParameterStatus message.
651                 // On protocol 3.0, 7.4 and above support it.
652                 SupportsPrepare = (_serverVersion.IndexOf("7.4") != -1)
653                                     || (_serverVersion.IndexOf("7.5") != -1);
654             }
655         }
656
657         internal Stream Stream {
658             get
659             {
660                 return _connector.Stream;
661             }
662             set
663             {
664                 stream = value;
665             }
666         }
667         
668         internal Connector Connector
669         {
670             get
671             {
672                 return _connector;
673             }
674             set
675             {
676                 _connector = value;
677             }
678         }
679
680         /*
681         public bool useSSL() 
682         {
683                 if (SSL_ENABLED=="yes")
684                         return true;
685
686                 return false;
687         }
688         */
689
690         // State
691         internal void Query (NpgsqlCommand queryCommand)
692         {
693             CurrentState.Query(this, queryCommand );
694         }
695
696         internal void Authenticate (string password)
697         {
698             CurrentState.Authenticate(this, password );
699         }
700
701         internal void Startup ()
702         {
703             CurrentState.Startup(this);
704         }
705
706         internal void Parse (NpgsqlParse parse)
707         {
708             CurrentState.Parse(this, parse);
709         }
710
711         internal void Flush ()
712         {
713             CurrentState.Flush(this);
714         }
715
716         internal void Sync ()
717         {
718             CurrentState.Sync(this);
719         }
720
721         internal void Bind (NpgsqlBind bind)
722         {
723             CurrentState.Bind(this, bind);
724         }
725
726         internal void Execute (NpgsqlExecute execute)
727         {
728             CurrentState.Execute(this, execute);
729         }
730         
731         
732         // Default SSL Callbacks implementation.
733         private Boolean DefaultCertificateValidationCallback(
734                                                     X509Certificate certificate,
735                                                     int[]        certificateErrors)
736         {
737             return true;
738         }
739         
740         
741
742         internal NpgsqlState CurrentState {
743             get
744             {
745                 return state;
746             }
747             set
748             {
749                 state = value;
750             }
751         }
752
753         internal NpgsqlBackEndKeyData BackEndKeyData {
754             get
755             {
756                 return backend_keydata;
757             }
758             set
759             {
760                 backend_keydata = value;
761             }
762         }
763
764         internal String ServerName {
765             get
766             {
767                 return (String)connection_string_values[CONN_SERVER];
768             }
769         }
770
771         internal String ServerPort {
772             get
773             {
774                 return   (String)connection_string_values[CONN_PORT];
775             }
776         }
777
778         internal String DatabaseName {
779             get
780             {
781                 return (String)connection_string_values[CONN_DATABASE];
782             }
783         }
784
785         internal String UserName {
786             get
787             {
788                 return (String)connection_string_values[CONN_USERID];
789             }
790         }
791
792         internal String ServerPassword {
793             get
794             {
795                 return (String)connection_string_values[CONN_PASSWORD];
796             }
797         }
798
799         internal String SSL {
800             get
801             {
802                 return (String)connection_string_values[SSL_ENABLED];
803             }
804         }
805
806         internal Encoding Encoding {
807             get
808             {
809                 return connection_encoding;
810             }
811             
812             set
813             {
814                 connection_encoding = value;
815             }
816         }
817
818         internal NpgsqlMediator Mediator {
819             get
820             {
821                 return _mediator;
822             }
823         }
824
825         internal Boolean InTransaction {
826             get
827             {
828                 return _inTransaction;
829             }
830             set
831             {
832                 _inTransaction = value;
833             }
834         }
835
836         internal Boolean SupportsPrepare {
837             get
838             {
839                 return _supportsPrepare;
840             }
841             set
842             {
843                 _supportsPrepare = value;
844             }
845         }
846
847         internal String ServerVersion {
848             get
849             {
850                 return _serverVersion;
851             }
852             set
853             {
854                 _serverVersion = value;
855             }
856         }
857
858         internal Hashtable OidToNameMapping {
859             get
860             {
861                 return _oidToNameMapping;
862             }
863             set
864             {
865                 _oidToNameMapping = value;
866             }
867
868         }
869
870         internal Int32 BackendProtocolVersion {
871             get
872             {
873                 return _backendProtocolVersion;
874             }
875             set
876             {
877                 _backendProtocolVersion = value;
878             }
879         }
880         
881         internal Int32 MinPoolSize {
882             get
883             {
884                 return Int32.Parse((String)connection_string_values[MIN_POOL_SIZE]);
885             }
886         }
887         
888         internal Int32 MaxPoolSize {
889             get
890             {
891                 return Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]);
892             }
893         }
894
895     }
896
897 }