2004-01-17 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
authorFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>
Sat, 17 Jan 2004 17:39:10 +0000 (17:39 -0000)
committerFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>
Sat, 17 Jan 2004 17:39:10 +0000 (17:39 -0000)
* Added initial support for connection pool.
* Fixed Connection testsuite for nested transactions with connection pool.
* Removed some finalizers which were causing segmentation fault.

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

mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
mcs/class/Npgsql/Npgsql/NpgsqlState.cs
mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
mcs/class/Npgsql/Test/ConnectionTests.cs

index 331e17e7aaaa8347b82038606fe4c53761cbafd5..ced6457575bdb7c153b74654638db6be0194c4d6 100755 (executable)
@@ -26,6 +26,7 @@ using System.IO;
 using System.Net;
 using System.Net.Sockets;
 using System.Resources;
+using System.Collections;
 using Mono.Security.Protocol.Tls;
 
 namespace Npgsql
@@ -56,7 +57,6 @@ namespace Npgsql
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
 
-            // Create a new TLS Session
             try
             {
                 TcpClient tcpc = new TcpClient(context.ServerName, Int32.Parse(context.ServerPort));
@@ -73,16 +73,20 @@ namespace Npgsql
                         stream = new SslClientStream(tcpc.GetStream(), context.ServerName, true, Mono.Security.Protocol.Tls.SecurityProtocolType.Default);
                     }
                 }
-                context.Stream = stream;
                 
+                context.Connector.Stream = stream;
+                
+                               
             }
             catch (TlsException e)
             {
                 throw new NpgsqlException(e.ToString());
             }
+            
             NpgsqlEventLog.LogMsg(resman, "Log_ConnectedTo", LogLevel.Normal, context.ServerName, context.ServerPort);
             ChangeState(context, NpgsqlConnectedState.Instance);
             context.Startup();
+            
         }
 
     }
index effb75b64ec0e09821e7336233de9b53043e78dd..99694ea3dc423fe0a5a48e6d364b8df8788ea90a 100755 (executable)
@@ -104,10 +104,10 @@ namespace Npgsql
         /// <summary>
         /// Finalizer for <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
         /// </summary>
-        ~NpgsqlCommand ()
+        /*~NpgsqlCommand ()
         {
             Dispose(false);
-        }
+        }*/
 
         // Public properties.
         /// <summary>
@@ -471,7 +471,7 @@ namespace Npgsql
 
             CheckNotification();
 
-
+            
             // Get the resultsets and create a Datareader with them.
             return new NpgsqlDataReader(connection.Mediator.GetResultSets(), connection.Mediator.GetCompletedResponses(), connection, cb);
         }
@@ -616,9 +616,12 @@ namespace Npgsql
         /// </summary>
         protected override void Dispose (bool disposing)
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
+            
             if (disposing)
             {
+                // Only if explicitly calling Close or dispose we still have access to 
+                // managed resources.
+                NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
                 if (connection != null)
                 {
                     connection.Dispose();
index fa6492a902161241844c748f71fdd168420f321a..f36502985b37c76d0ac6426326a73143b7ce2cff 100644 (file)
@@ -242,10 +242,10 @@ namespace Npgsql
             }
         }
 
-        ~NpgsqlCommandBuilder ()
+        /*~NpgsqlCommandBuilder ()
         {
             Dispose(false);
-        }
+        }*/
 
     }
 
index 2c14efa8acaca38e85aa18912caff5c59b8e21d2..2abc2d740a099ff09934138dec43d23c2bae3db4 100755 (executable)
@@ -50,7 +50,7 @@ namespace Npgsql
     /// PostgreSQL server.
     /// </summary>
     [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))]
