2004-05-20 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
authorFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>
Fri, 21 May 2004 00:04:00 +0000 (00:04 -0000)
committerFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>
Fri, 21 May 2004 00:04:00 +0000 (00:04 -0000)
NpgsqlAsciiRow.cs,
NpgsqlBackEndKeyData.cs,
NpgsqlBinaryRow.cs,
NpgsqlCommand.cs,
NpgsqlConnectedState.cs,
NpgsqlConnection.cs,
NpgsqlConnection.resx,
NpgsqlConnector.cs,
NpgsqlConnectorPool.cs,
NpgsqlError.cs,
NpgsqlMediator.cs,
NpgsqlMessageTypes.cs,
NpgsqlPasswordPacket.cs,
NpgsqlQuery.cs,
NpgsqlRowDescription.cs,
NpgsqlStartupPacket.cs,
NpgsqlState.cs,
PGUtil.cs,
NpgsqlTypes/NpgsqlTypesHelper.cs : - store protocol version as an enum, keep numbers as protocol specific
- split more protocol handlers between version 2 and version 3
- split MessageTypes class on ver2/ver3 and add remaining types for ver3 - removed handlers for deprecated protocol message types
- store BackendKeyData in its own member on Mediator
- Store ParameterStatus objects in a key map on Mediator
- Get backend version now from the Mediator if possible
- Rewrite parsers for server version and connection string
- Store server version numericially (in a new class ServerVersion)
- As usual, lots of code cleanup/commenting/etc.

Thanks very much Glen Parker (glenebob@nwlink.com) for this patch.

svn path=/trunk/mcs/; revision=27786

18 files changed:
mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs
mcs/class/Npgsql/Npgsql/NpgsqlBinaryRow.cs
mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnection.resx
mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
mcs/class/Npgsql/Npgsql/NpgsqlError.cs
mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs
mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs
mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs
mcs/class/Npgsql/Npgsql/NpgsqlState.cs
mcs/class/Npgsql/Npgsql/PGUtil.cs

index e0cc2e6981758695d4134dbf86cf8f8121b263b1..a170c7a263a6c8c19fb261c19e1025fff905024e 100755 (executable)
@@ -44,15 +44,15 @@ namespace Npgsql
         // Logging related values
         private static readonly String CLASSNAME = "NpgsqlAsciiRow";
 
-        private ArrayList                                                      data;
-        private readonly Int16 READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
-        private NpgsqlRowDescription row_desc;
-        private Hashtable                                                      oid_to_name_mapping;
-        private Int32                 protocol_version;
+        private ArrayList             data;
+        private readonly Int16        READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
+        private NpgsqlRowDescription  row_desc;
+        private Hashtable             oid_to_name_mapping;
+        private ProtocolVersion       protocol_version;
 
 
 
-        public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, Hashtable oidToNameMapping, Int32 protocolVersion)
+        public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, Hashtable oidToNameMapping, ProtocolVersion protocolVersion)
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
 
@@ -60,24 +60,25 @@ namespace Npgsql
             row_desc = rowDesc;
             oid_to_name_mapping = oidToNameMapping;
             protocol_version = protocolVersion;
-
         }
 
         public void ReadFromStream(Stream inputStream, Encoding encoding)
         {
-            if (protocol_version == ProtocolVersion.Version2)
-            {
+            switch (protocol_version) {
+            case ProtocolVersion.Version2 :
                 ReadFromStream_Ver_2(inputStream, encoding);
-            }
-            else
-            {
+                break;
+
+            case ProtocolVersion.Version3 :
                 ReadFromStream_Ver_3(inputStream, encoding);
+                break;
+
             }
         }
 
         private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2()");
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
 
             Byte[]       input_buffer = new Byte[READ_BUFFER_SIZE];
             Byte[]       null_map_array = new Byte[(row_desc.NumFields + 7)/8];
@@ -136,7 +137,7 @@ namespace Npgsql
 
         private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3()");
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
 
             Byte[] input_buffer = new Byte[READ_BUFFER_SIZE];
 
index 4321bbbebd8b4ccb5cd34d6bc73698b43f6932b3..693c5c88de0026a0d8c04a6de2d3b4af21984fe8 100755 (executable)
@@ -44,9 +44,9 @@ namespace Npgsql
         private Int32 _processId;
         private Int32 _secretKey;
 
-        private Int32 _protocolVersion;
+        private ProtocolVersion _protocolVersion;
 
-        public NpgsqlBackEndKeyData(Int32 protocolVersion)
+        public NpgsqlBackEndKeyData(ProtocolVersion protocolVersion)
         {
             _protocolVersion = protocolVersion;
             _processId = -1;
index 59566b53c8c506449f9c21f79d3442a1dbaeab43..20d57875d4cde86e79f748e1c0224630c2e5cf35 100755 (executable)
@@ -35,8 +35,8 @@ namespace Npgsql
 {
 
     /// <summary>
-    /// This class represents the AsciiRow message sent from PostgreSQL
-    /// server.
+    /// This class represents the BinaryRow message sent from PostgreSQL
+    /// server.  This is unused as of protocol version 3.
     /// </summary>
     ///
     internal sealed class NpgsqlBinaryRow
@@ -44,9 +44,8 @@ namespace Npgsql
         // Logging related values
         private static readonly String CLASSNAME = "NpgsqlBinaryRow";
 
-        private ArrayList                                                      data;
-        //        private readonly Int16       READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
-        private NpgsqlRowDescription row_desc;
+        private ArrayList                  data;
+        private NpgsqlRowDescription       row_desc;
 
         public NpgsqlBinaryRow(NpgsqlRowDescription rowDesc)
         {
@@ -54,7 +53,6 @@ namespace Npgsql
 
             data = new ArrayList();
             row_desc = rowDesc;
-
         }
 
 
index 37330b967e65f2f031f5b920f03ec717a219e994..a83e91de3a71f99bd2fb4157b7b0a8144fcfb8cd 100755 (executable)
@@ -348,12 +348,12 @@ namespace Npgsql
             // The only expected result is the CompletedResponse result.
             // If nothing is returned, just return -1.
 
-            if(connection.Mediator.GetCompletedResponses().Count == 0)
+            if(connection.Mediator.CompletedResponses.Count == 0)
                 return -1;
 
 
             // Check if the response is available.
-            String firstCompletedResponse = (String)connection.Mediator.GetCompletedResponses()[0];
+            String firstCompletedResponse = (String)connection.Mediator.CompletedResponses[0];
 
             if (firstCompletedResponse == null)
                 return -1;
@@ -452,7 +452,7 @@ namespace Npgsql
 
 
             // Get the resultsets and create a Datareader with them.
-            return new NpgsqlDataReader(connection.Mediator.GetResultSets(), connection.Mediator.GetCompletedResponses(), connection, cb);
+            return new NpgsqlDataReader(connection.Mediator.ResultSets, connection.Mediator.CompletedResponses, connection, cb);
         }
 
 
@@ -520,7 +520,7 @@ namespace Npgsql
             // Only the first column of the first row must be returned.
 
             // Get ResultSets.
-            ArrayList resultSets = connection.Mediator.GetResultSets();
+            ArrayList resultSets = connection.Mediator.ResultSets;
 
 
             // First data is the RowDescription object.
index 991151a5340b0d9f34223a8aa3e61653eeb217c5..e4389a471edb60913906d6e25df5975b7715b4e3 100755 (executable)
@@ -35,6 +35,7 @@ namespace Npgsql
 
         private NpgsqlConnectedState()
         {}
+
         public static NpgsqlConnectedState Instance
         {
             get
@@ -46,41 +47,19 @@ namespace Npgsql
                 return _instance;
             }
         }
+
         public override void Startup(NpgsqlConnection context)
         {
-            if (context.BackendProtocolVersion == ProtocolVersion.Version3)
-            {
-
-                NpgsqlStartupPacket startupPacket  = new NpgsqlStartupPacket(296, //Not used.
-                                                     3,
-                                                     0,
-                                                     context.DatabaseName,
-                                                     context.UserName,
-                                                     "",
-                                                     "",
-                                                     "");
-
-                startupPacket.WriteToStream( new BufferedStream(context.Stream), context.Encoding );
-                ProcessBackendResponses( context );
-            }
-            else if (context.BackendProtocolVersion == ProtocolVersion.Version2)
-            {
-
-                NpgsqlStartupPacket startupPacket  = new NpgsqlStartupPacket(296,
-                                                     2,
-                                                     0,
-                                                     context.DatabaseName,
-                                                     context.UserName,
-                                                     "",
-                                                     "",
-                                                     "");
-
-                startupPacket.WriteToStream( new BufferedStream(context.Stream), context.Encoding );
-                ProcessBackendResponses( context );
-
-
-            }
+            NpgsqlStartupPacket startupPacket  = new NpgsqlStartupPacket(296, //Not used.
+                                                  context.BackendProtocolVersion,
+                                                  context.DatabaseName,
+                                                  context.UserName,
+                                                  "",
+                                                  "",
+                                                  "");
 
+            startupPacket.WriteToStream( new BufferedStream(context.Stream), context.Encoding );
+            ProcessBackendResponses( context );
         }
 
     }
