? .idea
? Pgjdbc.iml
? nio-1.patch
? out
? org/postgresql/core/AbstractPGStream.java
? org/postgresql/core/PGNIOStream.java
? org/postgresql/core/PGRegularStream.java
? org/postgresql/core/StreamReadListener.java
? org/postgresql/ssl/MakeSSL.java
Index: org/postgresql/PGConnection.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/PGConnection.java,v
retrieving revision 1.18
diff -c -r1.18 PGConnection.java
*** org/postgresql/PGConnection.java	2 Aug 2011 13:40:12 -0000	1.18
--- org/postgresql/PGConnection.java	19 Jan 2012 22:47:48 -0000
***************
*** 10,15 ****
--- 10,17 ----
  package org.postgresql;
  
  import java.sql.*;
+ import java.util.TimerTask;
+ 
  import org.postgresql.copy.CopyManager;
  import org.postgresql.fastpath.Fastpath;
  import org.postgresql.largeobject.LargeObjectManager;
***************
*** 111,116 ****
       * @return the current threshold
       */
      public int getPrepareThreshold();
- 
  }
  
--- 113,117 ----
Index: org/postgresql/core/BaseConnection.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/BaseConnection.java,v
retrieving revision 1.27
diff -c -r1.27 BaseConnection.java
*** org/postgresql/core/BaseConnection.java	26 Sep 2011 12:52:30 -0000	1.27
--- org/postgresql/core/BaseConnection.java	19 Jan 2012 22:47:48 -0000
***************
*** 10,15 ****
--- 10,17 ----
  package org.postgresql.core;
  
  import java.sql.*;
+ import java.util.TimerTask;
+ 
  import org.postgresql.PGConnection;
  import org.postgresql.jdbc2.TimestampUtils;
  
***************
*** 156,159 ****
--- 158,168 ----
       * @return True for binary transfer, false for text transfer.
       */
      public boolean binaryTransferSend(int oid);
+ 
+     /**
+      * Adds task to be executed in this connection
+      * @param timerTask
+      * @param milliSeconds
+      */
+     public void addTimerTask(Runnable timerTask, long milliSeconds);
  }
Index: org/postgresql/core/PGStream.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/PGStream.java,v
retrieving revision 1.24
diff -c -r1.24 PGStream.java
*** org/postgresql/core/PGStream.java	2 Aug 2011 13:40:12 -0000	1.24
--- org/postgresql/core/PGStream.java	19 Jan 2012 22:47:48 -0000
***************
*** 9,82 ****
  */
  package org.postgresql.core;
  
- import java.io.BufferedOutputStream;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.FilterOutputStream;
  import java.io.IOException;
! import java.io.EOFException;
  import java.io.Writer;
  import java.net.Socket;
! import java.sql.*;
! 
! import org.postgresql.util.GT;
! import org.postgresql.util.PSQLState;
! import org.postgresql.util.PSQLException;
  
  /**
!  * Wrapper around the raw connection to the server that implements some basic
!  * primitives (reading/writing formatted data, doing string encoding, etc).
!  *<p>
!  * In general, instances of PGStream are not threadsafe; the caller must ensure
!  * that only one thread at a time is accessing a particular PGStream instance.
   */