-    public sealed class NpgsqlConnection : Component, IDbConnection, IDisposable
+    public sealed class NpgsqlConnection : Component, IDbConnection
     {
         //Changed the Name of this event because events usually don't start with 'On' in the .Net-Framework
         // (but their handlers do ;-)
@@ -84,6 +84,10 @@ namespace Npgsql
         // These are for ODBC connection string compatibility
         internal readonly String ODBC_USERID   = "UID";
         internal readonly String ODBC_PASSWORD = "PWD";
+        
+        // These are for the connection pool
+        internal readonly String MIN_POOL_SIZE = "MINPOOLSIZE";
+        internal readonly String MAX_POOL_SIZE = "MAXPOOLSIZE";
 
         // Values for possible CancelRequest messages.
         private NpgsqlBackEndKeyData backend_keydata;
@@ -99,6 +103,8 @@ namespace Npgsql
 
         private Stream                                 stream;
         
+        private Connector               _connector;
+        
         private Encoding                               connection_encoding;
 
         private Boolean                                        _supportsPrepare = false;
@@ -144,14 +150,7 @@ namespace Npgsql
                 ParseConnectionString();
         }
 
-        /// <summary>
-        /// Finalizer for NpgsqlConnection
-        /// </summary>
-        ~NpgsqlConnection ()
-        {
-            Dispose(false);
-        }
-
+        
         /// <summary>
         /// Gets or sets the string used to open a SQL Server database.
         /// </summary>
@@ -355,78 +354,101 @@ namespace Npgsql
                 connection_string_values[CONN_PORT] = PG_PORT;
             if (connection_string_values[SSL_ENABLED] == null)
                 connection_string_values[SSL_ENABLED] = "no";
-
+            
+            if (connection_string_values[MIN_POOL_SIZE] == null)
+                connection_string_values[MIN_POOL_SIZE] = "1";
+            if (connection_string_values[MAX_POOL_SIZE] == null)
+                connection_string_values[MAX_POOL_SIZE] = "-1";
+                
             try
             {
-
+            
                 // Check if the connection is already open.
                 if (connection_state == ConnectionState.Open)
                     throw new NpgsqlException(resman.GetString("Exception_ConnOpen"));
 
-
-                // Try first connect using the 3.0 protocol...
-                CurrentState.Open(this);
-
-
-                // Check if there were any errors.
-                if (_mediator.Errors.Count > 0)
+                lock(ConnectorPool.ConnectorPoolMgr)
                 {
-                    // Check if there is an error of protocol not supported...
-                    // As the message can be localized, just check the initial unlocalized part of the
-                    // message. If it is an error other than protocol error, when connecting using
-                    // version 2.0 we shall catch the error again.
-                    if (((String)_mediator.Errors[0]).StartsWith("FATAL"))
-                    {
-                        // Try using the 2.0 protocol.
-                        _mediator.Reset();
-                        CurrentState = NpgsqlClosedState.Instance;
-                        BackendProtocolVersion = ProtocolVersion.Version2;
-                        CurrentState.Open(this);
-                    }
-
-                    // Keep checking for errors...
-                    if(_mediator.Errors.Count > 0)
+                    Connector = ConnectorPool.ConnectorPoolMgr.RequestConnector(ConnectionString, false);
+                    Connector.InUse = true;
+                }
+                
+                if (!Connector.IsInitialized)
+                {
+                    
+                    // Reset state to initialize new connector in pool.
+                    CurrentState = NpgsqlClosedState.Instance;
+
+                    // Try first connect using the 3.0 protocol...
+                    CurrentState.Open(this);
+                    
+                    // Change the state of connection to open.
+                    connection_state = ConnectionState.Open;
+        
+                    // Check if there were any errors.
+                    if (_mediator.Errors.Count > 0)
                     {
-                        StringWriter sw = new StringWriter();
-                        sw.WriteLine(resman.GetString("Exception_OpenError"));
-                        uint i = 1;
-                        foreach(string error in _mediator.Errors)
+                        // Check if there is an error of protocol not supported...
+                        // As the message can be localized, just check the initial unlocalized part of the
+                        // message. If it is an error other than protocol error, when connecting using
+                        // version 2.0 we shall catch the error again.
+                        if (((String)_mediator.Errors[0]).StartsWith("FATAL"))
                         {
-                            sw.WriteLine("{0}. {1}", i++, error);
+                            // Try using the 2.0 protocol.
+                            _mediator.Reset();
+                            CurrentState = NpgsqlClosedState.Instance;
+                            BackendProtocolVersion = ProtocolVersion.Version2;
+                            CurrentState.Open(this);
+                        }
+    
+                        // Keep checking for errors...
+                        if(_mediator.Errors.Count > 0)
+                        {
+                            StringWriter sw = new StringWriter();
+                            sw.WriteLine(resman.GetString("Exception_OpenError"));
+                            uint i = 1;
+                            foreach(string error in _mediator.Errors)
+                            {
+                                sw.WriteLine("{0}. {1}", i++, error);
+                            }
+                            CurrentState = NpgsqlClosedState.Instance;
+                            _mediator.Reset();
+                            throw new NpgsqlException(sw.ToString());
                         }
-                        CurrentState = NpgsqlClosedState.Instance;
-                        _mediator.Reset();
-                        throw new NpgsqlException(sw.ToString());
                     }
+    
+                    backend_keydata = _mediator.GetBackEndKeyData();
+    
+                    
+    
+                    // Get version information to enable/disable server version features.
+                    // Only for protocol 2.0.
+                    if (BackendProtocolVersion == ProtocolVersion.Version2)
+                    {
+                        NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
+                        _serverVersion = (String) command.ExecuteScalar();
+                    }
+                    
+                    Connector.ServerVersion = _serverVersion;
+                    
                 }
-
-                backend_keydata = _mediator.GetBackEndKeyData();
-
-                // Change the state of connection to open.
-                connection_state = ConnectionState.Open;
-
-                // Get version information to enable/disable server version features.
-                // Only for protocol 2.0.
-                if (BackendProtocolVersion == ProtocolVersion.Version2)
-                {
-                    NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
-                    _serverVersion = (String) command.ExecuteScalar();
-                }
-
-
                 //NpgsqlCommand commandEncoding = new NpgsqlCommand("show client_encoding", this);
                 //String serverEncoding = (String)commandEncoding.ExecuteScalar();
 
                 //if (serverEncoding.Equals("UNICODE"))
                 //  connection_encoding = Encoding.UTF8;
-
-
-
+                
+                
+                // Connector was obtained from pool. 
+                // Do a mini initialization in the state machine.
+                
+                connection_state = ConnectionState.Open;
+                _serverVersion = Connector.ServerVersion;
+                CurrentState = NpgsqlReadyState.Instance;
+                
                 ProcessServerVersion();
                 _oidToNameMapping = NpgsqlTypesHelper.LoadTypesMapping(this);
 
-
-
             }
 
 