index 7928d3935e46fb2cd639c8a0d170f390d3664934..c351d1e7ec22f63d485b575de290d7c27209729f 100755 (executable)
@@ -54,26 +54,26 @@ namespace Npgsql
     [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))]
     public sealed class NpgsqlConnection : Component, IDbConnection, ICloneable
     {
+        // Logging related values
+        private readonly String CLASSNAME = "NpgsqlConnection";
+
         //Changed the Name of this event because events usually don't start with 'On' in the .Net-Framework
         // (but their handlers do ;-)
         /// <summary>
         /// Occurs on NotificationResponses from the PostgreSQL backend.
         /// </summary>
-        public event NotificationEventHandler Notification;
-
+        public event NotificationEventHandler   Notification;
 
         // Public properties for ssl callbacks
-        public CertificateValidationCallback CertificateValidationCallback;
-        public CertificateSelectionCallback CertificateSelectionCallback;
-        public PrivateKeySelectionCallback PrivateKeySelectionCallback;
-
+        public CertificateValidationCallback    CertificateValidationCallback;
+        public CertificateSelectionCallback     CertificateSelectionCallback;
+        public PrivateKeySelectionCallback      PrivateKeySelectionCallback;
 
+        private NpgsqlState                                    state;
 
-        private NpgsqlState                    state;
-
-        private ConnectionState        connection_state;
-        private String                                 connection_string;
-        internal ListDictionary        connection_string_values;
+        private ConnectionState                 connection_state;
+        private String                          connection_string;
+        internal ListDictionary                 connection_string_values;
         // some of the following constants are needed
         // for designtime support so I made them 'internal'
         // as I didn't want to add another interface for internal access
@@ -104,36 +104,27 @@ namespace Npgsql
 
 
         // Values for possible CancelRequest messages.
-        private NpgsqlBackEndKeyData backend_keydata;
+        private NpgsqlBackEndKeyData            backend_keydata;
 
         // Flag for transaction status.
-        private Boolean                                                        _inTransaction = false;
+        private Boolean                         _inTransaction = false;
 
         // Mediator which will hold data generated from backend
-        private NpgsqlMediator _mediator;
-
-        // Logging related values
-        private readonly String CLASSNAME = "NpgsqlConnection";
-
-        private Stream                                 stream;
+        private NpgsqlMediator                  _mediator;
+        private Stream                          stream;
+        private Connector                       _connector;
+        private Encoding                        connection_encoding;
 
-        private Connector               _connector;
+        private ServerVersion                   _serverVersion;
+        private ProtocolVersion                 _backendProtocolVersion;
+        private Int32                           _connectionTimeout;
 
-        private Encoding                               connection_encoding;
+        private Boolean                         _supportsPrepare = false;
 
-        private Boolean                                        _supportsPrepare = false;
-
-        private String                                         _serverVersion; // Contains string returned from select version();
-
-        private Hashtable                              _oidToNameMapping;
+        private Hashtable                       _oidToNameMapping;
 
         private System.Resources.ResourceManager resman;
 
-        private Int32                   _backendProtocolVersion;
-
-        private Int32                   _connectionTimeout;
-
-
         /// <summary>
         /// Initializes a new instance of the
         /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class.
@@ -155,7 +146,7 @@ namespace Npgsql
             connection_state = ConnectionState.Closed;
             state = NpgsqlClosedState.Instance;
             connection_string = ConnectionString;
-            connection_string_values = new ListDictionary();
+            connection_string_values = new ListDictionary(CaseInsensitiveComparer.Default);
             connection_encoding = Encoding.Default;
             _backendProtocolVersion = ProtocolVersion.Version3;
 
@@ -167,11 +158,9 @@ namespace Npgsql
             CertificateValidationCallback = new CertificateValidationCallback(DefaultCertificateValidationCallback);
 
 
-            if (connection_string != String.Empty)
-                ParseConnectionString();
+            ParseAndSetConnectionString(ConnectionString);
         }
 
-
         /// <summary>
         /// Gets or sets the string used to open a SQL Server database.
         /// </summary>
@@ -190,9 +179,7 @@ namespace Npgsql
             set
             {
                 NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value);
-                connection_string = value;
-                if (connection_string != String.Empty)
-                    ParseConnectionString();
+                ParseAndSetConnectionString(value);
             }
         }
 
@@ -331,7 +318,7 @@ namespace Npgsql
             if(this.connection_state != ConnectionState.Open)
                 throw new InvalidOperationException(resman.GetString("Exception_ChangeDatabaseOnOpenConn"));
 
-            String oldDatabaseName = (String)connection_string_values[CONN_DATABASE];
+            String oldDatabaseName = ConnectStringValueToString(CONN_DATABASE);
             Close();
 
             connection_string_values[CONN_DATABASE] = dbName;
@@ -361,10 +348,12 @@ namespace Npgsql
                 throw new InvalidOperationException(resman.GetString("Exception_ConnStrEmpty"));
             if (connection_string_values[CONN_SERVER] == null)
                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_SERVER);
-            if ((connection_string_values[CONN_USERID] == null) & (connection_string_values[ODBC_USERID] == null))
+            if (connection_string_values[CONN_USERID] == null)
                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_USERID);
-            if ((connection_string_values[CONN_PASSWORD] == null) & (connection_string_values[ODBC_PASSWORD] == null))
+            if (connection_string_values[CONN_PASSWORD] == null)
                 throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), CONN_PASSWORD);
+
+            // Check and use defaults for these missing arguments.
             if (connection_string_values[CONN_DATABASE] == null)
                 // Database is optional. "[...] defaults to the user name if empty"
                 connection_string_values[CONN_DATABASE] = connection_string_values[CONN_USERID];
@@ -384,6 +373,7 @@ namespace Npgsql
 
             try
             {
+                String       ServerVersionString = String.Empty;
 
                 // Check if the connection is already open.
                 if (connection_state == ConnectionState.Open)
@@ -392,15 +382,14 @@ namespace Npgsql
                 lock(ConnectorPool.ConnectorPoolMgr)
                 {
                     Connector = ConnectorPool.ConnectorPoolMgr.RequestConnector(ConnectionString,
-                                Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]),
-                                Int32.Parse((String)connection_string_values[CONN_TIMEOUT]),
+                                ConnectStringValueToInt32(MAX_POOL_SIZE),
+                                ConnectStringValueToInt32(CONN_TIMEOUT),
                                 false);
                     Connector.InUse = true;
                 }
 
                 if (!Connector.IsInitialized)
                 {
-
                     // Reset state to initialize new connector in pool.
                     CurrentState = NpgsqlClosedState.Instance;
 
@@ -427,29 +416,38 @@ namespace Npgsql
                         }
 
                         // Keep checking for errors...
-                        if(_mediator.Errors.Count > 0)
+                        if(_mediator.Errors.Count > 0) {
                             throw new NpgsqlException(_mediator.Errors);
-
+                        }
                     }
 
-                    backend_keydata = _mediator.GetBackEndKeyData();
+                    backend_keydata = _mediator.BackendKeyData;
+
+                    // First try to determine backend server version using the newest method.
+                    try {
+                        ServerVersionString = ((NpgsqlParameterStatus)_mediator.Parameters["__npgsql_server_version"]).ParameterValue;
+                    } catch {}
 
-                    // Get version information to enable/disable server version features.
-                    // Only for protocol 2.0.
-                    if (BackendProtocolVersion == ProtocolVersion.Version2)
+                    // Fall back to the old way, SELECT VERSION().
+                    // This should not happen for protocol version 3+.
+                    if (ServerVersionString.Length == 0)
                     {
                         NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
-                        _serverVersion = (String) command.ExecuteScalar();
+                        ServerVersionString = ExtractServerVersion( (String)command.ExecuteScalar() );
                     }
 
+                    // Cook version string so we can use it for enabling/disabling things based on
+                    // backend version.
+                    _serverVersion = ParseServerVersion(ServerVersionString);
+
                     // Adjust client encoding.
 
                     //NpgsqlCommand commandEncoding = new NpgsqlCommand("show client_encoding", this);
                     //String clientEncoding = (String)commandEncoding.ExecuteScalar();
 