! public class PGStream
! {
!     private final String host;
!     private final int port;
! 
!     private final byte[] _int4buf;
!     private final byte[] _int2buf;
! 
!     private Socket connection;
!     private VisibleBufferedInputStream pg_input;
!     private OutputStream pg_output;
!     private byte[] streamBuffer;
! 
!     private Encoding encoding;
!     private Writer encodingWriter;
! 
!     /**
!      * Constructor:  Connect to the PostgreSQL back end and return
!      * a stream connection.
!      *
!      * @param host the hostname to connect to
!      * @param port the port number that the postmaster is sitting on
!      * @exception IOException if an IOException occurs below it.
!      */
!     public PGStream(String host, int port) throws IOException
!     {
!         this.host = host;
!         this.port = port;
! 
!         changeSocket(new Socket(host, port));
!         setEncoding(Encoding.getJVMEncoding("US-ASCII"));
! 
!         _int2buf = new byte[2];
!         _int4buf = new byte[4];
!     }
  
!     public String getHost() {
!         return host;
!     }
  
!     public int getPort() {
!         return port;
!     }
! 
!     public Socket getSocket() {
!         return connection;
!     }
  
      /**
       * Check for pending backend messages without blocking.
--- 9,35 ----
  */
  package org.postgresql.core;
  
  import java.io.IOException;
! import java.io.InputStream;
  import java.io.Writer;
  import java.net.Socket;
! import java.sql.SQLException;
! import java.util.Properties;
! import java.util.TimerTask;
  
  /**
!   * Wrapper around the raw connection to the server that implements some basic
!   * primitives (reading/writing formatted data, doing string encoding, etc).
!   *<p>
!   * In general, instances of PGStream are not threadsafe; the caller must ensure
!   * that only one thread at a time is accessing a particular PGStream instance.
   */
! public interface PGStream {
!     String getHost();
  
!     int getPort();
  
!     Socket getSocket();
  
      /**
       * Check for pending backend messages without blocking.
***************
*** 87,95 ****
       *
       * @return true if there is a pending backend message
       */
!     public boolean hasMessagePending() throws IOException {
!         return pg_input.available() > 0 || connection.getInputStream().available() > 0;
!     }
  
      /**
       * Switch this stream to using a new socket. Any existing socket
--- 40,46 ----
       *
       * @return true if there is a pending backend message
       */
!     boolean hasMessagePending() throws IOException;
  
      /**
       * Switch this stream to using a new socket. Any existing socket
***************
*** 99,123 ****
       * @param socket the new socket to change to
       * @throws IOException if something goes wrong
       */
!     public void changeSocket(Socket socket) throws IOException {
!         this.connection = socket;
  
!         // Submitted by Jason Venner <jason@idiom.com>. Disable Nagle
!         // as we are selective about flushing output only when we
!         // really need to.
!         connection.setTcpNoDelay(true);
! 
!         // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
!         pg_input = new VisibleBufferedInputStream(connection.getInputStream(), 8192);
!         pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
! 
!         if (encoding != null)
!             setEncoding(encoding);
!     }
! 
!     public Encoding getEncoding() {
!         return encoding;
!     }
  
      /**
       * Change the encoding used by this connection.
--- 50,58 ----
       * @param socket the new socket to change to
       * @throws IOException if something goes wrong
       */
!     void changeSocket(Socket socket) throws IOException;
  
!     Encoding getEncoding();
  
      /**
       * Change the encoding used by this connection.
***************
*** 125,149 ****
       * @param encoding the new encoding to use
       * @throws IOException if something goes wrong
       */
!     public void setEncoding(Encoding encoding) throws IOException {
!         // Close down any old writer.
!         if (encodingWriter != null)
!             encodingWriter.close();
! 
!         this.encoding = encoding;
! 
!         // Intercept flush() downcalls from the writer; our caller
!         // will call PGStream.flush() as needed.
!         OutputStream interceptor = new FilterOutputStream(pg_output) {
!                                        public void flush() throws IOException {
!                                        }
!                                        public void close() throws IOException {
!                                            super.flush();
!                                        }
!                                    };
! 
!         encodingWriter = encoding.getEncodingWriter(interceptor);
!     }
  
      /**
       * Get a Writer instance that encodes directly onto the underlying stream.
--- 60,66 ----
       * @param encoding the new encoding to use
       * @throws IOException if something goes wrong
       */
!     void setEncoding(Encoding encoding) throws IOException;
  
      /**
       * Get a Writer instance that encodes directly onto the underlying stream.
***************
*** 157,167 ****
       * @return the shared Writer instance
       * @throws IOException if something goes wrong.
       */
!     public Writer getEncodingWriter() throws IOException {
!         if (encodingWriter == null)
!             throw new IOException("No encoding has been set on this connection");
!         return encodingWriter;
!     }
  
      /**
       * Sends a single character to the back end
--- 74,80 ----
       * @return the shared Writer instance
       * @throws IOException if something goes wrong.
       */
!     Writer getEncodingWriter() throws IOException;
  
      /**
       * Sends a single character to the back end
***************
*** 169,178 ****
       * @param val the character to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void SendChar(int val) throws IOException
!     {
!         pg_output.write(val);
!     }
  
      /**
       * Sends a 4-byte integer to the back end
--- 82,88 ----
       * @param val the character to be sent
       * @exception IOException if an I/O error occurs
       */
!     void SendChar(int val) throws IOException;
  
      /**
       * Sends a 4-byte integer to the back end
***************
*** 180,193 ****
       * @param val the integer to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void SendInteger4(int val) throws IOException
!     {
!         _int4buf[0] = (byte)(val >>> 24);
!         _int4buf[1] = (byte)(val >>> 16);
!         _int4buf[2] = (byte)(val >>> 8);
!         _int4buf[3] = (byte)(val);
!         pg_output.write(_int4buf);
!     }
  
      /**
       * Sends a 2-byte integer (short) to the back end
--- 90,96 ----
       * @param val the integer to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void SendInteger4(int val) throws IOException;
  
      /**
       * Sends a 2-byte integer (short) to the back end
***************
*** 195,209 ****
       * @param val the integer to be sent
       * @exception IOException if an I/O error occurs or <code>val</code> cannot be encoded in 2 bytes
       */
!     public void SendInteger2(int val) throws IOException
!     {
!         if (val < Short.MIN_VALUE || val > Short.MAX_VALUE)
!             throw new IOException("Tried to send an out-of-range integer as a 2-byte value: " + val);
! 
!         _int2buf[0] = (byte)(val >>> 8);
!         _int2buf[1] = (byte)val;
!         pg_output.write(_int2buf);
!     }
  
      /**
       * Send an array of bytes to the backend
--- 98,104 ----
       * @param val the integer to be sent
       * @exception IOException if an I/O error occurs or <code>val</code> cannot be encoded in 2 bytes
       */
!     public void SendInteger2(int val) throws IOException;
  
      /**
       * Send an array of bytes to the backend
***************
*** 211,220 ****
       * @param buf The array of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[]) throws IOException
!     {
!         pg_output.write(buf);
!     }
  
      /**
       * Send a fixed-size array of bytes to the backend. If buf.length < siz,
--- 106,112 ----
       * @param buf The array of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[]) throws IOException;
  
      /**
       * Send a fixed-size array of bytes to the backend. If buf.length < siz,
***************
*** 224,233 ****
       * @param siz the number of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[], int siz) throws IOException
!     {
!         Send(buf, 0, siz);
!     }
  
      /**
       * Send a fixed-size array of bytes to the backend. If length < siz,
--- 116,122 ----
       * @param siz the number of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[], int siz) throws IOException;
  
      /**
       * Send a fixed-size array of bytes to the backend. If length < siz,
***************
*** 238,252 ****
       * @param siz the number of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[], int off, int siz) throws IOException
!     {
! 	int bufamt = buf.length - off;
!         pg_output.write(buf, off, bufamt < siz ? bufamt : siz);
!         for (int i = bufamt ; i < siz ; ++i)
!         {
!             pg_output.write(0);
!         }
!     }
  
      /**
       * Receives a single character from the backend, without
--- 127,133 ----
       * @param siz the number of bytes to be sent
       * @exception IOException if an I/O error occurs
       */
!     public void Send(byte buf[], int off, int siz) throws IOException;
  
      /**
       * Receives a single character from the backend, without
***************
*** 255,267 ****
       * @return the character received
       * @exception IOException if an I/O Error occurs
       */
!     public int PeekChar() throws IOException
!     {
!         int c = pg_input.peek();
!         if (c < 0)
!             throw new EOFException();
!         return c;
!     }
  
      /**
       * Receives a single character from the backend
--- 136,142 ----
       * @return the character received
       * @exception IOException if an I/O Error occurs
       */
!     public int PeekChar() throws IOException;
  
      /**
       * Receives a single character from the backend
***************
*** 269,281 ****
       * @return the character received
       * @exception IOException if an I/O Error occurs
       */
!     public int ReceiveChar() throws IOException
!     {
!         int c = pg_input.read();
!         if (c < 0)
!             throw new EOFException();
!         return c;
!     }
  
      /**
       * Receives a four byte integer from the backend
--- 144,150 ----
       * @return the character received
       * @exception IOException if an I/O Error occurs
       */
!     public int ReceiveChar() throws IOException;
  
      /**
       * Receives a four byte integer from the backend
***************
*** 283,295 ****
       * @return the integer received from the backend
       * @exception IOException if an I/O error occurs
       */
!     public int ReceiveInteger4() throws IOException
!     {
!         if (pg_input.read(_int4buf) != 4)
!             throw new EOFException();
! 
!         return (_int4buf[0] & 0xFF) << 24 | (_int4buf[1] & 0xFF) << 16 | (_int4buf[2] & 0xFF) << 8 | _int4buf[3] & 0xFF;
!     }
  
      /**
       * Receives a two byte integer from the backend
--- 152,158 ----
       * @return the integer received from the backend
       * @exception IOException if an I/O error occurs
       */
!     public int ReceiveInteger4() throws IOException;
  
      /**
       * Receives a two byte integer from the backend
***************
*** 297,309 ****
       * @return the integer received from the backend
       * @exception IOException if an I/O error occurs
       */
!     public int ReceiveInteger2() throws IOException
!     {
!         if (pg_input.read(_int2buf) != 2)
!             throw new EOFException();
! 
!         return (_int2buf[0] & 0xFF) << 8 | _int2buf[1] & 0xFF;
!     }
  
      /**
       * Receives a fixed-size string from the backend.
--- 160,166 ----
       * @return the integer received from the backend
       * @exception IOException if an I/O error occurs
       */
!     int ReceiveInteger2() throws IOException;
  
      /**
       * Receives a fixed-size string from the backend.
***************
*** 311,326 ****
       * @param len the length of the string to receive, in bytes.
       * @return the decoded string
       */
!     public String ReceiveString(int len) throws IOException {
!         if (!pg_input.ensureBytes(len)) {
!             throw new EOFException();
!         }
! 
!         String res = encoding.decode(pg_input.getBuffer(), pg_input.getIndex(),
!                                      len);
!         pg_input.skip(len);
!         return res;
!     }
  
      /**
       * Receives a null-terminated string from the backend. If we don't see a
--- 168,174 ----
       * @param len the length of the string to receive, in bytes.
       * @return the decoded string
       */
!     String ReceiveString(int len) throws IOException;
  
      /**
       * Receives a null-terminated string from the backend. If we don't see a
***************
*** 329,342 ****
       * @return string from back end
       * @exception IOException if an I/O error occurs, or end of file
       */
!     public String ReceiveString() throws IOException
!     {
!         int len = pg_input.scanCStringLength();
!         String res = encoding.decode(pg_input.getBuffer(), pg_input.getIndex(),
!                                      len - 1);
!         pg_input.skip(len);
!         return res;
!     }
  
      /**
       * Read a tuple from the back end. A tuple is a two dimensional
--- 177,184 ----
       * @return string from back end
       * @exception IOException if an I/O error occurs, or end of file
       */
!     public String ReceiveString() throws IOException;
! 
  
      /**
       * Read a tuple from the back end. A tuple is a two dimensional
***************
*** 347,380 ****
       * an array of bytearrays
       * @exception IOException if a data I/O error occurs
       */
!     public byte[][] ReceiveTupleV3() throws IOException, OutOfMemoryError
!     {
!         //TODO: use l_msgSize
!         int l_msgSize = ReceiveInteger4();
!         int i;
!         int l_nf = ReceiveInteger2();
!         byte[][] answer = new byte[l_nf][];
! 
!         OutOfMemoryError oom = null;
!         for (i = 0 ; i < l_nf ; ++i)
!         {
!             int l_size = ReceiveInteger4();
!             if (l_size != -1) {
!                 try {
!                     answer[i] = new byte[l_size];
!                     Receive(answer[i], 0, l_size);
!                 } catch(OutOfMemoryError oome) {
!                     oom = oome;
!                     Skip(l_size);
!                 }
!             }
!         }
! 
!         if (oom != null)
!             throw oom;
! 
!         return answer;
!     }
  
      /**
       * Read a tuple from the back end. A tuple is a two dimensional
--- 189,195 ----
       * an array of bytearrays
       * @exception IOException if a data I/O error occurs
       */
!     byte[][] ReceiveTupleV3() throws IOException, OutOfMemoryError;
  
      /**
       * Read a tuple from the back end. A tuple is a two dimensional
***************
*** 387,433 ****
       * an array of bytearrays
       * @exception IOException if a data I/O error occurs
       */
!     public byte[][] ReceiveTupleV2(int nf, boolean bin) throws IOException, OutOfMemoryError
!     {
!         int i, bim = (nf + 7) / 8;
!         byte[] bitmask = Receive(bim);
!         byte[][] answer = new byte[nf][];
! 
!         int whichbit = 0x80;
!         int whichbyte = 0;
! 
!         OutOfMemoryError oom = null;
!         for (i = 0 ; i < nf ; ++i)
!         {
!             boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
!             whichbit >>= 1;
!             if (whichbit == 0)
!             {
!                 ++whichbyte;
!                 whichbit = 0x80;
!             }
!             if (!isNull)
!             {
!                 int len = ReceiveInteger4();
!                 if (!bin)
!                     len -= 4;
!                 if (len < 0)
!                     len = 0;
!                 try {
!                     answer[i] = new byte[len];
!                     Receive(answer[i], 0, len);
!                 } catch(OutOfMemoryError oome) {
!                     oom = oome;
!                     Skip(len);
!                 }
!             }
!         }
! 
!         if (oom != null)
!             throw oom;
! 
!         return answer;
!     }
  
      /**
       * Reads in a given number of bytes from the backend
--- 202,208 ----
       * an array of bytearrays
       * @exception IOException if a data I/O error occurs
       */
!     byte[][] ReceiveTupleV2(int nf, boolean bin) throws IOException, OutOfMemoryError;
  
      /**
       * Reads in a given number of bytes from the backend
***************
*** 436,447 ****
       * @return array of bytes received
       * @exception IOException if a data I/O error occurs
       */
!     public byte[] Receive(int siz) throws IOException
!     {
!         byte[] answer = new byte[siz];
!         Receive(answer, 0, siz);
!         return answer;
!     }
  
      /**
       * Reads in a given number of bytes from the backend
--- 211,217 ----
       * @return array of bytes received
       * @exception IOException if a data I/O error occurs
       */
!     byte[] Receive(int siz) throws IOException;
  
      /**
       * Reads in a given number of bytes from the backend
***************
*** 451,476 ****
       * @param siz number of bytes to read
       * @exception IOException if a data I/O error occurs
       */
!     public void Receive(byte[] buf, int off, int siz) throws IOException
!     {
!         int s = 0;
! 
!         while (s < siz)
!         {
!             int w = pg_input.read(buf, off + s, siz - s);
!             if (w < 0)
!                 throw new EOFException();
!             s += w;
!         }
!     }
! 
!     public void Skip(int size) throws IOException {
!         long s = 0;
!         while (s < size) {
!             s += pg_input.skip(size - s);
!         }
!     }
  
  
      /**
       * Copy data from an input stream to the connection.
--- 221,229 ----
       * @param siz number of bytes to read
       * @exception IOException if a data I/O error occurs
       */
!     void Receive(byte[] buf, int off, int siz) throws IOException;
  
+     void Skip(int size) throws IOException;
  
      /**
       * Copy data from an input stream to the connection.
***************
*** 478,552 ****
       * @param inStream the stream to read data from
       * @param remaining the number of bytes to copy
       */
!     public void SendStream(InputStream inStream, int remaining) throws IOException {
!         int expectedLength = remaining;
!         if (streamBuffer == null)
!             streamBuffer = new byte[8192];
! 
!         while (remaining > 0)
!         {
!             int count = (remaining > streamBuffer.length ? streamBuffer.length : remaining);
!             int readCount;
! 
!             try
!             {
!                 readCount = inStream.read(streamBuffer, 0, count);
!                 if (readCount < 0)
!                     throw new EOFException(GT.tr("Premature end of input stream, expected {0} bytes, but only read {1}.", new Object[]{new Integer(expectedLength), new Integer(expectedLength - remaining)}));
!             }
!             catch (IOException ioe)
!             {
!                 while (remaining > 0)
!                 {
!                     Send(streamBuffer, count);
!                     remaining -= count;
!                     count = (remaining > streamBuffer.length ? streamBuffer.length : remaining);
!                 }
!                 throw new PGBindException(ioe);
!             }
! 
!             Send(streamBuffer, readCount);
!             remaining -= readCount;
!         }
!     }
! 
! 
  
      /**
       * Flush any pending output to the backend.
       * @exception IOException if an I/O error occurs
       */
!     public void flush() throws IOException
!     {
!         if (encodingWriter != null)
!             encodingWriter.flush();
!         pg_output.flush();
!     }
  
      /**
       * Consume an expected EOF from the backend
       * @exception SQLException if we get something other than an EOF
       */
!     public void ReceiveEOF() throws SQLException, IOException
!     {
!         int c = pg_input.read();
!         if (c < 0)
!             return;
!         throw new PSQLException(GT.tr("Expected an EOF from server, got: {0}", new Integer(c)), PSQLState.COMMUNICATION_ERROR);
!     }
  
      /**
       * Closes the connection
       *
       * @exception IOException if an I/O Error occurs
       */
!     public void close() throws IOException
!     {
!         if (encodingWriter != null)
!             encodingWriter.close();
! 
!         pg_output.close();
!         pg_input.close();
!         connection.close();
!     }
  }
--- 231,287 ----
       * @param inStream the stream to read data from
       * @param remaining the number of bytes to copy
       */
!     void SendStream(InputStream inStream, int remaining) throws IOException;
  
      /**
       * Flush any pending output to the backend.
       * @exception IOException if an I/O error occurs
       */
!     void flush() throws IOException;
  
      /**
       * Consume an expected EOF from the backend
       * @exception SQLException if we get something other than an EOF
       */
!     void ReceiveEOF() throws SQLException, IOException;
  
      /**
       * Closes the connection
       *
       * @exception IOException if an I/O Error occurs
       */
!     void close() throws IOException;
! 
!     /**
!      * Establish new connection to the server
!      * @param closeOriginal if to close this socket (true) or leave it connected (false)
!      * @return newly established connection
!      * @throws IOException if an I/O Error occurs
!      */
!     PGStream reconnect(boolean closeOriginal) throws IOException;
! 
!     /**
!      * Enables SSL on the stream
!      * @param requireSSL is SSL is required or optional
!      * @param info connection properties
!      * @param logger where to log o
!      * @return either this connection or new one if reconnect was required
!      * @throws IOException if an I/O Error occurs
!      * @throws SQLException if a protocol-level error occurs
!      */
!     PGStream enableSSL(boolean requireSSL, Properties info, Logger logger) throws IOException, SQLException;
! 
!     /**
!      * Sets new read listener
!      * @param newListener read listener to set
!      * @return old read listener or null if listeners are not supported
!      */
!     StreamReadListener readListener(StreamReadListener newListener) throws IOException;
! 
!     /**
!      * Adds task to be executed in this connection
!      * @param timerTask
!      * @param milliSeconds
!      */
!     public void addTimerTask(Runnable timerTask, long milliSeconds);
  }