@@ -450,26 +472,8 @@ namespace Npgsql
         /// </summary>
         public void Close()
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
-
-            try
-            {
-                if ((connection_state == ConnectionState.Open))
-                {
-                    CurrentState.Close(this);
-                }
-            }
-            catch (IOException e)
-            {
-                throw new NpgsqlException(resman.GetString("Exception_CloseError"), e);
-            }
-            finally
-            {
-                // Even if an exception occurs, let object in a consistent state.
-                if (stream != null)
-                    stream.Close();
-                connection_state = ConnectionState.Closed;
-            }
+            Dispose(true);
+            
         }
 
         /// <summary>
@@ -503,12 +507,32 @@ namespace Npgsql
         /// <b>false</b> to release only unmanaged resources.</param>
         protected override void Dispose(bool disposing)
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose", disposing);
-            if (disposing == true)
+            if (disposing)
             {
-                if (this.connection_state == ConnectionState.Open)
-                    this.Close();
-                this.connection_string = null;
+                // Only if explicitly calling Close or dispose we still have access to 
+                // managed resources.
+                NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose", disposing);
+
+                try
+                {
+                    if ((connection_state == ConnectionState.Open))
+                    {
+                        CurrentState.Close(this);
+                    }
+                    
+                }
+                catch (IOException e)
+                {
+                    throw new NpgsqlException(resman.GetString("Exception_CloseError"), e);
+                }
+                finally
+                {
+                    // Even if an exception occurs, let object in a consistent state.
+                    /*if (stream != null)
+                        stream.Close();*/
+                    connection_state = ConnectionState.Closed;
+                }
+                                
             }
             base.Dispose (disposing);
         }