-                    if (connection_string_values[CONN_ENCODING].Equals("UNICODE"))
+                    if (ConnectStringValueToString(CONN_ENCODING).ToUpper() == "UNICODE") {
                         connection_encoding = Encoding.UTF8;
-
+                    }
 
                     Connector.ServerVersion = ServerVersion;
                     Connector.BackendProtocolVersion = BackendProtocolVersion;
@@ -461,6 +459,7 @@ namespace Npgsql
                 // Do a mini initialization in the state machine.
 
                 connection_state = ConnectionState.Open;
+
                 ServerVersion = Connector.ServerVersion;
                 BackendProtocolVersion = Connector.BackendProtocolVersion;
                 Encoding = Connector.Encoding;
@@ -469,10 +468,6 @@ namespace Npgsql
 
                 ProcessServerVersion();
                 _oidToNameMapping = NpgsqlTypesHelper.LoadTypesMapping(this);
-
-
-
-
             }
 
             catch(IOException e)
@@ -560,10 +555,13 @@ namespace Npgsql
             return new NpgsqlConnection(ConnectionString);
         }
 
+
+        //         
         // Private util methods
+        //
 
         /// <summary>
-        /// This method parses the connection string.
+        /// This method parses, cleans, and assigns the connection string.
         /// It translates it to a list of key-value pairs.
         /// Valid values are:
         /// Server             - Address/Name of Postgresql Server
@@ -575,43 +573,122 @@ namespace Npgsql
         /// MaxPoolSize - Max size of connection pool
         /// Encoding    - Encoding to be used
         /// Timeout     - Time to wait for connection open. In seconds.
+        /// The resulting cleaned connection string will have all key names
+        /// upper-cased for consistency and to help ensure proper operation
+        /// with the connection pool (which is keyed on connection string).
+        /// If any errors occur, the entire operation is aborted and the
+        /// connection state will be left unchanged.
         /// </summary>
-        private void ParseConnectionString()
+        private void ParseAndSetConnectionString(String CS)
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ParseConnectionString");
 
-            connection_string_values.Clear();
+            ListDictionary new_values = new ListDictionary(CaseInsensitiveComparer.Default);
+            StringBuilder CleanedConnectionString = new StringBuilder();
+            String[] pairs;
+            String[] keyvalue;
 
             // Get the key-value pairs delimited by CONN_DELIM
-            String[] pairs = connection_string.Split(new Char[] {CONN_DELIM});
+            pairs = CS.Split(new Char[] {CONN_DELIM});
 
-            String[] keyvalue;
             // Now, for each pair, get its key-value.
-            foreach(String s in pairs)
+            foreach(String sraw in pairs)
             {
-                // This happen when there are trailling/empty CONN_DELIMs
+                String s = sraw.Trim();
+                String Key = "", Value = "";
+
+                // This happens when there are trailing/empty CONN_DELIMs
                 // Just ignore them.
-                if (s == "")
+                if (s == "") {
                     continue;
+                }
 
-                keyvalue = s.Split(new Char[] {CONN_ASSIGN});
+                // Split this chunk on the first CONN_ASSIGN only.
+                keyvalue = s.Split(new Char[] {CONN_ASSIGN}, 2);
+
+                // Always trim things.
+                // Keys get uppercased for a numner of reasons
+                // (but NOT to enable case insensative comparisons).
+                Key = keyvalue[0].Trim().ToUpper();
+
+                // We don't expect keys this long, and it might be about to be put
+                // in an error message, so makes sure it is a sane length.
+                if (Key.Length > 20) {
+                    Key = Key.Substring(0, 20);
+                }
 
                 // Check if there is a key-value pair.
-                if (keyvalue.Length != 2)
-                    throw new ArgumentException(resman.GetString("Exception_WrongKeyVal"), connection_string);
+                if (keyvalue.Length != 2) {
+                    throw new ArgumentException(resman.GetString("Exception_WrongKeyVal"), Key);
+                }
 
-                // Shift the key to upper case, and substitute ODBC style keys
-                keyvalue[0] = keyvalue[0].ToUpper();
-                if (keyvalue[0] == ODBC_USERID)
-                    keyvalue[0] = CONN_USERID;
-                if (keyvalue[0] == ODBC_PASSWORD)
-                    keyvalue[0] = CONN_PASSWORD;
+                // Always trim things.
+                Value = keyvalue[1].Trim();
 
-                // Add the pair to the dictionary. The key is shifted to upper
-                // case for case insensitivity.
+                // Do some ODBC related substitions
+                if (Key == ODBC_USERID) {
+                    Key = CONN_USERID;
+                } else if (Key == ODBC_PASSWORD) {
+                    Key = CONN_PASSWORD;
+                }
+
+                NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, Key, Value);
+
+                // Add the pair to the dictionary..
+                new_values.Add(Key, Value);
+
+                // Add the pair to the cleaned list. The key is shifted to upper case.
+                CleanedConnectionString.AppendFormat("{0}{1}{2}{3}", Key, CONN_ASSIGN, Value, CONN_DELIM);
+            }
+
+            // Finally assign the real containers from our scratch ones.
+            connection_string_values = new_values;
+                                               connection_string = CleanedConnectionString.ToString();
+        }
+
+        /// <summary>
+        /// This method takes a version string as returned by SELECT VERSION() and returns
+        /// a valid version string ("7.2.2" for example).
+        /// This is only needed when running protocol version 2.
+        /// This does not do any validity checks.
+        /// </summary>
+        private string ExtractServerVersion (string VersionString)
+        {
+            Int32               Start = 0, End = 0;
+
+            // find the first digit and assume this is the start of the version number
+            for ( ; Start < VersionString.Length && ! char.IsDigit(VersionString[Start]) ; Start++);
+
+            End = Start;
+
+            // read until hitting whitespace, which should terminate the version number
+            for ( ; End < VersionString.Length && ! char.IsWhiteSpace(VersionString[End]) ; End++);
+
+            return VersionString.Substring(Start, End - Start + 1);
+        }
+
+        /// <summary>
+        /// This method takes a version string ("7.4.1" for example) and produces
+        /// the required integer version numbers (7, 4, and 1).
+        /// </summary>
+        private ServerVersion ParseServerVersion (string VersionString)
+        {
+            String[]        Parts;
+
+            Parts = VersionString.Split('.');
 
-                NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, keyvalue[0], keyvalue[1]);
-                connection_string_values.Add(keyvalue[0], keyvalue[1]);
+            if (Parts.Length != 3) {
+                throw new FormatException("Internal: Backend sent bad version string");
+            }
+
+            try {
+                return new ServerVersion(
+                    Convert.ToInt32(Parts[0]),
+                    Convert.ToInt32(Parts[1]),
+                    Convert.ToInt32(Parts[2])
+                );
+            } catch (Exception E) {
+                throw new FormatException("Internal: Backend sent bad version string", E);
             }
         }
 
@@ -623,21 +700,8 @@ namespace Npgsql
         private void ProcessServerVersion ()
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessServerVersion");
-            // FIXME: Do a better parsing of server version to avoid
-            // hardcode version numbers.
 
-            if (BackendProtocolVersion == ProtocolVersion.Version2)
-            {
-                // With protocol version 2, only 7.3 version supports prepare.
-                SupportsPrepare = (_serverVersion.IndexOf("PostgreSQL 7.3") != -1);
-            }
-            else
-            {
-                // 3.0+ version is set by ParameterStatus message.
-                // On protocol 3.0, 7.4 and above support it.
-                SupportsPrepare = (_serverVersion.IndexOf("7.4") != -1)
-                                  || (_serverVersion.IndexOf("7.5") != -1);
-            }
+            SupportsPrepare = ServerVersion.GreaterOrEqual(7, 3, 0);
         }
 
         internal Stream Stream {
@@ -830,7 +894,7 @@ namespace Npgsql
             }
         }
 
-        internal String ServerVersion {
+        internal ServerVersion ServerVersion {
             get
             {
                 return _serverVersion;
@@ -853,7 +917,7 @@ namespace Npgsql
 
         }
 
-        internal Int32 BackendProtocolVersion {
+        internal ProtocolVersion BackendProtocolVersion {
             get
             {
                 return _backendProtocolVersion;
@@ -878,6 +942,26 @@ namespace Npgsql
             }
         }
 
-    }
+        public Int32 ConnectStringValueToInt32(String Key)
+        {
+            if (! connection_string_values.Contains(Key)) {
+                return 0;
+            }
 
+            try {
+                return Convert.ToInt32(connection_string_values[Key]);
+            } catch (Exception E) {
+                throw new ArgumentException(resman.GetString("Exception_InvalidIntegerKeyVal"), Key, E);
+            }
+        }
+
+        public String ConnectStringValueToString(String Key)
+        {
+            if (! connection_string_values.Contains(Key)) {
+                return "";
+            }
+
+            return Convert.ToString(connection_string_values[Key]);
+        }
+    }
 }