Index: org/postgresql/core/ProtocolConnection.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/ProtocolConnection.java,v
retrieving revision 1.10
diff -c -r1.10 ProtocolConnection.java
*** org/postgresql/core/ProtocolConnection.java	22 Sep 2011 12:53:23 -0000	1.10
--- org/postgresql/core/ProtocolConnection.java	19 Jan 2012 22:47:48 -0000
***************
*** 13,18 ****
--- 13,19 ----
  import org.postgresql.PGNotification;
  import java.sql.*;
  import java.util.BitSet;
+ import java.util.TimerTask;
  
  /**
   * Provides access to protocol-level connection operations.
***************
*** 148,151 ****
--- 149,159 ----
       * @return the server integer_datetime setting.
       */
      public boolean getIntegerDateTimes();
+ 
+     /**
+      * Adds task to be executed in this connection
+      * @param timerTask
+      * @param milliSeconds
+      */
+     public void addTimerTask(Runnable timerTask, long milliSeconds);
  }
Index: org/postgresql/core/VisibleBufferedInputStream.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/VisibleBufferedInputStream.java,v
retrieving revision 1.5
diff -c -r1.5 VisibleBufferedInputStream.java
*** org/postgresql/core/VisibleBufferedInputStream.java	2 Aug 2011 13:40:12 -0000	1.5
--- org/postgresql/core/VisibleBufferedInputStream.java	19 Jan 2012 22:47:48 -0000
***************
*** 27,38 ****
       * first fill the buffer and serve the bytes from there. Larger
       * reads are directly done to the provided byte array.
       */
!     private static final int MINIMUM_READ = 1024;
      
      /**
       * In how large spans is the C string zero-byte scanned.
       */
!     private static final int STRING_SCAN_SPAN = 1024;
  
      /**
       * The wrapped input stream.
--- 27,38 ----
       * first fill the buffer and serve the bytes from there. Larger
       * reads are directly done to the provided byte array.
       */
!     static final int MINIMUM_READ = 1024;
      
      /**
       * In how large spans is the C string zero-byte scanned.
       */