@@ -524,6 +548,8 @@ namespace Npgsql
         /// Database   - Database name. Defaults to user name if not specified
         /// User               - User name
         /// Password   - Password for clear text authentication
+        /// MinPoolSize - Min size of connection pool
+        /// MaxPoolSize - Max size of connection pool
         /// </summary>
         private void ParseConnectionString()
         {
@@ -572,28 +598,45 @@ 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.
-                SupportsPrepare = (_serverVersion.IndexOf("7.4") != -1);
+                // On protocol 3.0, 7.4 and above support it.
+                SupportsPrepare = (_serverVersion.IndexOf("7.4") != -1)
+                                    || (_serverVersion.IndexOf("7.5") != -1);
             }
         }
 
         internal Stream Stream {
             get
             {
-                return stream;
+                return _connector.Stream;
             }
             set
             {
                 stream = value;
             }
         }
+        
+        internal Connector Connector
+        {
+            get
+            {
+                return _connector;
+            }
+            set
+            {
+                _connector = value;
+            }
+        }
 
         /*
         public bool useSSL() 
@@ -779,6 +822,20 @@ namespace Npgsql
                 _backendProtocolVersion = value;
             }
         }
+        
+        internal Int32 MinPoolSize {
+            get
+            {
+                return Int32.Parse((String)connection_string_values[MIN_POOL_SIZE]);
+            }
+        }
+        
+        internal Int32 MaxPoolSize {
+            get
+            {
+                return Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]);
+            }
+        }
 
     }
 
index 2bb4a9b732058b23877804575642d2e0790921a0..db582303ec41b06eb1ddab5fca67d74a471b2f9f 100755 (executable)
 
 using System;
 using System.Net.Sockets;
+using System.IO;
 
 namespace Npgsql
 {
     /// <summary>
     /// !!! Helper class, for compilation only.
     /// </summary>
-    internal class Socket
-    {
-        internal void Open()
-        {
-            return;
-        }
-        internal void Close()
-        {
-            return;
-        }
-    }
-
+    
     /// <summary>
     /// Connector implements the logic for the Connection Objects to
     /// access the physical connection to the database, and isolate
@@ -51,7 +41,20 @@ namespace Npgsql
     internal class Connector
     {
         /// <value>Buffer for the public Pooled property</value>
-        private bool mPooled;
+        private Boolean _inUse;
+
+
+        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 Boolean _isInitialized;
+        
+        private Boolean mPooled;
+        private Boolean mOpen;
 
         /// <value>Chain references for implementing a double linked
         /// list</value>
@@ -79,6 +82,42 @@ namespace Npgsql
                 this.mPooled = value;
             }
         }
+        
+        internal String ServerVersion
+        {
+            get
+            {
+                return _serverVersion;
+            }
+            
+            set
+            {
+                _serverVersion = value;
+            }
+        }
+        
+        
+        internal Stream Stream {
+            get
+            {
+                return _stream;
+            }
+            set
+            {
+                _stream = value;
+                _isInitialized = true;
+            }
+        }
+        
+        internal Boolean IsInitialized
+        {
+            get
+            {
+                return _isInitialized;
+            }
+            
+        }
+        
 
         /// <value>Buffer for the public Shared property</value>
         private bool mShared;
@@ -132,17 +171,16 @@ namespace Npgsql
 
         /// <value>Provides physical access to the server</value>
         // !!! to be fixed
-        private Npgsql.Socket Socket;
-
-        /// <value>True if the physical connection is open.</value>
-        private bool mOpen;
+        //private Npgsql.Socket Socket;
 
+        
         /// <summary>
         /// Default constructor. Creates a pooled Connector by default.
         /// </summary>
         public Connector()
         {
-            this.Pooled = true;
+            Pooled = true;
+            _isInitialized = false;
         }
 
         /// <summary>
@@ -150,9 +188,9 @@ namespace Npgsql
         /// </summary>
         internal Connector( string ConnectString, bool Shared )
         {
-            this.ConnectString = ConnectString;
-            this.Shared = Shared;
-            this.Pooled = true;
+            ConnectString = ConnectString;
+            Shared = Shared;
+            Pooled = true;
         }
 
         /// <summary>
@@ -162,9 +200,22 @@ namespace Npgsql
         /// Method of the connection pool manager.</remarks>
         internal void Open()
         {
-            this.Socket = new Npgsql.Socket();
-            this.Socket.Open(); // !!! to be fixed
-            this.mOpen = true;
+            //this.Socket = new Npgsql.Socket();
+            //this.Socket.Open(); // !!! to be fixed
+            //this.mOpen = true;
+        }
+        
+        
+        internal Boolean InUse {
+            get
+            {
+                return _inUse;
+            }
+            set
+            {
+                _inUse = value;
+            }
+            
         }
 
         /// <summary>
@@ -175,7 +226,7 @@ namespace Npgsql
         /// evaluation inside this method, so they are left in their current state.
         ///    They get new meaning again when the connector is requested from the
         /// pool manager later. </remarks>
-        public void Release()
+        /*public void Release()
         {
             if ( this.mShared )
             {
@@ -207,9 +258,9 @@ namespace Npgsql
                     // Instead they are (implicitly) handed over to the
                     // garbage collection.
                     // !!! to be fixed
-                    this.Socket.Close();
+                    //this.Socket.Close();
                 }
             }
-        }
+        }*/
     }
 }