index 78b5a14e8a6e637052e08c62a9096e3e61c50a9c..1c4e721278c7f8f16d4b884e523fe36a7b07b76e 100644 (file)
        <data name="Exception_WrongKeyVal">
                <value>key=value argument incorrect in ConnectionString</value>
        </data>
+       <data name="Exception_InvalidIntegerKeyVal">
+               <value>expecting key=[numeric] value in ConnectionString</value>
+       </data>
        <data name="Log_ConnectionStringValues">
                <value>Connection string option: {0} = {1}</value>
        </data>
index 9783b95e8595730a622f061eff6b97170093bb3e..18fa85fd6f98ce36f3ef06d6f8ac3e07bc7c7a75 100755 (executable)
@@ -47,12 +47,8 @@ namespace Npgsql
 
         private Stream _stream;
 
-        // This is information about the connection
-        // this connector is holding. For while only the server version is used.
-        // Change later for a more generic way to keep it. (Hashtable)
-        private String _serverVersion;
-
-        private Int32 _backendProtocolVersion;
+        private ProtocolVersion _backendProtocolVersion;
+        private ServerVersion _serverVersion;
 
         private Encoding _encoding;
 
@@ -89,7 +85,7 @@ namespace Npgsql
             }
         }
 
-        internal String ServerVersion
+        internal ServerVersion ServerVersion
         {
             get
             {
@@ -115,7 +111,7 @@ namespace Npgsql
             }
         }
 