!     static final int STRING_SCAN_SPAN = 1024;
  
      /**
       * The wrapped input stream.
Index: org/postgresql/core/v2/ConnectionFactoryImpl.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/v2/ConnectionFactoryImpl.java,v
retrieving revision 1.24
diff -c -r1.24 ConnectionFactoryImpl.java
*** org/postgresql/core/v2/ConnectionFactoryImpl.java	17 Nov 2011 11:27:50 -0000	1.24
--- org/postgresql/core/v2/ConnectionFactoryImpl.java	19 Jan 2012 22:47:49 -0000
***************
*** 17,23 ****
  import java.io.IOException;
  import java.net.ConnectException;
  
- import org.postgresql.Driver;
  import org.postgresql.core.*;
  import org.postgresql.util.PSQLException;
  import org.postgresql.util.PSQLState;
--- 17,22 ----
***************
*** 81,91 ****
          PGStream newStream = null;
          try
          {
!             newStream = new PGStream(host, port);
  
              // Construct and send an ssl startup packet if requested.
              if (trySSL)
!                 newStream = enableSSL(newStream, requireSSL, info, logger);
              
              
              // Set the socket timeout if the "socketTimeout" property has been set.
--- 80,90 ----
          PGStream newStream = null;
          try
          {
!             newStream = new PGRegularStream(host, port);
  
              // Construct and send an ssl startup packet if requested.
              if (trySSL)
!                 newStream = newStream.enableSSL(requireSSL, info, logger);
              
              
              // Set the socket timeout if the "socketTimeout" property has been set.
***************
*** 181,188 ****
                  throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
  
              // We have to reconnect to continue.
!             pgStream.close();
!             return new PGStream(pgStream.getHost(), pgStream.getPort());
  
          case 'N':
              if (logger.logDebug())
--- 180,186 ----
                  throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
  
              // We have to reconnect to continue.
!             return pgStream.reconnect(true);
  
          case 'N':
              if (logger.logDebug())
Index: org/postgresql/core/v2/ProtocolConnectionImpl.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/v2/ProtocolConnectionImpl.java,v
retrieving revision 1.14
diff -c -r1.14 ProtocolConnectionImpl.java
*** org/postgresql/core/v2/ProtocolConnectionImpl.java	22 Sep 2011 12:53:24 -0000	1.14
--- org/postgresql/core/v2/ProtocolConnectionImpl.java	19 Jan 2012 22:47:49 -0000
***************
*** 91,97 ****
              if (logger.logDebug())
                  logger.debug(" FE=> CancelRequest(pid=" + cancelPid + ",ckey=" + cancelKey + ")");
  
!             cancelStream = new PGStream(pgStream.getHost(), pgStream.getPort());
              cancelStream.SendInteger4(16);
              cancelStream.SendInteger2(1234);
              cancelStream.SendInteger2(5678);
--- 91,97 ----
              if (logger.logDebug())
                  logger.debug(" FE=> CancelRequest(pid=" + cancelPid + ",ckey=" + cancelKey + ")");
  
!             cancelStream = pgStream.reconnect(false);
              cancelStream.SendInteger4(16);
              cancelStream.SendInteger2(1234);
              cancelStream.SendInteger2(5678);
***************
*** 211,216 ****
--- 211,220 ----
          return false;
      }
  
+     public void addTimerTask(Runnable timerTask, long milliSeconds) {
+         pgStream.addTimerTask(timerTask, milliSeconds);
+     }
+ 
      private String serverVersion;
      private int cancelPid;
      private int cancelKey;
Index: org/postgresql/core/v3/ConnectionFactoryImpl.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/v3/ConnectionFactoryImpl.java,v
retrieving revision 1.28
diff -c -r1.28 ConnectionFactoryImpl.java
*** org/postgresql/core/v3/ConnectionFactoryImpl.java	17 Nov 2011 11:27:51 -0000	1.28
--- org/postgresql/core/v3/ConnectionFactoryImpl.java	19 Jan 2012 22:47:49 -0000
***************
*** 17,23 ****
  import java.io.IOException;
  import java.net.ConnectException;
  
- import org.postgresql.Driver;
  import org.postgresql.core.*;
  import org.postgresql.util.PSQLException;
  import org.postgresql.util.PSQLState;
--- 17,22 ----
***************
*** 97,107 ****
          PGStream newStream = null;
          try
          {
!             newStream = new PGStream(host, port);
  
              // Construct and send an ssl startup packet if requested.
              if (trySSL)
!                 newStream = enableSSL(newStream, requireSSL, info, logger);
              
              // Set the socket timeout if the "socketTimeout" property has been set.
              String socketTimeoutProperty = info.getProperty("socketTimeout", "0");
--- 96,106 ----
          PGStream newStream = null;
          try
          {
!             newStream = trySSL ? new PGRegularStream(host, port) : new PGNIOStream(host, port);
  
              // Construct and send an ssl startup packet if requested.
              if (trySSL)
!                 newStream = newStream.enableSSL(requireSSL, info, logger);
              
              // Set the socket timeout if the "socketTimeout" property has been set.
              String socketTimeoutProperty = info.getProperty("socketTimeout", "0");
***************
*** 218,272 ****
          return start + tz.substring(4);
      }
  
-     private PGStream enableSSL(PGStream pgStream, boolean requireSSL, Properties info, Logger logger) throws IOException, SQLException {
-         if (logger.logDebug())
-             logger.debug(" FE=> SSLRequest");
- 
-         // Send SSL request packet
-         pgStream.SendInteger4(8);
-         pgStream.SendInteger2(1234);
-         pgStream.SendInteger2(5679);
-         pgStream.flush();
- 
-         // Now get the response from the backend, one of N, E, S.
-         int beresp = pgStream.ReceiveChar();
-         switch (beresp)
-         {
-         case 'E':
-             if (logger.logDebug())
-                 logger.debug(" <=BE SSLError");
- 
-             // Server doesn't even know about the SSL handshake protocol
-             if (requireSSL)
-                 throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
- 
-             // We have to reconnect to continue.
-             pgStream.close();
-             return new PGStream(pgStream.getHost(), pgStream.getPort());
- 
-         case 'N':
-             if (logger.logDebug())
-                 logger.debug(" <=BE SSLRefused");
- 
-             // Server does not support ssl
-             if (requireSSL)
-                 throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
- 
-             return pgStream;
- 
-         case 'S':
-             if (logger.logDebug())
-                 logger.debug(" <=BE SSLOk");
- 
-             // Server supports ssl
-             org.postgresql.ssl.MakeSSL.convert(pgStream, info, logger);
-             return pgStream;
- 
-         default:
-             throw new PSQLException(GT.tr("An error occured while setting up the SSL connection."), PSQLState.PROTOCOL_VIOLATION);
-         }
-     }
- 
      private void sendStartupPacket(PGStream pgStream, String[][] params, Logger logger) throws IOException {
          if (logger.logDebug())
          {
--- 217,222 ----
Index: org/postgresql/core/v3/ProtocolConnectionImpl.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/core/v3/ProtocolConnectionImpl.java,v
retrieving revision 1.15
diff -c -r1.15 ProtocolConnectionImpl.java
*** org/postgresql/core/v3/ProtocolConnectionImpl.java	22 Sep 2011 12:53:24 -0000	1.15
--- org/postgresql/core/v3/ProtocolConnectionImpl.java	19 Jan 2012 22:47:49 -0000
***************
*** 91,97 ****
              if (logger.logDebug())
                  logger.debug(" FE=> CancelRequest(pid=" + cancelPid + ",ckey=" + cancelKey + ")");
  
!             cancelStream = new PGStream(pgStream.getHost(), pgStream.getPort());
              cancelStream.SendInteger4(16);
              cancelStream.SendInteger2(1234);
              cancelStream.SendInteger2(5678);
--- 91,97 ----
              if (logger.logDebug())
                  logger.debug(" FE=> CancelRequest(pid=" + cancelPid + ",ckey=" + cancelKey + ")");
  
!             cancelStream = pgStream.reconnect(false);
              cancelStream.SendInteger4(16);
              cancelStream.SendInteger2(1234);
              cancelStream.SendInteger2(5678);
***************
*** 218,224 ****
          return integerDateTimes;
      }
  
!    /**
       * True if server uses integers for date and time fields. False if
       * server uses double.
       */
--- 218,228 ----
          return integerDateTimes;
      }
  
!     public void addTimerTask(Runnable timerTask, long milliSeconds) {
!         pgStream.addTimerTask(timerTask, milliSeconds);
!     }
! 
!     /**
       * True if server uses integers for date and time fields. False if
       * server uses double.
       */
Index: org/postgresql/jdbc2/AbstractJdbc2Connection.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Connection.java,v
retrieving revision 1.58
diff -c -r1.58 AbstractJdbc2Connection.java
*** org/postgresql/jdbc2/AbstractJdbc2Connection.java	26 Sep 2011 12:52:30 -0000	1.58
--- org/postgresql/jdbc2/AbstractJdbc2Connection.java	19 Jan 2012 22:47:49 -0000
***************
*** 1227,1230 ****
--- 1227,1234 ----
      public boolean binaryTransferSend(int oid) {
          return useBinarySendForOids.get(oid);
      }
+ 
+     public void addTimerTask(Runnable timerTask, long milliSeconds) {
+         protoConnection.addTimerTask(timerTask, milliSeconds);
+     }
  }
Index: org/postgresql/jdbc2/AbstractJdbc2Statement.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java,v
retrieving revision 1.127
diff -c -r1.127 AbstractJdbc2Statement.java
*** org/postgresql/jdbc2/AbstractJdbc2Statement.java	30 Sep 2011 10:08:17 -0000	1.127
--- org/postgresql/jdbc2/AbstractJdbc2Statement.java	19 Jan 2012 22:47:50 -0000
***************
*** 724,730 ****
          	
          };
          
!         Driver.addTimerTask( cancelTimer, seconds);
          timeout = seconds;
      }
  
--- 724,730 ----
          	
          };
          
!         connection.addTimerTask( cancelTimer, seconds * 1000);
          timeout = seconds;
      }
  
Index: org/postgresql/test/jdbc2/StatementTest.java
===================================================================
RCS file: /cvsroot/jdbc/pgjdbc/org/postgresql/test/jdbc2/StatementTest.java,v
retrieving revision 1.32
diff -c -r1.32 StatementTest.java
*** org/postgresql/test/jdbc2/StatementTest.java	22 Sep 2011 12:53:26 -0000	1.32
--- org/postgresql/test/jdbc2/StatementTest.java	19 Jan 2012 22:47:51 -0000
***************
*** 491,498 ****
      			{
      				fail("Query timeout should have occured and cleaned this up");
      			}
!     		}, 1000);
!     		stmt.setQueryTimeout(100);
      		stmt.execute("select pg_sleep(999999999999999)");
      		
      	}catch( SQLException sqle )
--- 491,498 ----
      			{
      				fail("Query timeout should have occured and cleaned this up");
      			}
!     		}, 10000);
!     		stmt.setQueryTimeout(1);
      		stmt.execute("select pg_sleep(999999999999999)");
      		
      	}catch( SQLException sqle )