index 402e610f76386c8cdc86b723a83b1e176f5b93c4..4eb20332ad365b750160e446cbdbe6e49fd41f6f 100755 (executable)
@@ -22,6 +22,7 @@
 //             0.00.0000 - 06/17/2002 - ulrich sprick - creation
 
 using System;
+using System.Collections;
 using Npgsql;
 
 namespace Npgsql
@@ -31,11 +32,18 @@ namespace Npgsql
         /// <value>Unique static instance of the connector pool
         /// mamager.</value>
         internal static ConnectorPool ConnectorPoolMgr = new Npgsql.ConnectorPool();
+        
+        public ConnectorPool()
+        {
+            PooledConnectors = new Hashtable();
+        }
+        
 
-        /// <value>List of unused, pooled connectors avaliable to the
+        /// <value>Map of index to unused pooled connectors, avaliable to the
         /// next RequestConnector() call.</value>
-        /// <remarks>Points to the head of a double linked list</remarks>
-        internal Npgsql.Connector PooledConnectors;
+        /// <remarks>This hasmap will be indexed by connection string.
+        /// This key will hold a list of the pooled connectors available to be used.</remarks>
+        internal Hashtable PooledConnectors;
 
         /// <value>List of used, shared conncetors.</value>
         /// <remarks>Points to the head of a double linked list</remarks>
@@ -81,7 +89,7 @@ namespace Npgsql
         /// Inserts a connector at the head of a pooled connector list.
         /// </summary>
         /// <param name="Connector">The connctor to be inserted</param>
-        internal void InsertPooledConnector( Npgsql.Connector Connector )
+        /*internal void InsertPooledConnector( Npgsql.Connector Connector )
         {
             if ( this.PooledConnectors == null ) // the list is empty
             {
@@ -97,6 +105,18 @@ namespace Npgsql
             }
             // point the list to the new head
             this.PooledConnectors = Connector;
+        }*/
+        
+        
+        internal Int32 GetPoolSize(String connectionString)
+        {
+            ArrayList pool = (ArrayList)PooledConnectors[connectionString];
+            if (pool == null)
+                return 0;
+            else
+                return pool.Count;
+            
+                       
         }
 
         /// <summary>
@@ -108,67 +128,69 @@ namespace Npgsql
         /// <param name="Shared">Allows multiple connections
         /// on a single connector. </param>
         /// <returns>A pooled connector object.</returns>