-        internal Int32 BackendProtocolVersion
+        internal ProtocolVersion BackendProtocolVersion
         {
             get
             {
@@ -176,30 +172,6 @@ namespace Npgsql
         /// connector is to be moved to the PooledConnectors list.</value>
         internal int mShareCount;
 
-        /// <value>Private Buffer for the connection string property.</value>
-        /// <remarks>Compared to the requested connection string in the
-        /// ConnectorPool.RequestConnector() function.
-        /// Should not be modified if physical connection is open.</remarks>
-        private string mConnectString;
-
-        /// <summary>Used to connect to the database server. </summary>
-        public string ConnectString
-        {
-            get
-            {
-                return mConnectString;
-            }
-            set
-            {
-                if ( this.mOpen ) // uuuuugh, bad habits...
-                {
-                    throw new InvalidOperationException( "Connection strings "
-                                                      + " cannot be modified if connection is open." );
-                }
-                mConnectString = value;
-            }
-        }
-
         /// <value>Provides physical access to the server</value>
         // !!! to be fixed
         //private Npgsql.Socket Socket;
@@ -217,9 +189,8 @@ namespace Npgsql
         /// <summary>
         /// Construcor, initializes the Connector object.
         /// </summary>
-        internal Connector( string ConnectString, bool Shared )
+        internal Connector( bool Shared )
         {
-            ConnectString = ConnectString;
             Shared = Shared;
             Pooled = true;
         }
index 093f75c3096d44c7e5db5f4989316c8744d3c83d..0c9843c8c4183651a9701530ed60c48f80a890a9 100755 (executable)
@@ -109,9 +109,9 @@ namespace Npgsql
         }*/
 
 
-        internal Int32 GetPoolSize(String connectionString)
+        internal Int32 GetPoolSize(String PoolKey)
         {
-            ArrayList pool = (ArrayList)PooledConnectors[connectionString];
+            ArrayList pool = (ArrayList)PooledConnectors[PoolKey];
             if (pool == null)
                 return 0;
             else
@@ -124,12 +124,12 @@ namespace Npgsql
         /// Searches the shared and pooled connector lists for a
         /// matching connector object or creates a new one.
         /// </summary>
-        /// <param name="ConnectString">used to connect to the
-        /// database server</param>
+        /// <param name="PoolKey">A unique key (actually the connection string)
+        /// used to identify a connection</param>
         /// <param name="Shared">Allows multiple connections
         /// on a single connector. </param>
         /// <returns>A pooled connector object.</returns>
-        internal Npgsql.Connector RequestConnector (String connectionString,
+        internal Npgsql.Connector RequestConnector (String PoolKey,
                 Int32 maxPoolSize,
                 Int32 timeout,
                 Boolean shared )
@@ -162,12 +162,12 @@ namespace Npgsql
                 // (unused) connectors are beeing searched.
 
 
-                connectorPool = (ArrayList)PooledConnectors[connectionString];
+                connectorPool = (ArrayList)PooledConnectors[PoolKey];
 
                 if (connectorPool == null)
                 {
                     connectorPool = new ArrayList();
-                    PooledConnectors[connectionString] = connectorPool;
+                    PooledConnectors[PoolKey] = connectorPool;
                 }
 
 
@@ -182,7 +182,7 @@ namespace Npgsql
 
                 if (connectorPool.Count < maxPoolSize)
                 {
-                    connector = new Npgsql.Connector(connectionString, shared);
+                    connector = new Npgsql.Connector(shared);
 
                     connectorPool.Add(connector);
 
index f771c1fabdb08cda4201e984a7c635138d0d44cc..adf1d54c19f62f7a35c3a66ec727588570fbc82c 100644 (file)
@@ -40,7 +40,7 @@ namespace Npgsql
         // Logging related values
         private static readonly String CLASSNAME = "NpgsqlError";
 
-        private Int32 protocol_version;
+        private ProtocolVersion protocol_version;
         private String _severity = "";
         private String _code = "";
         private String _message = "";
@@ -187,7 +187,7 @@ namespace Npgsql
         {}
 
 
-        internal NpgsqlError(Int32 protocolVersion)
+        internal NpgsqlError(ProtocolVersion protocolVersion)
         {
             protocol_version = protocolVersion;
 
@@ -195,18 +195,22 @@ namespace Npgsql
 
         internal void ReadFromStream(Stream inputStream, Encoding encoding)
         {
-            if (protocol_version == ProtocolVersion.Version2)
-            {
+            switch (protocol_version) {
+            case ProtocolVersion.Version2 :
                 ReadFromStream_Ver_2(inputStream, encoding);
-            }
-            else
-            {
+                break;
+
+            case ProtocolVersion.Version3 :
                 ReadFromStream_Ver_3(inputStream, encoding);
+                break;
+
             }
         }
 
         private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
         {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
+
             String Raw;
             String[] Parts;
 
@@ -227,6 +231,8 @@ namespace Npgsql
 
         private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
         {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
+
             Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);
 
             //[TODO] Would this be the right way to do?
index be93fa3d908cf2bb00a0896cb3fc84dcde12afc4..0c37752c8be1b065789ca8bdf9cf5f11ba1413ee 100755 (executable)
@@ -26,6 +26,7 @@
 using System;
 using System.Text;
 using System.Collections;
+using System.Collections.Specialized;
 
 namespace Npgsql
 {
@@ -43,6 +44,8 @@ namespace Npgsql
         private        ArrayList                                                       _resultSets;
         private ArrayList                                                      _responses;
         private ArrayList             _notifications;
+        private ListDictionary        _parameters;
+        private NpgsqlBackEndKeyData  _backend_key_data;
 
         private NpgsqlRowDescription   _rd;
         private ArrayList                                                      _rows;
@@ -55,6 +58,8 @@ namespace Npgsql
             _resultSets = new ArrayList();
             _responses = new ArrayList();
             _notifications = new ArrayList();
+            _parameters = new ListDictionary(CaseInsensitiveComparer.Default);
+            _backend_key_data = null;
         }
 
         public void Reset()
@@ -64,9 +69,27 @@ namespace Npgsql
             _resultSets.Clear();
             _responses.Clear();
             _notifications.Clear();
+            _parameters.Clear();
+            _backend_key_data = null;
             _rd = null;
         }
 
+        public ArrayList ResultSets
+        {
+            get
+            {
+                return _resultSets;
+            }
+        }
+
+        public ArrayList CompletedResponses
+        {
+            get
+            {
+                return _responses;
+            }
+        }
+
         public ArrayList Errors
         {
             get
@@ -89,7 +112,22 @@ namespace Npgsql
             {
                 return _notifications;
             }
+        }
 
+        public ListDictionary Parameters
+        {
+            get
+            {
+                return _parameters;
+            }
+        }
+
+        public NpgsqlBackEndKeyData BackendKeyData
+        {
+            get
+            {
+                return _backend_key_data;
+            }
         }
 
         public void AddNotification(NpgsqlNotificationEventArgs data)
@@ -97,8 +135,6 @@ namespace Npgsql
             _notifications.Add(data);
         }
 
-
-
         public void AddCompletedResponse(String response)
         {
             if (_rd != null)
@@ -139,26 +175,14 @@ namespace Npgsql
         }
 
 
-        public void AddBackendKeydata(NpgsqlBackEndKeyData keydata)
+        public void SetBackendKeydata(NpgsqlBackEndKeyData keydata)
         {
-            _responses.Add(keydata);   //hack
+            _backend_key_data = keydata;
         }
 
-        public ArrayList GetResultSets()
+        public void AddParameterStatus(String Key, NpgsqlParameterStatus PS)
         {
-            return _resultSets;
+            _parameters[Key] = PS;
         }
-
-        public ArrayList GetCompletedResponses()
-        {
-            return _responses;
-        }
-
-        public NpgsqlBackEndKeyData GetBackEndKeyData()
-        {
-            return (NpgsqlBackEndKeyData)_responses[0];        //hack
-        }
-
-
     }
 }
index 2dcdc5c0bc62c9caead4b15f12ad5b34f54f81a2..b223053f8f85b8a352abd1221c65598af72a48e2 100755 (executable)
@@ -28,19 +28,21 @@ using System;
 namespace Npgsql
 {
     /// <summary>
-    /// Summary description for NpgsqlMessageTypes.
+    /// Class NpgsqlMessageTypes_Ver_2.
+    /// Defines PG frontend/backend protocol message types and parameters used in protocol version 2.
     /// </summary>
-    internal sealed class NpgsqlMessageTypes
+    internal sealed class NpgsqlMessageTypes_Ver_2
     {
-        private NpgsqlMessageTypes()
-        {
-            //
-            // TODO: Add constructor logic here
-            //
-        }
+        private NpgsqlMessageTypes_Ver_2()
+        {}
+
+        public const Char StartupPacket = ' ';
+        public const Char Terminate = 'X';
+
         public const Char AsciiRow = 'D';
-        public const Char AuthenticationRequest = 'R';
+        public const Char BinaryRow = 'B';
 
+        public const Char AuthenticationRequest = 'R';
         // specific Authentication request types
         public const Int32 AuthenticationOk = 0;
         public const Int32 AuthenticationKerberosV4 = 1;
@@ -51,8 +53,6 @@ namespace Npgsql
         public const Int32 AuthenticationSCMCredential = 6;
 
         public const Char BackendKeyData = 'K';
-        public const Char BinaryRow = 'B';
-        public const Char BindComplete = '2';
         public const Char CancelRequest = 'F';
         public const Char CompletedResponse = 'C';
         public const Char CopyDataRows = ' ';
@@ -70,16 +70,74 @@ namespace Npgsql
 
         public const Char NoticeResponse = 'N';
         public const Char NotificationResponse = 'A';
-        public const Char ParameterStatus = 'S';
-        public const Char ParseComplete = '1';
         public const Char PasswordPacket = ' ';
         public const Char Query = 'Q';
         public const Char ReadyForQuery = 'Z';
         public const Char RowDescription = 'T';
         public const Char SSLRequest = ' ';
+    }
+
+
+    /// <summary>
+    /// Class NpgsqlMessageTypes_Ver_3.
+    /// Defines PG frontend/backend protocol message types and parameters used in protocol version 3.
+    /// </summary>
+    internal sealed class NpgsqlMessageTypes_Ver_3
+    {
+        private NpgsqlMessageTypes_Ver_3()
+        {}
+
         public const Char StartupPacket = ' ';
+        public const Char Termination = 'X';
 
+        public const Char DataRow = 'D';
 
+        public const Char AuthenticationRequest = 'R';
+        // specific Authentication request types
+        public const Int32 AuthenticationOk = 0;
+        public const Int32 AuthenticationKerberosV4 = 1;
+        public const Int32 AuthenticationKerberosV5 = 2;
+        public const Int32 AuthenticationClearTextPassword = 3;
+        public const Int32 AuthenticationCryptPassword = 4;
+        public const Int32 AuthenticationMD5Password = 5;
+        public const Int32 AuthenticationSCMCredential = 6;
+
+        public const Char BackendKeyData = 'K';
+        public const Char CancelRequest = 'F';
+        public const Char CompletedResponse = 'C';
+        public const Char CopyDataRows = ' ';
+        public const Char CopyInResponse = 'G';
+        public const Char CopyOutResponse = 'H';
+        public const Char EmptyQueryResponse = 'I';
+        public const Char ErrorResponse = 'E';
+        public const Char FunctionCall = 'F';
+        public const Char FunctionCallResponse = 'V';
+
+        public const Char NoticeResponse = 'N';
+        public const Char NotificationResponse = 'A';
+        public const Char ParameterStatus = 'S';
+        public const Char PasswordPacket = ' ';
+        public const Char Query = 'Q';
+        public const Char ReadyForQuery = 'Z';
+        public const Char RowDescription = 'T';
+        public const Char SSLRequest = ' ';
+
+        // extended query frontend messages
+        public const Char Parse = 'P';
+        public const Char Bind = 'B';
+        public const Char Execute = 'E';
+        public const Char Describe = 'D';
+        public const Char Close = 'C';
+        public const Char Flush = 'H';
+        public const Char Sync = 'S';
+
+        // extended query backend messages
+        public const Char ParseComplete = '1';
+        public const Char BindComplete = '2';
+        public const Char PortalSuspended = 's';
+        public const Char ParameterDescription = 't';
+        public const Char NoData = 'n';
+        public const Char CloseComplete = '3';
 
     }
 }
index 349d756b50fb01973441404828183c96eb3331f0..5b9f498bead1726647aba94a15833f0d5eecf886 100755 (executable)
@@ -42,10 +42,10 @@ namespace Npgsql
         private static readonly String CLASSNAME = "NpgsqlPasswordPacket";
 
         private String password;
-        private Int32 protocolVersion;
+        private ProtocolVersion protocolVersion;
 
 
-        public NpgsqlPasswordPacket(String password, Int32 protocolVersion)
+        public NpgsqlPasswordPacket(String password, ProtocolVersion protocolVersion)
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
 
@@ -57,27 +57,28 @@ namespace Npgsql
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
 
-            if (protocolVersion == ProtocolVersion.Version2)
-            { // Write the size of the packet.
+            switch (protocolVersion) {
+            case ProtocolVersion.Version2 :
+                // Write the size of the packet.
                 // 4 + (passwordlength + 1) -> Int32 + NULL terminated string.
-                //output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length + 1))), 0, 4);
-
+                // output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length + 1))), 0, 4);
                 PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(password) + 1);
 
                 // Write String.
                 PGUtil.WriteString(password, outputStream, encoding);
-            }
-            else
-            {
+
+                break;
+
+            case ProtocolVersion.Version3 :
                 outputStream.WriteByte((Byte)'p');
                 PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(password) + 1);
 
                 // Write String.
                 PGUtil.WriteString(password, outputStream, encoding);
-            }
 
+                break;
 
+            }
         }
     }
-
 }
index 9cc7cefc62999987d65c974059056991ff6988da..7a241073a246780108ef959b524d71a5f74d5151 100755 (executable)
@@ -35,9 +35,9 @@ namespace Npgsql
     internal sealed class NpgsqlQuery
     {
         private String _commandText;
-        private Int32 _protocolVersion;
+        private ProtocolVersion _protocolVersion;
 
-        public NpgsqlQuery(String commandText, Int32 protocolVersion)
+        public NpgsqlQuery(String commandText, ProtocolVersion protocolVersion)
         {
             _commandText = commandText;
             _protocolVersion = protocolVersion;
@@ -52,21 +52,14 @@ namespace Npgsql
             // Write the byte 'Q' to identify a query message.
             outputStream.WriteByte((Byte)'Q');
 
-
-            if (_protocolVersion == ProtocolVersion.Version3)
+            if (_protocolVersion == ProtocolVersion.Version3) {
                 // Write message length. Int32 + string length + null terminator.
                 PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(_commandText) + 1);
-
-
-
+            }
 
             // Write the query. In this case it is the CommandText text.
             // It is a string terminated by a C NULL character.
-
             PGUtil.WriteString(_commandText, outputStream, encoding);
-
-
-
         }
     }
 }
index 9549d5bc86ea569ee4fcf75e944e729d5695c879..2ee5a7053048da715b5a5e59d1f7e337c3ac0829 100755 (executable)
@@ -67,82 +67,92 @@ namespace Npgsql
 
         private ArrayList   fields_index = new ArrayList();
 