*** /var/empty	1970-01-01 03:00:00.000000000 +0300
--- org/postgresql/core/AbstractPGStream.java	2012-01-20 00:44:42.584702723 +0200
***************
*** 0 ****
--- 1,247 ----
+ /*-------------------------------------------------------------------------
+ *
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   $PostgreSQL: pgjdbc/org/postgresql/core/BaseConnection.java,v 1.27 2011/09/26 12:52:30 davecramer Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+ package org.postgresql.core;
+ 
+ import org.postgresql.util.GT;
+ import org.postgresql.util.PSQLException;
+ import org.postgresql.util.PSQLState;
+ 
+ import java.io.EOFException;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.sql.SQLException;
+ import java.util.Properties;
+ 
+ /**
+  * This class implements high-level PGStream methods common to NIO and Stream
+  * implementations
+  */
+ public abstract class AbstractPGStream implements PGStream {
+     protected final String host;
+     protected final int port;
+     private byte[] streamBuffer;
+ 
+     public AbstractPGStream(String host, int port) {
+         this.port = port;
+         this.host = host;
+     }
+ 
+     /**
+      * Read a tuple from the back end. A tuple is a two dimensional
+      * array of bytes. This variant reads the V3 protocol's tuple
+      * representation.
+      *
+      * @return null if the current response has no more tuples, otherwise
+      * an array of bytearrays
+      * @exception java.io.IOException if a data I/O error occurs
+      */
+     public byte[][] ReceiveTupleV3() throws IOException, OutOfMemoryError
+     {
+         //TODO: use l_msgSize
+         int l_msgSize = ReceiveInteger4();
+         int i;
+         int l_nf = ReceiveInteger2();
+         byte[][] answer = new byte[l_nf][];
+ 
+         OutOfMemoryError oom = null;
+         for (i = 0 ; i < l_nf ; ++i)
+         {
+             int l_size = ReceiveInteger4();
+             if (l_size != -1) {
+                 try {
+                     answer[i] = new byte[l_size];
+                     Receive(answer[i], 0, l_size);
+                 } catch(OutOfMemoryError oome) {
+                     oom = oome;
+                     Skip(l_size);
+                 }
+             }
+         }
+ 
+         if (oom != null)
+             throw oom;
+ 
+         return answer;
+     }
+ 
+     /**
+      * Read a tuple from the back end. A tuple is a two dimensional
+      * array of bytes. This variant reads the V2 protocol's tuple
+      * representation.
+      *
+      * @param nf the number of fields expected
+      * @param bin true if the tuple is a binary tuple
+      * @return null if the current response has no more tuples, otherwise
+      * an array of bytearrays
+      * @exception java.io.IOException if a data I/O error occurs
+      */
+     public byte[][] ReceiveTupleV2(int nf, boolean bin) throws IOException, OutOfMemoryError
+     {
+         int i, bim = (nf + 7) / 8;
+         byte[] bitmask = Receive(bim);
+         byte[][] answer = new byte[nf][];
+ 
+         int whichbit = 0x80;
+         int whichbyte = 0;
+ 
+         OutOfMemoryError oom = null;
+         for (i = 0 ; i < nf ; ++i)
+         {
+             boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
+             whichbit >>= 1;
+             if (whichbit == 0)
+             {
+                 ++whichbyte;
+                 whichbit = 0x80;
+             }
+             if (!isNull)
+             {
+                 int len = ReceiveInteger4();
+                 if (!bin)
+                     len -= 4;
+                 if (len < 0)
+                     len = 0;
+                 try {
+                     answer[i] = new byte[len];
+                     Receive(answer[i], 0, len);
+                 } catch(OutOfMemoryError oome) {
+                     oom = oome;
+                     Skip(len);
+                 }
+             }
+         }
+ 
+         if (oom != null)
+             throw oom;
+ 
+         return answer;
+     }
+ 
+     public PGStream enableSSL(boolean requireSSL, Properties info, Logger logger) throws IOException, SQLException {
+         if (logger.logDebug())
+             logger.debug(" FE=> SSLRequest");
+ 
+         // Send SSL request packet
+         SendInteger4(8);
+         SendInteger2(1234);
+         SendInteger2(5679);
+         flush();
+ 
+         // Now get the response from the backend, one of N, E, S.
+         int beresp = ReceiveChar();
+         switch (beresp)
+         {
+         case 'E':
+             if (logger.logDebug())
+                 logger.debug(" <=BE SSLError");
+ 
+             // Server doesn't even know about the SSL handshake protocol
+             if (requireSSL)
+                 throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
+ 
+             // We have to reconnect to continue.
+             return reconnect(true);
+ 
+         case 'N':
+             if (logger.logDebug())
+                 logger.debug(" <=BE SSLRefused");
+ 
+             // Server does not support ssl
+             if (requireSSL)
+                 throw new PSQLException(GT.tr("The server does not support SSL."), PSQLState.CONNECTION_REJECTED);
+ 
+             return this;
+ 
+         case 'S':
+             if (logger.logDebug())
+                 logger.debug(" <=BE SSLOk");
+ 
+             // Server supports ssl
+             org.postgresql.ssl.MakeSSL.convert(this, info, logger);
+             return this;
+ 
+         default:
+             throw new PSQLException(GT.tr("An error occured while setting up the SSL connection."), PSQLState.PROTOCOL_VIOLATION);
+         }
+     }
+ 
+     public String getHost() {
+         return host;
+     }
+ 
+     public int getPort() {
+         return port;
+     }
+ 
+     /**
+      * Send a fixed-size array of bytes to the backend. If buf.length < siz,
+      * pad with zeros. If buf.lengh > siz, truncate the array.
+      *
+      * @param buf the array of bytes to be sent
+      * @param siz the number of bytes to be sent
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void Send(byte buf[], int siz) throws IOException
+     {
+         Send(buf, 0, siz);
+     }
+ 
+     /**
+      * Reads in a given number of bytes from the backend
+      *
+      * @param siz number of bytes to read
+      * @return array of bytes received
+      * @exception java.io.IOException if a data I/O error occurs
+      */
+     public byte[] Receive(int siz) throws IOException
+     {
+         byte[] answer = new byte[siz];
+         Receive(answer, 0, siz);
+         return answer;
+     }
+ 
+     /**
+      * Copy data from an input stream to the connection.
+      *
+      * @param inStream the stream to read data from
+      * @param remaining the number of bytes to copy
+      */
+     public void SendStream(InputStream inStream, int remaining) throws IOException {
+         int expectedLength = remaining;
+         if (streamBuffer == null)
+             streamBuffer = new byte[8192];
+ 
+         while (remaining > 0)
+         {
+             int count = (remaining > streamBuffer.length ? streamBuffer.length : remaining);
+             int readCount;
+ 
+             try
+             {
+                 readCount = inStream.read(streamBuffer, 0, count);
+                 if (readCount < 0)
+                     throw new EOFException(GT.tr("Premature end of input stream, expected {0} bytes, but only read {1}.", new Object[]{new Integer(expectedLength), new Integer(expectedLength - remaining)}));
+             }
+             catch (IOException ioe)
+             {
+                 while (remaining > 0)
+                 {
+                     Send(streamBuffer, count);
+                     remaining -= count;
+                     count = (remaining > streamBuffer.length ? streamBuffer.length : remaining);
+                 }
+                 throw new PGBindException(ioe);
+             }
+ 
+             Send(streamBuffer, readCount);
+             remaining -= readCount;
+         }
+     }
+ }
*** /var/empty	1970-01-01 03:00:00.000000000 +0300
--- org/postgresql/core/PGNIOStream.java	2012-01-20 00:44:42.594702723 +0200
***************
*** 0 ****
--- 1,537 ----
+ /*-------------------------------------------------------------------------
+ *
+ * Copyright (c) 2003-2012, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   $PostgreSQL: pgjdbc/org/postgresql/core/PGStream.java,v 1.24 2011/08/02 13:40:12 davecramer Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+ package org.postgresql.core;
+ 
+ import org.postgresql.util.GT;
+ import org.postgresql.util.PSQLException;
+ import org.postgresql.util.PSQLState;
+ 
+ import java.io.*;
+ import java.net.InetSocketAddress;
+ import java.net.Socket;
+ import java.nio.ByteBuffer;
+ import java.nio.ByteOrder;
+ import java.nio.channels.SelectionKey;
+ import java.nio.channels.Selector;
+ import java.nio.channels.SocketChannel;
+ import java.sql.SQLException;
+ import java.util.PriorityQueue;
+ 
+ /**
+  * PGStream implementation using java NIO v1
+  */
+ public class PGNIOStream extends AbstractPGStream {
+ 
+     private SocketChannel connection;
+     private SelectionKey readWriteSelectionKey, readSelectionKey, writeSelectionKey;
+     private ByteBuffer pg_input;
+     private ByteBuffer pg_output;
+     private StreamReadListener readListener;
+     private final PriorityQueue<DelayedTask> taskQueue = new PriorityQueue<DelayedTask>();
+ 
+     private Encoding encoding;
+ 
+     /**
+      * Constructor:  Connect to the PostgreSQL back end and return
+      * a stream connection.
+      *
+      * @param host the hostname to connect to
+      * @param port the port number that the postmaster is sitting on
+      * @exception java.io.IOException if an IOException occurs below it.
+      */
+     public PGNIOStream(String host, int port) throws IOException
+     {
+         super(host, port);
+ 
+         // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
+         pg_input = ByteBuffer.allocate(8192).order(ByteOrder.BIG_ENDIAN);
+         pg_output = ByteBuffer.allocate(8192).order(ByteOrder.BIG_ENDIAN);
+ 
+         setEncoding(Encoding.getJVMEncoding("US-ASCII"));
+ 
+         changeSocket(SocketChannel.open(new InetSocketAddress(host, port)).socket());
+     }
+ 
+     public Socket getSocket() {
+         return connection.socket();
+     }
+ 
+     /**
+      * Sets new read listener
+      * @param newListener read listener to set
+      * @return old read listener
+      */
+     public StreamReadListener readListener(StreamReadListener newListener) throws IOException {
+         StreamReadListener rc = readListener;
+         readListener = newListener;
+         if (rc == null ^ newListener == null) {
+             if (readWriteSelectionKey != null)
+                 readWriteSelectionKey.selector().close();
+ 
+             readWriteSelectionKey = connection.register(Selector.open(),
+                     readListener == null ? SelectionKey.OP_WRITE : SelectionKey.OP_READ | SelectionKey.OP_WRITE);
+         }
+         return rc;
+     }
+ 
+     public void addTimerTask(Runnable timerTask, long milliSeconds) {
+         long startTime = System.currentTimeMillis() + milliSeconds;
+         synchronized (taskQueue) {
+             taskQueue.add(new DelayedTask(timerTask, startTime));
+         }
+     }
+ 
+     /**
+      * Check for pending backend messages without blocking.
+      * Might return false when there actually are messages
+      * waiting, depending on the characteristics of the
+      * underlying socket. This is used to detect asynchronous
+      * notifies from the backend, when available.
+      *
+      * @return true if there is a pending backend message
+      */
+     public boolean hasMessagePending() throws IOException {
+         tryRead(readSelectionKey);
+         return pg_input.hasRemaining();
+     }
+ 
+     /**
+      * Switch this stream to using a new socket. Any existing socket
+      * is <em>not</em> closed; it's assumed that we are changing to
+      * a new socket that delegates to the original socket (e.g. SSL).
+      *
+      * @param socket the new socket to change to
+      * @throws java.io.IOException if something goes wrong
+      */
+     public void changeSocket(Socket socket) throws IOException {
+         this.connection = socket.getChannel();
+ 
+         connection.configureBlocking(false);
+ 
+         // Submitted by Jason Venner <jason@idiom.com>. Disable Nagle
+         // as we are selective about flushing output only when we
+         // really need to.
+         socket.setTcpNoDelay(true);
+ 
+         pg_input.clear().limit(0);
+         pg_output.clear();
+ 
+         if (readSelectionKey != null)
+             readSelectionKey.selector().close();
+         readSelectionKey = connection.register(Selector.open(), SelectionKey.OP_READ);
+ 
+         if (readWriteSelectionKey != null)
+             readWriteSelectionKey.selector().close();
+         readWriteSelectionKey = connection.register(Selector.open(), SelectionKey.OP_READ | SelectionKey.OP_WRITE);
+ 
+         if (writeSelectionKey != null)
+             writeSelectionKey.selector().close();
+         writeSelectionKey = connection.register(Selector.open(), SelectionKey.OP_WRITE);
+     }
+ 
+     public Encoding getEncoding() {
+         return encoding;
+     }
+ 
+     /**
+      * Change the encoding used by this connection.
+      *
+      * @param encoding the new encoding to use
+      * @throws java.io.IOException if something goes wrong
+      */
+     public void setEncoding(Encoding encoding) throws IOException {
+         this.encoding = encoding;
+     }
+ 
+     /**
+      * This writer is used by V2 connections only
+      * and we don't support this type of stream for V2
+      *
+      * @throws UnsupportedOperationException
+      */
+     public Writer getEncodingWriter() throws IOException {
+         throw new UnsupportedOperationException();
+     }
+ 
+     /**
+      * Sends a single character to the back end
+      *
+      * @param val the character to be sent
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void SendChar(int val) throws IOException
+     {
+         ensureWriteSpace(1);
+         pg_output.put((byte) val);
+     }
+ 
+     /**
+      * Sends a 4-byte integer to the back end
+      *
+      * @param val the integer to be sent
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void SendInteger4(int val) throws IOException
+     {
+         pg_output.putInt(val);
+     }
+ 
+     /**
+      * Sends a 2-byte integer (short) to the back end
+      *
+      * @param val the integer to be sent
+      * @exception java.io.IOException if an I/O error occurs or <code>val</code> cannot be encoded in 2 bytes
+      */
+     public void SendInteger2(int val) throws IOException
+     {
+         if (val < Short.MIN_VALUE || val > Short.MAX_VALUE)
+             throw new IOException("Tried to send an out-of-range integer as a 2-byte value: " + val);
+ 
+         pg_output.putShort((short) val);
+     }
+ 
+     /**
+      * Send an array of bytes to the backend
+      *
+      * @param buf The array of bytes to be sent
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void Send(byte buf[]) throws IOException
+     {
+         Send(buf, buf.length);
+     }
+ 
+     /**
+      * Send a fixed-size array of bytes to the backend. If length < siz,
+      * pad with zeros. If length > siz, truncate the array.
+      *
+      * @param buf the array of bytes to be sent
+      * @param off offset in the array to start sending from
+      * @param siz the number of bytes to be sent
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void Send(byte buf[], int off, int siz) throws IOException
+     {
+         if (siz <= pg_output.remaining()) {
+             pg_output.put(buf, off, siz);
+             return;
+         }
+     	int bufamt = buf.length - off;
+         int sendSize = bufamt < siz ? bufamt : siz;
+         flush();
+         Send(ByteBuffer.wrap(buf, off, sendSize));
+         for (int i = bufamt ; i < siz ; ++i)
+         {
+             SendChar(0);
+         }
+     }
+ 
+     /**
+      * Sends all data available in ByteBuffer. Clears buffer afterwards
+      */
+     private void Send(ByteBuffer buffer) throws IOException {
+         SelectionKey selectionKey = readListener != null ? readWriteSelectionKey : writeSelectionKey;
+         while (buffer.hasRemaining()) {
+             if (connection.write(buffer) == 0) {
+                 if (readListener != null) {
+                     tryRead(selectionKey);
+                     if (pg_input.hasRemaining()) {
+                         while (pg_input.hasRemaining())
+                             readListener.canRead();
+                     } else {
+                         select(selectionKey);
+                     }
+                 }
+             }
+         }
+         buffer.clear();
+     }
+ 
+     /**
+      * Receives a single character from the backend, without
+      * advancing the current protocol stream position.
+      *
+      * @return the character received
+      * @exception java.io.IOException if an I/O Error occurs
+      */
+     public int PeekChar() throws IOException
+     {
+         ensureReadData(1);
+         return pg_input.get(pg_input.position());
+     }
+ 
+     /**
+      * Receives a single character from the backend
+      *
+      * @return the character received
+      * @exception java.io.IOException if an I/O Error occurs
+      */
+     public int ReceiveChar() throws IOException
+     {
+         ensureReadData(1);
+         return pg_input.get();
+     }
+ 
+     /**
+      * Receives a four byte integer from the backend
+      *
+      * @return the integer received from the backend
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public int ReceiveInteger4() throws IOException
+     {
+         ensureReadData(4);
+         return pg_input.getInt();
+     }
+ 
+     /**
+      * Receives a two byte integer from the backend
+      *
+      * @return the integer received from the backend
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public int ReceiveInteger2() throws IOException
+     {
+         ensureReadData(2);
+         return pg_input.getShort();
+     }
+ 
+     /**
+      * Receives a fixed-size string from the backend.
+      *
+      * @param len the length of the string to receive, in bytes.
+      * @return the decoded string
+      */
+     public String ReceiveString(int len) throws IOException {
+         ensureReadData(len);
+         String res = encoding.decode(pg_input.array(), pg_input.arrayOffset() + pg_input.position(),
+                                      len);
+         pg_input.position(pg_input.position() + len);
+         return res;
+     }
+ 
+     /**
+      * Receives a null-terminated string from the backend. If we don't see a
+      * null, then we assume something has gone wrong.
+      *
+      * @return string from back end
+      * @exception java.io.IOException if an I/O error occurs, or end of file
+      */
+     public String ReceiveString() throws IOException
+     {
+         String rc = ReceiveString(scanCStringLength());
+         pg_input.position(pg_input.position() + 1);
+         return rc;
+     }
+ 
+     /**
+      * Ensures pg_input has full C-style string (0-ended)
+      * @return full C-String length, not including 0 byte
+      * @throws java.io.IOException if an I/O error occurs, or end of file
+      */
+     private int scanCStringLength() throws IOException {
+         for (int i = 0;; i++) {
+             if (pg_input.remaining() < i) {
+                 ensureReadData(i + VisibleBufferedInputStream.STRING_SCAN_SPAN);
+             }
+             if (pg_input.get(pg_input.position() + i) == 0)
+                 return i;
+         }
+     }
+ 
+     private void tryRead(SelectionKey selectionKey) throws IOException {
+         if (pg_input.hasRemaining())
+             return;
+         pg_input.clear();
+         try {
+             tryRead(pg_input, selectionKey);
+         }finally {
+             pg_input.flip();
+         }
+     }
+ 
+     private void ensureWriteSpace(int bytes) throws IOException {
+         if (pg_output.remaining() < bytes)
+             flush();
+     }
+ 
+     /**
+      * Ensures input has required number of bytes
+      * @param len how many bytes should be in buffer on exit
+      * @throws IOException if an I/O error occurs, or end of file
+      */
+     private void ensureReadData(int len) throws IOException{
+         if (pg_input.remaining() >= len)
+             return;
+         if (!pg_input.hasRemaining())
+             pg_input.clear().limit(0);
+         int startPosition = 0;
+         if (pg_input.capacity() < len) {
+             pg_input = ByteBuffer.allocate(Math.max(len, pg_input.capacity() * 2)).put(pg_input);
+         } else if (pg_input.capacity() - pg_input.position() < len) {
+             pg_input.compact();
+         } else {
+             startPosition = pg_input.position();
+             pg_input.position(startPosition + pg_input.remaining()).limit(pg_input.capacity());
+ 
+         }
+         try {
+             while (pg_input.position() - startPosition < len) {
+                 blockingRead(pg_input);
+             }
+         }finally {
+             pg_input.flip().position(startPosition);
+         }
+     }
+ 
+     private void blockingRead(ByteBuffer buffer) throws IOException {
+         if (tryRead(buffer, readSelectionKey) > 0)
+             return;
+         select(readSelectionKey);
+         if (tryRead(buffer, readSelectionKey) == 0)
+             throw new IOException("Can't read anything after select");
+     }
+ 
+     private int tryRead(ByteBuffer buffer, SelectionKey selectionKey) throws IOException {
+         int read = connection.read(buffer);
+         if (read == 0) {
+             readSelectionKey.selector().selectedKeys().remove(selectionKey);
+         } else  if (read < 0)
+             throw new EOFException();
+         return read;
+     }
+ 
+     private int select(SelectionKey selectionKey) throws IOException {
+         int selected;
+         do {
+             long timeout = runQueue();
+             selected = selectionKey.selector().select(timeout);
+         } while (selected == 0);
+         return selectionKey.readyOps();
+     }
+ 
+     private long runQueue() {
+         synchronized (taskQueue) {
+             for (DelayedTask task = taskQueue.peek(); task != null; task = taskQueue.peek()) {
+                 long timeout = task.runTime - System.currentTimeMillis();
+                 if (timeout <= 0) {
+                     taskQueue.poll().task.run();
+                 } else {
+                     return timeout;
+                 }
+             }
+         }
+         return 0;
+     }
+ 
+     /**
+      * Reads in a given number of bytes from the backend
+      *
+      * @param buf buffer to store result
+      * @param off offset in buffer
+      * @param siz number of bytes to read
+      * @exception java.io.IOException if a data I/O error occurs
+      */
+     public void Receive(byte[] buf, int off, int siz) throws IOException
+     {
+         if (siz <= pg_input.remaining()) {
+             pg_input.get(buf, off, siz);
+             return;
+         }
+         if (siz < VisibleBufferedInputStream.MINIMUM_READ) {
+             ensureReadData(siz);
+             pg_input.get(buf, off, siz);
+             return;
+         }
+         ByteBuffer buffer = ByteBuffer.wrap(buf, off, siz);
+         buffer.put(pg_input);
+         while (buffer.hasRemaining())
+             blockingRead(buffer);
+     }
+ 
+     public void Skip(int size) throws IOException {
+         while (size > 0) {
+             if (pg_input.remaining() > size) {
+                 pg_input.position(pg_input.position() + size);
+                 return;
+             }
+             size -= pg_input.remaining();
+             pg_input.clear().limit(0);
+             ensureReadData(Math.min(size, pg_input.capacity()));
+         }
+     }
+ 
+ 
+     /**
+      * Flush any pending output to the backend.
+      * @exception java.io.IOException if an I/O error occurs
+      */
+     public void flush() throws IOException
+     {
+         pg_output.flip();
+         Send(pg_output);
+     }
+ 
+     /**
+      * Consume an expected EOF from the backend
+      * @exception java.sql.SQLException if we get something other than an EOF
+      */
+     public void ReceiveEOF() throws SQLException, IOException
+     {
+         try {
+             throw new PSQLException(GT.tr("Expected an EOF from server, got: {0}", new Integer(PeekChar())), PSQLState.COMMUNICATION_ERROR);
+         } catch (EOFException e) {
+             return;
+         }
+     }
+ 
+     /**
+      * Closes the connection
+      *
+      * @exception java.io.IOException if an I/O Error occurs
+      */
+     public void close() throws IOException
+     {
+         if (readSelectionKey != null) {
+             readSelectionKey.selector().close();
+             readSelectionKey = null;
+         }
+         if (readWriteSelectionKey != null) {
+             readWriteSelectionKey.selector().close();
+             readWriteSelectionKey = null;
+         }
+         if (writeSelectionKey != null) {
+             writeSelectionKey.selector().close();
+             writeSelectionKey = null;
+         }
+         connection.close();
+     }
+ 
+     public PGStream reconnect(boolean closeOriginal) throws IOException {
+         if (closeOriginal)
+             close();
+ 
+         return new PGNIOStream(getHost(), getPort());
+     }
+ 
+     public static class DelayedTask implements Comparable<DelayedTask>{
+         private final Runnable task;
+         private final long runTime;
+ 
+         public DelayedTask(Runnable task, long runTime) {
+             this.task = task;
+             this.runTime = runTime;
+         }
+ 
+         public int compareTo(DelayedTask o) {
+             return runTime  < o.runTime ? -1 : runTime == o.runTime ? 0 : 1;
+         }
+     }
+ }
*** /var/empty	1970-01-01 03:00:00.000000000 +0300
--- org/postgresql/core/PGRegularStream.java	2012-01-20 00:44:42.594702723 +0200
***************
*** 0 ****
--- 1,397 ----
+ /*-------------------------------------------------------------------------
+ *
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   $PostgreSQL: pgjdbc/org/postgresql/core/PGStream.java,v 1.24 2011/08/02 13:40:12 davecramer Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+ package org.postgresql.core;
+ 
+ import org.postgresql.Driver;
+ import java.io.BufferedOutputStream;
+ import java.io.InputStream;
+ import java.io.OutputStream;
+ import java.io.FilterOutputStream;
+ import java.io.IOException;
+ import java.io.EOFException;
+ import java.io.Writer;
+ import java.net.Socket;
+ import java.sql.*;
+ import java.util.TimerTask;
+ 
+ import org.postgresql.util.GT;
+ import org.postgresql.util.PSQLState;
+ import org.postgresql.util.PSQLException;
+ 
+ /**
+  * PGStream implementation using regular Stream-based sockets
+  */
+ public class PGRegularStream extends AbstractPGStream {
+     private final byte[] _int4buf;
+     private final byte[] _int2buf;
+ 
+     private Socket connection;
+     private VisibleBufferedInputStream pg_input;
+     private OutputStream pg_output;
+ 
+     private Encoding encoding;
+     private Writer encodingWriter;
+ 
+     /**
+      * Constructor:  Connect to the PostgreSQL back end and return
+      * a stream connection.
+      *
+      * @param host the hostname to connect to
+      * @param port the port number that the postmaster is sitting on
+      * @exception IOException if an IOException occurs below it.
+      */
+     public PGRegularStream(String host, int port) throws IOException
+     {
+         super(host, port);
+ 
+         changeSocket(new Socket(host, port));
+         setEncoding(Encoding.getJVMEncoding("US-ASCII"));
+ 
+         _int2buf = new byte[2];
+         _int4buf = new byte[4];
+     }
+ 
+     public Socket getSocket() {
+         return connection;
+     }
+ 
+     /**
+      * Check for pending backend messages without blocking.
+      * Might return false when there actually are messages
+      * waiting, depending on the characteristics of the
+      * underlying socket. This is used to detect asynchronous
+      * notifies from the backend, when available.
+      *
+      * @return true if there is a pending backend message
+      */
+     public boolean hasMessagePending() throws IOException {
+         return pg_input.available() > 0 || connection.getInputStream().available() > 0;
+     }
+ 
+     /**
+      * Switch this stream to using a new socket. Any existing socket
+      * is <em>not</em> closed; it's assumed that we are changing to
+      * a new socket that delegates to the original socket (e.g. SSL).
+      *
+      * @param socket the new socket to change to
+      * @throws IOException if something goes wrong
+      */
+     public void changeSocket(Socket socket) throws IOException {
+         this.connection = socket;
+ 
+         // Submitted by Jason Venner <jason@idiom.com>. Disable Nagle
+         // as we are selective about flushing output only when we
+         // really need to.
+         connection.setTcpNoDelay(true);
+ 
+         // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
+         pg_input = new VisibleBufferedInputStream(connection.getInputStream(), 8192);
+         pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
+ 
+         if (encoding != null)
+             setEncoding(encoding);
+     }
+ 
+     public Encoding getEncoding() {
+         return encoding;
+     }
+ 
+     /**
+      * Change the encoding used by this connection.
+      *
+      * @param encoding the new encoding to use
+      * @throws IOException if something goes wrong
+      */
+     public void setEncoding(Encoding encoding) throws IOException {
+         // Close down any old writer.
+         if (encodingWriter != null)
+             encodingWriter.close();
+ 
+         this.encoding = encoding;
+ 
+         // Intercept flush() downcalls from the writer; our caller
+         // will call PGStream.flush() as needed.
+         OutputStream interceptor = new FilterOutputStream(pg_output) {
+                                        public void flush() throws IOException {
+                                        }
+                                        public void close() throws IOException {
+                                            super.flush();
+                                        }
+                                    };
+ 
+         encodingWriter = encoding.getEncodingWriter(interceptor);
+     }
+ 
+     /**
+      * Get a Writer instance that encodes directly onto the underlying stream.
+      *<p>
+      * The returned Writer should not be closed, as it's a shared object.
+      * Writer.flush needs to be called when switching between use of the Writer and
+      * use of the PGStream write methods, but it won't actually flush output
+      * all the way out -- call {@link #flush} to actually ensure all output
+      * has been pushed to the server.
+      *
+      * @return the shared Writer instance
+      * @throws IOException if something goes wrong.
+      */
+     public Writer getEncodingWriter() throws IOException {
+         if (encodingWriter == null)
+             throw new IOException("No encoding has been set on this connection");
+         return encodingWriter;
+     }
+ 
+     /**
+      * Sends a single character to the back end
+      *
+      * @param val the character to be sent
+      * @exception IOException if an I/O error occurs
+      */
+     public void SendChar(int val) throws IOException
+     {
+         pg_output.write(val);
+     }
+ 
+     /**
+      * Sends a 4-byte integer to the back end
+      *
+      * @param val the integer to be sent
+      * @exception IOException if an I/O error occurs
+      */
+     public void SendInteger4(int val) throws IOException
+     {
+         _int4buf[0] = (byte)(val >>> 24);
+         _int4buf[1] = (byte)(val >>> 16);
+         _int4buf[2] = (byte)(val >>> 8);
+         _int4buf[3] = (byte)(val);
+         pg_output.write(_int4buf);
+     }
+ 
+     /**
+      * Sends a 2-byte integer (short) to the back end
+      *
+      * @param val the integer to be sent
+      * @exception IOException if an I/O error occurs or <code>val</code> cannot be encoded in 2 bytes
+      */
+     public void SendInteger2(int val) throws IOException
+     {
+         if (val < Short.MIN_VALUE || val > Short.MAX_VALUE)
+             throw new IOException("Tried to send an out-of-range integer as a 2-byte value: " + val);
+ 
+         _int2buf[0] = (byte)(val >>> 8);
+         _int2buf[1] = (byte)val;
+         pg_output.write(_int2buf);
+     }
+ 
+     /**
+      * Send an array of bytes to the backend
+      *
+      * @param buf The array of bytes to be sent
+      * @exception IOException if an I/O error occurs
+      */
+     public void Send(byte buf[]) throws IOException
+     {
+         pg_output.write(buf);
+     }
+ 
+     /**
+      * Send a fixed-size array of bytes to the backend. If length < siz,
+      * pad with zeros. If length > siz, truncate the array.
+      *
+      * @param buf the array of bytes to be sent
+      * @param off offset in the array to start sending from
+      * @param siz the number of bytes to be sent
+      * @exception IOException if an I/O error occurs
+      */
+     public void Send(byte buf[], int off, int siz) throws IOException
+     {
+ 	int bufamt = buf.length - off;
+         pg_output.write(buf, off, bufamt < siz ? bufamt : siz);
+         for (int i = bufamt ; i < siz ; ++i)
+         {
+             pg_output.write(0);
+         }
+     }
+ 
+     /**
+      * Receives a single character from the backend, without
+      * advancing the current protocol stream position.
+      *
+      * @return the character received
+      * @exception IOException if an I/O Error occurs
+      */
+     public int PeekChar() throws IOException
+     {
+         int c = pg_input.peek();
+         if (c < 0)
+             throw new EOFException();
+         return c;
+     }
+ 
+     /**
+      * Receives a single character from the backend
+      *
+      * @return the character received
+      * @exception IOException if an I/O Error occurs
+      */
+     public int ReceiveChar() throws IOException
+     {
+         int c = pg_input.read();
+         if (c < 0)
+             throw new EOFException();
+         return c;
+     }
+ 
+     /**
+      * Receives a four byte integer from the backend
+      *
+      * @return the integer received from the backend
+      * @exception IOException if an I/O error occurs
+      */
+     public int ReceiveInteger4() throws IOException
+     {
+         if (pg_input.read(_int4buf) != 4)
+             throw new EOFException();
+ 
+         return (_int4buf[0] & 0xFF) << 24 | (_int4buf[1] & 0xFF) << 16 | (_int4buf[2] & 0xFF) << 8 | _int4buf[3] & 0xFF;
+     }
+ 
+     /**
+      * Receives a two byte integer from the backend
+      *
+      * @return the integer received from the backend
+      * @exception IOException if an I/O error occurs
+      */
+     public int ReceiveInteger2() throws IOException
+     {
+         if (pg_input.read(_int2buf) != 2)
+             throw new EOFException();
+ 
+         return (_int2buf[0] & 0xFF) << 8 | _int2buf[1] & 0xFF;
+     }
+ 
+     /**
+      * Receives a fixed-size string from the backend.
+      *
+      * @param len the length of the string to receive, in bytes.
+      * @return the decoded string
+      */
+     public String ReceiveString(int len) throws IOException {
+         if (!pg_input.ensureBytes(len)) {
+             throw new EOFException();
+         }
+ 
+         String res = encoding.decode(pg_input.getBuffer(), pg_input.getIndex(),
+                 len);
+         pg_input.skip(len);
+         return res;
+     }
+ 
+     /**
+      * Receives a null-terminated string from the backend. If we don't see a
+      * null, then we assume something has gone wrong.
+      *
+      * @return string from back end
+      * @exception IOException if an I/O error occurs, or end of file
+      */
+     public String ReceiveString() throws IOException
+     {
+         int len = pg_input.scanCStringLength();
+         String res = encoding.decode(pg_input.getBuffer(), pg_input.getIndex(),
+                 len - 1);
+         pg_input.skip(len);
+         return res;
+     }
+ 
+     /**
+      * Reads in a given number of bytes from the backend
+      *
+      * @param buf buffer to store result
+      * @param off offset in buffer
+      * @param siz number of bytes to read
+      * @exception IOException if a data I/O error occurs
+      */
+     public void Receive(byte[] buf, int off, int siz) throws IOException
+     {
+         int s = 0;
+ 
+         while (s < siz)
+         {
+             int w = pg_input.read(buf, off + s, siz - s);
+             if (w < 0)
+                 throw new EOFException();
+             s += w;
+         }
+     }
+ 
+     public void Skip(int size) throws IOException {
+         long s = 0;
+         while (s < size) {
+             s += pg_input.skip(size - s);
+         }
+     }
+ 
+     /**
+      * Flush any pending output to the backend.
+      * @exception IOException if an I/O error occurs
+      */
+     public void flush() throws IOException
+     {
+         if (encodingWriter != null)
+             encodingWriter.flush();
+         pg_output.flush();
+     }
+ 
+     /**
+      * Consume an expected EOF from the backend
+      * @exception SQLException if we get something other than an EOF
+      */
+     public void ReceiveEOF() throws SQLException, IOException
+     {
+         int c = pg_input.read();
+         if (c < 0)
+             return;
+         throw new PSQLException(GT.tr("Expected an EOF from server, got: {0}", new Integer(c)), PSQLState.COMMUNICATION_ERROR);
+     }
+ 
+     /**
+      * Closes the connection
+      *
+      * @exception IOException if an I/O Error occurs
+      */
+     public void close() throws IOException
+     {
+         if (encodingWriter != null)
+             encodingWriter.close();
+ 
+         pg_output.close();
+         pg_input.close();
+         connection.close();
+     }
+ 
+     public PGStream reconnect(boolean closeOriginal) throws IOException {
+         if (closeOriginal)
+             close();
+ 
+         return new PGRegularStream(getHost(), getPort());
+     }
+ 
+     public StreamReadListener readListener(StreamReadListener newListener) {
+         return null;
+     }
+ 
+     public void addTimerTask(final Runnable timerTask, long milliSeconds) {
+         Driver.addTimerTask(new TimerTask() {
+             @Override
+             public void run() {
+                 timerTask.run();
+             }
+         }, milliSeconds);
+     }
+ }
*** /var/empty	1970-01-01 03:00:00.000000000 +0300
--- org/postgresql/core/StreamReadListener.java	2012-01-16 22:41:24.930708430 +0200
***************
*** 0 ****
--- 1,8 ----
+ package org.postgresql.core;
+ 
+ /**
+  * This is callback that will be called when data is available to read from PGStream
+  */
+ public interface StreamReadListener {
+     void canRead();
+ }