-        internal Npgsql.Connector RequestConnector ( string ConnectString,
+        internal Npgsql.Connector RequestConnector ( String connectionString,
                 bool Shared )
         {
-            Npgsql.Connector Connector;
+            Connector connector;
+            ArrayList connectorPool = null;
 
             if ( Shared )
             {
                 // if a shared connector is requested then the
                 // Shared Connector List is searched first
 
-                for ( Connector = Npgsql.ConnectorPool.ConnectorPoolMgr.SharedConnectors;
+                /*for ( Connector = Npgsql.ConnectorPool.ConnectorPoolMgr.SharedConnectors;
                         Connector != null; Connector = Connector.Next )
                 {
-                    if ( Connector.ConnectString == ConnectString )
+                    if ( Connector.ConnectString == connectionString )
                     {  // Bingo!
                         // Return the shared connector to caller
                         Connector.mShareCount++;
                         return Connector;
                     }
-                }
+                }*/
+                
+                return null;
             }
             else
             {
                 // if a shared connector could not be found or a
                 // nonshared connector is requested, then the pooled
                 // (unused) connectors are beeing searched.
-
-                for ( Connector = Npgsql.ConnectorPool.ConnectorPoolMgr.PooledConnectors;
-                        Connector != null; Connector = Connector.Next )
+                
+                
+                connectorPool = (ArrayList)PooledConnectors[connectionString];
+                
+                if (connectorPool == null)
                 {
-                    if ( Connector.ConnectString == ConnectString )
-                    {  // Bingo!
-                        // Remove the Connector from the pooled connectors list.
-                        this.CutOutConnector( Connector );
-                    }
-                    Connector.Shared = Shared;
-                    if ( Shared )
-                    {
-                        // Shared Connectors are then put in the shared
-                        // connectors list in order to be used by
-                        // additional clients.
-                        this.InsertSharedConnector( Connector );
-                        Connector.mShareCount++;
-                    }
-                    // done...
-                    return Connector;
+                    connectorPool = new ArrayList();
+                    PooledConnectors[connectionString] = connectorPool;
                 }
-            }
+                
+                
+                // Now look for an available connector.
+                
+                
+                foreach (Connector c in connectorPool)
+                {
+                    if (!c.InUse)
+                        return c;
+                }
+                
+                // No suitable connector could be found, so create new one
+                connector = new Npgsql.Connector( connectionString, Shared );
 
-            // No suitable connector could be found, so create new one
-            Connector = new Npgsql.Connector( ConnectString, Shared );
+            connectorPool.Add(connector);
+            
 
-            // Shared connections are added to the shared connectors list
-            if ( Shared )
-            {
-                this.InsertSharedConnector( Connector );
-                Connector.mShareCount++;
+            // and then returned to the caller
+            return connector;
+                
+                
+                
             }
 
-            // and then returned to the caller
-            return Connector;
+            
         }
     }
 }
index b1459c050b2939fc6ca8294b0dc57f9a6a028a43..3812e984e066c275469a837fab360ec3aa9656f9 100755 (executable)
@@ -243,8 +243,10 @@ namespace Npgsql
 
             CheckCanRead();
 
-            if (i < 0 || _rowIndex < 0)
-                throw new InvalidOperationException("Cannot read data.");
+            if (i < 0)
+                throw new InvalidOperationException("Cannot read data. Column less than 0 specified.");
+            if (_rowIndex < 0)
+                throw new InvalidOperationException("Cannot read data. DataReader not initialized. Maybe you forgot to call Read()?");
             return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[i];
 
 
index 9df92da4f3cacdaad384c0ccfe60c0f17cc06639..cfaa0762876c4246f7c3fb1efa792cc997d814ab 100755 (executable)
@@ -146,7 +146,7 @@ namespace Npgsql
             {
                 Console.WriteLine(message);
             }