-        private Int32 protocol_version;
+        private ProtocolVersion protocol_version;
 
-        public NpgsqlRowDescription(Int32 protocolVersion)
+        public NpgsqlRowDescription(ProtocolVersion protocolVersion)
         {
             protocol_version = protocolVersion;
         }
 
         public void ReadFromStream(Stream input_stream, Encoding encoding)
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream");
+            switch (protocol_version) {
+            case ProtocolVersion.Version2 :
+                ReadFromStream_Ver_2(input_stream, encoding);
+                break;
 
+            case ProtocolVersion.Version3 :
+                ReadFromStream_Ver_3(input_stream, encoding);
+                break;
 
-            if (protocol_version == ProtocolVersion.Version2)
-            {
-                Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4
+            }
+        }
 
-                // Read the number of fields.
-                input_stream.Read(input_buffer, 0, 2);
-                Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));
+        public void ReadFromStream_Ver_2(Stream input_stream, Encoding encoding)
+        {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
 
+            Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4
 
-                // Temporary FieldData object to get data from stream and put in array.
-                NpgsqlRowDescriptionFieldData fd;
+            // Read the number of fields.
+            input_stream.Read(input_buffer, 0, 2);
+            Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));
 
-                // Now, iterate through each field getting its data.
-                for (Int16 i = 0; i < num_fields; i++)
-                {
-                    fd = new NpgsqlRowDescriptionFieldData();
 
-                    // Set field name.
-                    fd.name = PGUtil.ReadString(input_stream, encoding);
+            // Temporary FieldData object to get data from stream and put in array.
+            NpgsqlRowDescriptionFieldData fd;
 
-                    // Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
-                    input_stream.Read(input_buffer, 0, 4 + 2 + 4);
+            // Now, iterate through each field getting its data.
+            for (Int16 i = 0; i < num_fields; i++)
+            {
+                fd = new NpgsqlRowDescriptionFieldData();
 
-                    fd.type_oid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
-                    fd.type_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
-                    fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
+                // Set field name.
+                fd.name = PGUtil.ReadString(input_stream, encoding);
 
-                    // Add field data to array.
-                    fields_data.Add(fd);
+                // Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
+                input_stream.Read(input_buffer, 0, 4 + 2 + 4);
 
-                    fields_index.Add(fd.name);
-                }
-            }
-            else
-            {
-                Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2
+                fd.type_oid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
+                fd.type_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
+                fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
+
+                // Add field data to array.
+                fields_data.Add(fd);
 
-                // Read the length of message.
-                // [TODO] Any use for now?
-                PGUtil.ReadInt32(input_stream, input_buffer);
-                Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);
+                fields_index.Add(fd.name);
+            }
+        }
 
-                // Temporary FieldData object to get data from stream and put in array.
-                NpgsqlRowDescriptionFieldData fd;
+        public void ReadFromStream_Ver_3(Stream input_stream, Encoding encoding)
+        {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
 
-                for (Int16 i = 0; i < num_fields; i++)
-                {
-                    fd = new NpgsqlRowDescriptionFieldData();
-
-                    fd.name = PGUtil.ReadString(input_stream, encoding);
-                    fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
-                    fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
-                    fd.type_oid = PGUtil.ReadInt32(input_stream, input_buffer);
-                    fd.type_size = PGUtil.ReadInt16(input_stream, input_buffer);
-                    fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
-                    fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
-
-                    fields_data.Add(fd);
-                    fields_index.Add(fd.name);
-                }
+            Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2
 
-            }
+            // Read the length of message.
+            // [TODO] Any use for now?
+            PGUtil.ReadInt32(input_stream, input_buffer);
+            Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);
 
+            // Temporary FieldData object to get data from stream and put in array.
+            NpgsqlRowDescriptionFieldData fd;
 
+            for (Int16 i = 0; i < num_fields; i++)
+            {
+                fd = new NpgsqlRowDescriptionFieldData();
+
+                fd.name = PGUtil.ReadString(input_stream, encoding);
+                fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
+                fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
+                fd.type_oid = PGUtil.ReadInt32(input_stream, input_buffer);
+                fd.type_size = PGUtil.ReadInt16(input_stream, input_buffer);
+                fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
+                fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
+
+                fields_data.Add(fd);
+                fields_index.Add(fd.name);
+            }
         }
 
         public NpgsqlRowDescriptionFieldData this[Int32 index]
@@ -151,7 +161,6 @@ namespace Npgsql
             {
                 return (NpgsqlRowDescriptionFieldData)fields_data[index];
             }
-
         }
 
         public Int16 NumFields
@@ -177,7 +186,6 @@ namespace Npgsql
             }
 
             return -1;
-
         }
 
     }
index cc30c7ed438513a977ff2079571426310ccafd48..47ef00f35a2c4a8c14b7b408127dd7026aa30776 100755 (executable)
@@ -39,13 +39,12 @@ namespace Npgsql
     ///
     internal sealed class NpgsqlStartupPacket
     {
-
         // Logging related values
         private static readonly String CLASSNAME = "NpgsqlStartupPacket";
 
         // Private fields.
         private Int32 packet_size;
-        private Int32 protocol_version;
+        private ProtocolVersion protocol_version;
         private String database_name;
         private String user_name;
         private String arguments;
@@ -53,8 +52,7 @@ namespace Npgsql
         private String optional_tty;
 
         public NpgsqlStartupPacket(Int32 packet_size,
-                                   Int32 protocol_version_major,
-                                   Int32 protocol_version_minor,
+                                   ProtocolVersion protocol_version,
                                    String database_name,
                                    String user_name,
                                    String arguments,
@@ -69,7 +67,8 @@ namespace Npgsql
             // know what to send.
 
             this.packet_size = packet_size;
-            this.protocol_version = (protocol_version_major<<16) | protocol_version_minor;
+            this.protocol_version = protocol_version;
+
             this.database_name = database_name;
             this.user_name = user_name;
             this.arguments = arguments;
@@ -81,73 +80,76 @@ namespace Npgsql
 
         public void WriteToStream(Stream output_stream, Encoding encoding)
         {
-
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
 
-            // [FIXME] Need exception handling ?
-
-            if (protocol_version == ProtocolVersion.Version2) // Protocol 2.0
-            {
-
-                // Packet length = 296
-                output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.packet_size)), 0, 4);
-
-                // Protocol version = 2.0
-                output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.protocol_version)), 0, 4);
+            switch (protocol_version) {
+            case ProtocolVersion.Version2 :
+                WriteToStream_Ver_2(output_stream, encoding);
+                break;
 
-                // Database name.
-                PGUtil.WriteLimString(this.database_name, 64, output_stream, encoding);
+            case ProtocolVersion.Version3 :
+                WriteToStream_Ver_3(output_stream, encoding);
+                break;
 
-                // User name.
-                PGUtil.WriteLimString(this.user_name, 32, output_stream, encoding);
+            }
+        }
 
-                // Arguments.
-                PGUtil.WriteLimString(this.arguments, 64, output_stream, encoding);
 
-                // Unused.
-                PGUtil.WriteLimString(this.unused, 64, output_stream, encoding);
+        private void WriteToStream_Ver_2(Stream output_stream, Encoding encoding)
+                               {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_2");
 
-                // Optional tty.
-                PGUtil.WriteLimString(this.optional_tty, 64, output_stream, encoding);
-                output_stream.Flush();
+            // Packet length = 296
+            output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.packet_size)), 0, 4);
 
-            }
+            output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(PGUtil.ConvertProtocolVersion(this.protocol_version))), 0, 4);
 
-            if (protocol_version >= ProtocolVersion.Version3) // Protocol 3+
-            {
-                PGUtil.WriteInt32(output_stream, 4 + 4 + 5 + (encoding.GetByteCount(user_name) + 1) + 9 + (encoding.GetByteCount(database_name) + 1) + 10 + 4 + 1);
+            // Database name.
+            PGUtil.WriteLimString(this.database_name, 64, output_stream, encoding);
 
-                // Protocol version = 3.0
+            // User name.
+            PGUtil.WriteLimString(this.user_name, 32, output_stream, encoding);
 
-                PGUtil.WriteInt32(output_stream, this.protocol_version);
+            // Arguments.
+            PGUtil.WriteLimString(this.arguments, 64, output_stream, encoding);
 
-                // User name.
+            // Unused.
+            PGUtil.WriteLimString(this.unused, 64, output_stream, encoding);
 
-                PGUtil.WriteString("user", output_stream, encoding);
+            // Optional tty.
+            PGUtil.WriteLimString(this.optional_tty, 64, output_stream, encoding);
+            output_stream.Flush();
+        }
 