-
+            
             if (logfile != null)
             {
                 if (logfile != "")
index af6d7881fdc82d33e5b7a66692bc968a78f1abab..fe61e619cda38a934d9234e23de3640875d6d17b 100755 (executable)
@@ -46,27 +46,49 @@ namespace Npgsql
         protected ResourceManager resman = null;
 
         public virtual void Open(NpgsqlConnection context)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Startup(NpgsqlConnection context)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Authenticate(NpgsqlConnection context, string password)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Query(NpgsqlConnection context, NpgsqlCommand command)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Ready( NpgsqlConnection context )
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void FunctionCall(NpgsqlConnection context, NpgsqlCommand command)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Parse(NpgsqlConnection context, NpgsqlParse parse)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Flush(NpgsqlConnection context)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Sync(NpgsqlConnection context)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Bind(NpgsqlConnection context, NpgsqlBind bind)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
         public virtual void Execute(NpgsqlConnection context, NpgsqlExecute execute)
-        {}
+        {
+            throw new InvalidOperationException("Internal Error! " + this);
+        }
 
         public NpgsqlState()
         {
@@ -75,7 +97,7 @@ namespace Npgsql
 
         public virtual void Close( NpgsqlConnection context )
         {
-            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
+            /*NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
             if ( context.State == ConnectionState.Open )
             {
                 Stream stream = context.Stream;
@@ -86,8 +108,11 @@ namespace Npgsql
                         PGUtil.WriteInt32(stream, 4);
                     stream.Flush();
                 }
-            }
-            ChangeState( context, NpgsqlClosedState.Instance );
+            }*/
+            
+            context.Connector.InUse = false;
+            context.Connector = null;
+            //ChangeState( context, NpgsqlClosedState.Instance );
         }
 
         ///<summary> This method is used by the states to change the state of the context.
index efc22647c1bd1f6b74edaa0ffaa0044c9f0d33fb..ef5a4da39b2f632dd73b2c4266fdb2001c0a33d2 100755 (executable)
@@ -247,7 +247,7 @@ namespace NpgsqlTypes
 
                 // Get the date time parsed in all expected formats for timestamp.
                 return DateTime.ParseExact(data,
-                                           new String[] {"yyyy-MM-dd HH:mm:ss.fff", "yyyy-MM-dd HH:mm:ss.ff", "yyyy-MM-dd HH:mm:ss.f", "yyyy-MM-dd HH:mm:ss"},
+                                           new String[] {"yyyy-MM-dd HH:mm:ss.ffffff", "yyyy-MM-dd HH:mm:ss.fffff", "yyyy-MM-dd HH:mm:ss.ffff", "yyyy-MM-dd HH:mm:ss.fff", "yyyy-MM-dd HH:mm:ss.ff", "yyyy-MM-dd HH:mm:ss.f", "yyyy-MM-dd HH:mm:ss"},
                                            DateTimeFormatInfo.InvariantInfo,
                                            DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
 
@@ -485,18 +485,17 @@ namespace NpgsqlTypes
         private static String ConvertByteArrayToBytea(Byte[] byteArray)
         {
             NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertByteArrayToBytea");
-            Int32 len = byteArray.Length;
-            Char[] res = new Char [len * 5];
-            for (Int32 i = 0; i <len; i++)
+            int len = byteArray.Length;
+            char[] res = new char[len * 5];
+            for (int i=0, o=0; i<len; ++i, o += 5)
             {
-                res [(i*5)] = '\\';
-                res [(i*5)+1] = '\\';
-                res [(i*5)+2] = (Char) (((byteArray[i] & 0xC0) >> 6) + '0');
-                res [(i*5)+3] = (Char) (((byteArray[i] & 0x38) >> 3) + '0');
-                res [(i*5)+4] = (Char) ((byteArray[i] & 0x07) + '0');
+                byte item = byteArray[i];
+                res[o] = res[o + 1] = '\\';
+                res[o + 2] = (char)('0' + (7 & (item >> 6)));
+                res[o + 3] = (char)('0' + (7 & (item >> 3)));
+                res[o + 4] = (char)('0' + (7 & item));
             }
-
-            return new String (res);
+            return new String(res);
 
         }
     }
index a4be37b23fd033ed44b8ad27c0849ae4c3dea003..5348bb6b0043466eed13c00d678f499145808eae 100755 (executable)
@@ -89,9 +89,21 @@ namespace NpgsqlTests
                {
                        _conn.Open();
                        
-                       NpgsqlTransaction t = _conn.BeginTransaction();
+            NpgsqlTransaction t = null;
+            try
+            {
+                           t = _conn.BeginTransaction();
                        
-                       t = _conn.BeginTransaction();
+                           t = _conn.BeginTransaction();
+            }
+            catch(Exception e)
+            {
+                // Catch exception so we call rollback the transaction initiated.
+                // This way, the connection pool doesn't get a connection with a transaction
+                // started.
+                t.Rollback();
+                throw e;
+            }            
                        
                }