-                // User name.
-                PGUtil.WriteString(user_name, output_stream, encoding);
 
-                // Database name.
-                PGUtil.WriteString("database", output_stream, encoding);
+        private void WriteToStream_Ver_3(Stream output_stream, Encoding encoding)
+        {
+            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_3");
 
-                // Database name.
-                PGUtil.WriteString(database_name, output_stream, encoding);
+            PGUtil.WriteInt32(output_stream, 4 + 4 + 5 + (encoding.GetByteCount(user_name) + 1) + 9 + (encoding.GetByteCount(database_name) + 1) + 10 + 4 + 1);
 
-                // DateStyle.
-                PGUtil.WriteString("DateStyle", output_stream, encoding);
+            PGUtil.WriteInt32(output_stream, Npgsql.PGUtil.ConvertProtocolVersion(this.protocol_version));
 
-                // DateStyle.
-                PGUtil.WriteString("ISO", output_stream, encoding);
+            // User name.
+            PGUtil.WriteString("user", output_stream, encoding);
 
-                output_stream.WriteByte(0);
-                output_stream.Flush();
+            // User name.
+            PGUtil.WriteString(user_name, output_stream, encoding);
 
-            }
+            // Database name.
+            PGUtil.WriteString("database", output_stream, encoding);
 
+            // Database name.
+            PGUtil.WriteString(database_name, output_stream, encoding);
 
+            // DateStyle.
+            PGUtil.WriteString("DateStyle", output_stream, encoding);
 
+            // DateStyle.
+            PGUtil.WriteString("ISO", output_stream, encoding);
 
+            output_stream.WriteByte(0);
+            output_stream.Flush();
         }
     }
 }
index 71093dac8c6180b7b4ca335ae62362d15570e88e..01689c75121d3555e8a5927fb0fface3da33bb01 100755 (executable)
@@ -135,8 +135,7 @@ namespace Npgsql
 
         protected virtual void ProcessBackendResponses( NpgsqlConnection context )
         {
-            switch (context.BackendProtocolVersion)
-            {
+            switch (context.BackendProtocolVersion) {
             case ProtocolVersion.Version2 :
                 ProcessBackendResponses_Ver_2(context);
                 break;
@@ -172,7 +171,7 @@ namespace Npgsql
                 // Check the first Byte of response.
                 switch ( stream.ReadByte() )
                 {
-                case NpgsqlMessageTypes.ErrorResponse :
+                case NpgsqlMessageTypes_Ver_2.ErrorResponse :
 
                     {
                         NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
@@ -197,7 +196,7 @@ namespace Npgsql
                     break;
 
 
-                case NpgsqlMessageTypes.AuthenticationRequest :
+                case NpgsqlMessageTypes_Ver_2.AuthenticationRequest :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
 
@@ -205,14 +204,14 @@ namespace Npgsql
 
                     authType = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationOk )
+                    if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationOk )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
 
                         break;
                     }
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationClearTextPassword )
+                    if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationClearTextPassword )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
 
@@ -225,7 +224,7 @@ namespace Npgsql
                     }
 
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationMD5Password )
+                    if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationMD5Password )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                         // Now do the "MD5-Thing"
@@ -287,7 +286,7 @@ namespace Npgsql
                     mediator.Errors.Add(String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType));
                     return;
 
-                case NpgsqlMessageTypes.RowDescription:
+                case NpgsqlMessageTypes_Ver_2.RowDescription:
                     // This is the RowDescription message.
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
                     rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
@@ -303,7 +302,7 @@ namespace Npgsql
                     // Now wait for the AsciiRow messages.
                     break;
 
-                case NpgsqlMessageTypes.AsciiRow:
+                case NpgsqlMessageTypes_Ver_2.AsciiRow:
 
                     // This is the AsciiRow message.
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");
@@ -318,7 +317,7 @@ namespace Npgsql
                     // Now wait for CompletedResponse message.
                     break;
 
-                case NpgsqlMessageTypes.BinaryRow:
+                case NpgsqlMessageTypes_Ver_2.BinaryRow:
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BinaryRow");
                     NpgsqlBinaryRow binaryRow = new NpgsqlBinaryRow(rd);
@@ -328,27 +327,27 @@ namespace Npgsql
 
                     break;
 
-                case NpgsqlMessageTypes.ReadyForQuery :
+                case NpgsqlMessageTypes_Ver_2.ReadyForQuery :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
                     readyForQuery = true;
                     ChangeState( context, NpgsqlReadyState.Instance );
                     break;
 
-                case NpgsqlMessageTypes.BackendKeyData :
+                case NpgsqlMessageTypes_Ver_2.BackendKeyData :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
                     // BackendKeyData message.
                     NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
                     backend_keydata.ReadFromStream(stream);
-                    mediator.AddBackendKeydata(backend_keydata);
+                    mediator.SetBackendKeydata(backend_keydata);
 
 
                     // Wait for ReadForQuery message
                     break;
                     ;
 
-                case NpgsqlMessageTypes.NoticeResponse :
+                case NpgsqlMessageTypes_Ver_2.NoticeResponse :
 
                     {
                         NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
@@ -362,7 +361,7 @@ namespace Npgsql
                     // Wait for ReadForQuery message
                     break;
 
-                case NpgsqlMessageTypes.CompletedResponse :
+                case NpgsqlMessageTypes_Ver_2.CompletedResponse :
                     // This is the CompletedResponse message.
                     // Get the string returned.
 
@@ -377,7 +376,7 @@ namespace Npgsql
                     // Now wait for ReadyForQuery message.
                     break;
 
-                case NpgsqlMessageTypes.CursorResponse :
+                case NpgsqlMessageTypes_Ver_2.CursorResponse :
                     // This is the cursor response message.
                     // It is followed by a C NULL terminated string with the name of
                     // the cursor in a FETCH case or 'blank' otherwise.
@@ -389,21 +388,7 @@ namespace Npgsql
                     // Continue waiting for ReadyForQuery message.
                     break;
 
-                case NpgsqlMessageTypes.ParseComplete :
-                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
-                    // Just read up the message length.
-                    PGUtil.ReadInt32(stream, new Byte[4]);
-                    readyForQuery = true;
-                    break;
-
-                case NpgsqlMessageTypes.BindComplete :
-                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
-                    // Just read up the message length.
-                    PGUtil.ReadInt32(stream, new Byte[4]);
-                    readyForQuery = true;
-                    break;
-
-                case NpgsqlMessageTypes.EmptyQueryResponse :
+                case NpgsqlMessageTypes_Ver_2.EmptyQueryResponse :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                     // This is the EmptyQueryResponse.
                     // [FIXME] Just ignore it this way?
@@ -412,7 +397,7 @@ namespace Npgsql
                     PGUtil.ReadString(stream, context.Encoding);
                     break;
 
-                case NpgsqlMessageTypes.NotificationResponse  :
+                case NpgsqlMessageTypes_Ver_2.NotificationResponse  :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");
 
@@ -425,18 +410,17 @@ namespace Npgsql
                     // Wait for ReadForQuery message
                     break;
 
-                case NpgsqlMessageTypes.ParameterStatus :
-                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
-                    NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus();
-                    parameterStatus.ReadFromStream(stream, context.Encoding);
+                default :
+                    // This could mean a number of things
+                    //   We've gotten out of sync with the backend?
+                    //   We need to implement this type?
+                    //   Backend has gone insane?
+                    // FIXME
+                    // what exception should we really throw here?
+                    throw new NotSupportedException("Backend sent unrecognized response type");
 
-                    NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue);
-                    if (parameterStatus.Parameter == "server_version")
-                        context.ServerVersion = parameterStatus.ParameterValue;
-                    break;
                 }
             }
-
         }
 
         protected virtual void ProcessBackendResponses_Ver_3( NpgsqlConnection context )
@@ -465,7 +449,7 @@ namespace Npgsql
                 // Check the first Byte of response.
                 switch ( stream.ReadByte() )
                 {
-                case NpgsqlMessageTypes.ErrorResponse :
+                case NpgsqlMessageTypes_Ver_3.ErrorResponse :
 
                     {
                         NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
@@ -490,7 +474,7 @@ namespace Npgsql
                     break;
 
 
-                case NpgsqlMessageTypes.AuthenticationRequest :
+                case NpgsqlMessageTypes_Ver_3.AuthenticationRequest :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
 
@@ -499,14 +483,14 @@ namespace Npgsql
 
                     authType = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationOk )
+                    if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationOk )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
 
                         break;
                     }
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationClearTextPassword )
+                    if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationClearTextPassword )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
 
@@ -519,7 +503,7 @@ namespace Npgsql
                     }
 
 
-                    if ( authType == NpgsqlMessageTypes.AuthenticationMD5Password )
+                    if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationMD5Password )
                     {
                         NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                         // Now do the "MD5-Thing"
@@ -581,7 +565,7 @@ namespace Npgsql
                     mediator.Errors.Add(String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType));
                     return;
 
-                case NpgsqlMessageTypes.RowDescription:
+                case NpgsqlMessageTypes_Ver_3.RowDescription:
                     // This is the RowDescription message.
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
                     rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
@@ -597,10 +581,10 @@ namespace Npgsql
                     // Now wait for the AsciiRow messages.
                     break;
 
-                case NpgsqlMessageTypes.AsciiRow:
+                case NpgsqlMessageTypes_Ver_3.DataRow:
 
                     // This is the AsciiRow message.
-                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");
+                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
                     NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(rd, context.OidToNameMapping, context.BackendProtocolVersion);
                     asciiRow.ReadFromStream(stream, context.Encoding);
 
@@ -612,7 +596,7 @@ namespace Npgsql
                     // Now wait for CompletedResponse message.
                     break;
 
-                case NpgsqlMessageTypes.ReadyForQuery :
+                case NpgsqlMessageTypes_Ver_3.ReadyForQuery :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
 
@@ -629,19 +613,19 @@ namespace Npgsql
 
                     break;
 
-                case NpgsqlMessageTypes.BackendKeyData :
+                case NpgsqlMessageTypes_Ver_3.BackendKeyData :
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
                     // BackendKeyData message.
                     NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
                     backend_keydata.ReadFromStream(stream);
-                    mediator.AddBackendKeydata(backend_keydata);
+                    mediator.SetBackendKeydata(backend_keydata);
 
 
                     // Wait for ReadForQuery message
                     break;
 
-                case NpgsqlMessageTypes.NoticeResponse :
+                case NpgsqlMessageTypes_Ver_3.NoticeResponse :
 
                     // Notices and errors are identical except that we
                     // just throw notices away completely ignored.
@@ -657,7 +641,7 @@ namespace Npgsql
                     // Wait for ReadForQuery message
                     break;
 
-                case NpgsqlMessageTypes.CompletedResponse :
+                case NpgsqlMessageTypes_Ver_3.CompletedResponse :
                     // This is the CompletedResponse message.
                     // Get the string returned.
 
@@ -671,33 +655,21 @@ namespace Npgsql
 
                     break;
 
-                case NpgsqlMessageTypes.CursorResponse :
-                    // This is the cursor response message.
-                    // It is followed by a C NULL terminated string with the name of
-                    // the cursor in a FETCH case or 'blank' otherwise.
-                    // In this case it should be always 'blank'.
-                    // [FIXME] Get another name for this function.
-                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");
-
-                    PGUtil.ReadString(stream, context.Encoding);
-                    // Continue waiting for ReadyForQuery message.
-                    break;
-
-                case NpgsqlMessageTypes.ParseComplete :
+                case NpgsqlMessageTypes_Ver_3.ParseComplete :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
                     // Just read up the message length.
                     PGUtil.ReadInt32(stream, Buff);
                     readyForQuery = true;
                     break;
 
-                case NpgsqlMessageTypes.BindComplete :
+                case NpgsqlMessageTypes_Ver_3.BindComplete :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
                     // Just read up the message length.
                     PGUtil.ReadInt32(stream, Buff);
                     readyForQuery = true;
                     break;
 
-                case NpgsqlMessageTypes.EmptyQueryResponse :
+                case NpgsqlMessageTypes_Ver_3.EmptyQueryResponse :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                     // This is the EmptyQueryResponse.
                     // [FIXME] Just ignore it this way?
@@ -706,8 +678,7 @@ namespace Npgsql
                     PGUtil.ReadInt32(stream, Buff);
                     break;
 
-                case NpgsqlMessageTypes.NotificationResponse  :
-
+                case NpgsqlMessageTypes_Ver_3.NotificationResponse  :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");
 
                     // Eat the length
@@ -724,15 +695,34 @@ namespace Npgsql
                     // Wait for ReadForQuery message
                     break;
 
-                case NpgsqlMessageTypes.ParameterStatus :
+                case NpgsqlMessageTypes_Ver_3.ParameterStatus :
                     NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
                     NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus();
                     parameterStatus.ReadFromStream(stream, context.Encoding);
 
                     NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue);
-                    if (parameterStatus.Parameter == "server_version")
-                        context.ServerVersion = parameterStatus.ParameterValue;
+
+                    mediator.AddParameterStatus(parameterStatus.Parameter, parameterStatus);
+
+                    if (parameterStatus.Parameter == "server_version") {
+                        // Add this one under our own name so that if the parameter name
+                        // changes in a future backend version, we can handle it here in the 
+                        // protocol handler and leave everybody else put of it.
+                        mediator.AddParameterStatus("__npgsql_server_version", parameterStatus);
+//                        context.ServerVersionString = parameterStatus.ParameterValue;
+                    }
+
                     break;
+
+                default :
+                    // This could mean a number of things
+                    //   We've gotten out of sync with the backend?
+                    //   We need to implement this type?
+                    //   Backend has gone insane?
+                    // FIXME
+                    // what exception should we really throw here?
+                    throw new NotSupportedException("Backend sent unrecognized response type");
+
                 }
             }
         }
index 2c4823a5d30a045208c66f765ce4c0a456f52c61..8d6e290c6792b93715df7672e2a80e4b5bc88f1d 100755 (executable)
@@ -34,21 +34,60 @@ using System.Resources;
 namespace Npgsql
 {
 
+    /// <summary>
+    /// Represent the frontend/backend protocol version in use.
+    /// </summary>
+    internal enum ProtocolVersion
+    {
+        Version2,
+        Version3
+    }
 
-    internal struct ProtocolVersion
+    /// <summary>
+    /// Represent the backend server version.
+    /// </summary>
+    internal class ServerVersion
     {
-        public const Int32 Version2 = 131072;
-        public const Int32 Version3 = 196608;
+        public static readonly Int32 ProtocolVersion2 = 2 << 16; // 131072
+        public static readonly Int32 ProtocolVersion3 = 3 << 16; // 196608
+
+        public String  Raw;
+        public Int32   Major;
+        public Int32   Minor;
+        public Int32   Patch;
+
+        private ServerVersion()
+        {}
+
+        public ServerVersion(Int32 Major, Int32 Minor, Int32 Patch)
+        {
+            this.Raw = string.Format("{0}.{1}.{2}", Major, Minor, Patch);
+            this.Major = Major;
+            this.Minor = Minor;
+            this.Patch = Patch;
+        }
+
+        public bool GreaterOrEqual(Int32 Major, Int32 Minor, Int32 Patch)
+        {
+            return
+                (this.Major > Major) ||
+                (this.Major == Major && this.Minor > Minor) ||
+                (this.Major == Major && this.Minor == Minor && this.Patch >= Patch);
+        }
+
+        public new String ToString()
+        {
+            return Raw;
+        }
     }
 
-internal enum FormatCode:
+    internal enum FormatCode:
     short
     {
         Text = 0,
         Binary = 1
     }
 
-
     ///<summary>
     /// This class provides many util methods to handle
     /// reading and writing of PostgreSQL protocol messages.
@@ -57,7 +96,6 @@ internal enum FormatCode:
     /// Should it be abstract or with a private constructor to prevent
     /// creating instances?
 
-    //
     internal sealed class PGUtil
     {
 
@@ -65,6 +103,28 @@ internal enum FormatCode:
         private static readonly String CLASSNAME = "PGUtil";
         private static ResourceManager resman = new ResourceManager(typeof(PGUtil));
 
+        ///<summary>
+        /// This method takes a ProtocolVersion and returns an integer
+        /// version number that the Postgres backend will recognize in a
+        /// startup packet.
+        /// </summary>
+
+        public static Int32 ConvertProtocolVersion(ProtocolVersion Ver)
+        {
+            switch (Ver) {
+            case ProtocolVersion.Version2 :
+                return ServerVersion.ProtocolVersion2;
+
+            case ProtocolVersion.Version3 :
+                return ServerVersion.ProtocolVersion3;
+
+            }
+
+            // CHECKME
+            // should we throw?
+            return 0;
+        }
+
         ///<summary>
         /// This method gets a C NULL terminated string from the network stream.
         /// It keeps reading a byte in each time until a NULL byte is returned.