List:Commits« Previous MessageNext Message »
From:eherman Date:January 15 2008 9:56pm
Subject:Connector/J commit: r6710 - in trunk/src/com/mysql/jdbc: . jdbc2/optional
View as plain text  
Added:
   trunk/src/com/mysql/jdbc/MysqlIO.java
   trunk/src/com/mysql/jdbc/MysqlIOprotocol.java
Removed:
   trunk/src/com/mysql/jdbc/MysqlIO.java
Modified:
   trunk/src/com/mysql/jdbc/Buffer.java
   trunk/src/com/mysql/jdbc/ConnectionImpl.java
   trunk/src/com/mysql/jdbc/ConnectionProperties.java
   trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
   trunk/src/com/mysql/jdbc/DatabaseMetaData.java
   trunk/src/com/mysql/jdbc/DatabaseMetaDataUsingInfoSchema.java
   trunk/src/com/mysql/jdbc/ExportControlled.java
   trunk/src/com/mysql/jdbc/RowDataCursor.java
   trunk/src/com/mysql/jdbc/RowDataDynamic.java
   trunk/src/com/mysql/jdbc/ServerPreparedStatement.java
   trunk/src/com/mysql/jdbc/StatementImpl.java
   trunk/src/com/mysql/jdbc/jdbc2/optional/ConnectionWrapper.java
Log:
interface-izing MysqlIO; 
added StringConnectionProperty 'mysqlIOFactory' defaults to MysqlIOprotocol.class.getName()

Modified: trunk/src/com/mysql/jdbc/Buffer.java
===================================================================
--- trunk/src/com/mysql/jdbc/Buffer.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/Buffer.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -57,11 +57,11 @@
 	Buffer(int size) {
 		this.byteBuffer = new byte[size];
 		setBufLength(this.byteBuffer.length);
-		this.position = MysqlIO.HEADER_LENGTH;
+		this.position = MysqlIOprotocol.HEADER_LENGTH;
 	}
 
 	final void clear() {
-		this.position = MysqlIO.HEADER_LENGTH;
+		this.position = MysqlIOprotocol.HEADER_LENGTH;
 	}
 
 	final void dump() {
@@ -92,7 +92,7 @@
 	}
 
 	final void dumpHeader() {
-		for (int i = 0; i < MysqlIO.HEADER_LENGTH; i++) {
+		for (int i = 0; i < MysqlIOprotocol.HEADER_LENGTH; i++) {
 			String hexVal = Integer.toHexString(readByte(i) & 0xff);
 
 			if (hexVal.length() == 1) {

Modified: trunk/src/com/mysql/jdbc/ConnectionImpl.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionImpl.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/ConnectionImpl.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -75,6 +75,9 @@
 		Connection {
 	private static final String JDBC_LOCAL_CHARACTER_SET_RESULTS = "jdbc.local.character_set_results";
 	
+    public static final int INITIAL_MAX_BUFFER_SIZE = 65535;
+
+	
 	/**
 	 * Used as a key for caching callable statements which (may) depend on
 	 * current catalog...In 5.0.x, they don't (currently), but stored procedure
@@ -1641,13 +1644,13 @@
 					// Fault injection for testing server character set indices
 		            
 		            if (props != null && props.getProperty("com.mysql.jdbc.faultInjection.serverCharsetIndex") != null) {
-		            	this.io.serverCharsetIndex = Integer.parseInt(
+		            	this.io.setServerCharsetIndex(Integer.parseInt(
 		            			props.getProperty(
-		            					"com.mysql.jdbc.faultInjection.serverCharsetIndex"));	
+		            					"com.mysql.jdbc.faultInjection.serverCharsetIndex")));	
 		            }
 		            
 					String serverEncodingToSet = 
-						CharsetMapping.INDEX_TO_CHARSET[this.io.serverCharsetIndex];
+						CharsetMapping.INDEX_TO_CHARSET[this.io.serverCharsetIndex()];
 					
 					if (serverEncodingToSet == null || serverEncodingToSet.length() == 0) {
 						if (realJavaEncoding != null) {
@@ -1656,7 +1659,7 @@
 						} else {
 							throw SQLError.createSQLException(
 									"Unknown initial character set index '"
-											+ this.io.serverCharsetIndex
+											+ this.io.serverCharsetIndex()
 											+ "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
 									SQLError.SQL_STATE_GENERAL_ERROR);
 						}
@@ -1677,7 +1680,7 @@
 					} else {
 						throw SQLError.createSQLException(
 								"Unknown initial character set index '"
-										+ this.io.serverCharsetIndex
+										+ this.io.serverCharsetIndex()
 										+ "' received from server. Initial client character set can be forced via the 'characterEncoding' property.",
 								SQLError.SQL_STATE_GENERAL_ERROR);
 					}
@@ -2029,7 +2032,8 @@
 								}
 							}
 	
-							this.io = new MysqlIO(newHost, newPort, mergedProps,
+							this.io = newMysqlIO(newHost, 
+							        newPort, mergedProps, getMysqlIOFactory(),
 									getSocketFactoryClassName(), this,
 									getSocketTimeout(), 
 									this.largeRowSizeThreshold.getValueAsInt());
@@ -2178,8 +2182,9 @@
 									}
 								}
 	
-								this.io = new MysqlIO(newHost, newPort,
-										mergedProps, getSocketFactoryClassName(),
+								this.io = newMysqlIO(newHost, newPort,
+										mergedProps, getMysqlIOFactory(),
+										getSocketFactoryClassName(),
 										this, getSocketTimeout(),
 										this.largeRowSizeThreshold.getValueAsInt());
 								this.io.doHandshake(this.user, this.password,
@@ -5489,4 +5494,20 @@
 	public void initializeExtension(Extension ex) throws SQLException {
 		ex.init(this, this.props);
 	}
+
+    private MysqlIO newMysqlIO(String host1, int port1, Properties props1,
+        String getMysqlIOFactory, 
+        String socketFactoryClassName, ConnectionImpl conn, int socketTimeout,
+        int largeRowSizeThreshold1) throws IOException, SQLException {
+        
+        Class[] argTypes = new Class[] { String.class, int.class,
+            Properties.class, String.class, ConnectionImpl.class, int.class,
+            int.class };
+        
+        Object[] args = new Object[] { host1, new Integer(port1), props1,
+            socketFactoryClassName, conn, new Integer(socketTimeout),
+            new Integer(largeRowSizeThreshold1) };
+
+        return (MysqlIO) Util.getInstance(getMysqlIOFactory, argTypes, args);
+    }
 }
\ No newline at end of file

Modified: trunk/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionProperties.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/ConnectionProperties.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -1594,4 +1594,8 @@
 	public int getSelfDestructOnPingMaxOperations();
 
 	public void setSelfDestructOnPingMaxOperations(int maxOperations);
+
+    public String getMysqlIOFactory();
+
+    public void setMysqlIOFactory(String mysqlIOFactoryClassName);
 }

Modified: trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java
===================================================================
--- trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/ConnectionPropertiesImpl.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -1074,7 +1074,13 @@
 			Integer.MAX_VALUE,
 			Messages.getString("ConnectionProperties.metadataCacheSize"), //$NON-NLS-1$
 			"3.1.1", PERFORMANCE_CATEGORY, 5); //$NON-NLS-1$
-	
+
+	StringConnectionProperty mysqlIOFactory = new StringConnectionProperty(
+           "mysqlIOFactory", //$NON-NLS-1$
+           MysqlIOprotocol.class.getName(),
+           Messages.getString("ConnectionProperties.mysqlIOFactory"), //$NON-NLS-1$
+           "6.0.0", CONNECTION_AND_AUTH_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
+
 	private IntegerConnectionProperty netTimeoutForStreamingResults = new IntegerConnectionProperty(
 			"netTimeoutForStreamingResults", 600, //$NON-NLS-1$
 			0, Integer.MAX_VALUE,
@@ -4358,4 +4364,12 @@
 	public void setSelfDestructOnPingMaxOperations(int maxOperations) {
 		this.selfDestructOnPingMaxOperations.setValue(maxOperations);
 	}
+
+    public String getMysqlIOFactory() {
+        return mysqlIOFactory.getValueAsString();
+    }
+
+    public void setMysqlIOFactory(String mysqlIOFactoryClassName) {
+        this.mysqlIOFactory.setValue(mysqlIOFactoryClassName);
+    }
 }

Modified: trunk/src/com/mysql/jdbc/DatabaseMetaData.java
===================================================================
--- trunk/src/com/mysql/jdbc/DatabaseMetaData.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/DatabaseMetaData.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -389,7 +389,7 @@
 			}
 
 			// BUFFER_LENGTH
-			this.bufferLength = MysqlIO.getMaxBuf();
+			this.bufferLength = ConnectionImpl.INITIAL_MAX_BUFFER_SIZE;
 
 			// NUM_PREC_RADIX (is this right for char?)
 			this.numPrecRadix = 10;
@@ -1329,7 +1329,7 @@
 									rowVal[1] = results.getBytes("Field");
 
 									String type = results.getString("Type");
-									int size = MysqlIO.getMaxBuf();
+									int size = ConnectionImpl.INITIAL_MAX_BUFFER_SIZE;
 									int decimals = 0;
 
 									/*
@@ -3790,7 +3790,7 @@
 	 *             DOCUMENT ME!
 	 */
 	public int getMaxStatementLength() throws SQLException {
-		return MysqlIO.getMaxBuf() - 4; // Max buffer - header
+		return ConnectionImpl.INITIAL_MAX_BUFFER_SIZE - 4; // Max buffer - header
 	}
 
 	/**

Modified: trunk/src/com/mysql/jdbc/DatabaseMetaDataUsingInfoSchema.java
===================================================================
--- trunk/src/com/mysql/jdbc/DatabaseMetaDataUsingInfoSchema.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/DatabaseMetaDataUsingInfoSchema.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -218,7 +218,7 @@
 				.append("CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN NUMERIC_PRECISION ELSE CASE WHEN CHARACTER_MAXIMUM_LENGTH > " 
 						+ Integer.MAX_VALUE + " THEN " + Integer.MAX_VALUE + 
 						" ELSE CHARACTER_MAXIMUM_LENGTH END END AS COLUMN_SIZE, "
-						+ MysqlIO.getMaxBuf() + " AS BUFFER_LENGTH,"
+						+ ConnectionImpl.INITIAL_MAX_BUFFER_SIZE + " AS BUFFER_LENGTH,"
 						+ "NUMERIC_SCALE AS DECIMAL_DIGITS,"
 						+ "10 AS NUM_PREC_RADIX,"
 						+ "CASE WHEN IS_NULLABLE='NO' THEN " + columnNoNulls + " ELSE CASE WHEN IS_NULLABLE='YES' THEN " + columnNullable + " ELSE " + columnNullableUnknown + " END END AS NULLABLE,"

Modified: trunk/src/com/mysql/jdbc/ExportControlled.java
===================================================================
--- trunk/src/com/mysql/jdbc/ExportControlled.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/ExportControlled.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -74,7 +74,7 @@
 	 *             Connector/J doesn't contain the SSL crytpo hooks needed to
 	 *             perform the handshake.
 	 */
-	protected static void transformSocketToSSLSocket(MysqlIO mysqlIO)
+	protected static void transformSocketToSSLSocket(MysqlIOprotocol mysqlIO)
 			throws SQLException {
 		javax.net.ssl.SSLSocketFactory sslFact = getSSLSocketFactoryDefaultOrConfigured(mysqlIO);
 
@@ -110,7 +110,7 @@
 	}
 
 	private static SSLSocketFactory getSSLSocketFactoryDefaultOrConfigured(
-			MysqlIO mysqlIO) throws SQLException {
+	        MysqlIOprotocol mysqlIO) throws SQLException {
 		String clientCertificateKeyStoreUrl = mysqlIO.connection
 				.getClientCertificateKeyStoreUrl();
 		String trustCertificateKeyStoreUrl = mysqlIO.connection

Deleted: trunk/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- trunk/src/com/mysql/jdbc/MysqlIO.java	2008-01-08 05:44:40 UTC (rev 6709)
+++ trunk/src/com/mysql/jdbc/MysqlIO.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -1,4535 +0,0 @@
-/*
-      Copyright (C) 2002-2007 MySQL AB
-
-      This program is free software; you can redistribute it and/or modify
-      it under the terms of version 2 of the GNU General Public License as
-      published by the Free Software Foundation.
-
-      There are special exceptions to the terms and conditions of the GPL
-      as it is applied to this software. View the full text of the
-      exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
-      software distribution.
-
-      This program is distributed in the hope that it will be useful,
-      but WITHOUT ANY WARRANTY; without even the implied warranty of
-      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-      GNU General Public License for more details.
-
-      You should have received a copy of the GNU General Public License
-      along with this program; if not, write to the Free Software
-      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-
-
- */
-package com.mysql.jdbc;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.lang.ref.SoftReference;
-import java.math.BigInteger;
-import java.net.MalformedURLException;
-import java.net.Socket;
-import java.net.URL;
-import java.security.NoSuchAlgorithmException;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-import java.util.zip.Deflater;
-
-import com.mysql.jdbc.profiler.ProfilerEvent;
-import com.mysql.jdbc.profiler.ProfilerEventHandler;
-import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;
-import com.mysql.jdbc.util.ReadAheadInputStream;
-import com.mysql.jdbc.util.ResultSetUtil;
-
-
-/**
- * This class is used by Connection for communicating with the MySQL server.
- *
- * @author Mark Matthews
- * @version $Id$
- *
- * @see java.sql.Connection
- */
-class MysqlIO {
-    private static final int UTF8_CHARSET_INDEX = 33;
-    private static final String CODE_PAGE_1252 = "Cp1252";
-	protected static final int NULL_LENGTH = ~0;
-    protected static final int COMP_HEADER_LENGTH = 3;
-    protected static final int MIN_COMPRESS_LEN = 50;
-    protected static final int HEADER_LENGTH = 4;
-    protected static final int AUTH_411_OVERHEAD = 33;
-    private static int maxBufferSize = 65535;
-    private static final int CLIENT_COMPRESS = 32; /* Can use compression
-    protcol */
-    protected static final int CLIENT_CONNECT_WITH_DB = 8;
-    private static final int CLIENT_FOUND_ROWS = 2;
-    private static final int CLIENT_LOCAL_FILES = 128; /* Can use LOAD DATA
-    LOCAL */
-
-    /* Found instead of
-       affected rows */
-    private static final int CLIENT_LONG_FLAG = 4; /* Get all column flags */
-    private static final int CLIENT_LONG_PASSWORD = 1; /* new more secure
-    passwords */
-    private static final int CLIENT_PROTOCOL_41 = 512; // for > 4.1.1
-    private static final int CLIENT_INTERACTIVE = 1024;
-    protected static final int CLIENT_SSL = 2048;
-    private static final int CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
-    protected static final int CLIENT_RESERVED = 16384; // for 4.1.0 only
-    protected static final int CLIENT_SECURE_CONNECTION = 32768;
-    private static final int CLIENT_MULTI_QUERIES = 65536; // Enable/disable multiquery support
-    private static final int CLIENT_MULTI_RESULTS = 131072; // Enable/disable multi-results
-    private static final int SERVER_STATUS_IN_TRANS = 1;
-    private static final int SERVER_STATUS_AUTOCOMMIT = 2; // Server in auto_commit mode
-    static final int SERVER_MORE_RESULTS_EXISTS = 8; // Multi query - next query exists
-    private static final int SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
-    private static final int SERVER_QUERY_NO_INDEX_USED = 32;
-	private static final int  SERVER_STATUS_CURSOR_EXISTS = 64;
-    private static final String FALSE_SCRAMBLE = "xxxxxxxx"; //$NON-NLS-1$
-    protected static final int MAX_QUERY_SIZE_TO_LOG = 1024; // truncate logging of queries at 1K
-    protected static final int MAX_QUERY_SIZE_TO_EXPLAIN = 1024 * 1024; // don't explain queries above 1MB
-    protected static final int INITIAL_PACKET_SIZE = 1024;
-    /**
-     * We store the platform 'encoding' here, only used to avoid munging
-     * filenames for LOAD DATA LOCAL INFILE...
-     */
-    private static String jvmPlatformCharset = null;
-
-    /**
-     * We need to have a 'marker' for all-zero datetimes so that ResultSet
-     * can decide what to do based on connection setting
-     */
-    protected final static String ZERO_DATE_VALUE_MARKER = "0000-00-00";
-    protected final static String ZERO_DATETIME_VALUE_MARKER = "0000-00-00 00:00:00";
-
-    static {
-        OutputStreamWriter outWriter = null;
-
-        //
-        // Use the I/O system to get the encoding (if possible), to avoid
-        // security restrictions on System.getProperty("file.encoding") in
-        // applets (why is that restricted?)
-        //
-        try {
-            outWriter = new OutputStreamWriter(new ByteArrayOutputStream());
-            jvmPlatformCharset = outWriter.getEncoding();
-        } finally {
-            try {
-                if (outWriter != null) {
-                    outWriter.close();
-                }
-            } catch (IOException ioEx) {
-                // ignore
-            }
-        }
-    }
-
-    /** Max number of bytes to dump when tracing the protocol */
-    private final static int MAX_PACKET_DUMP_LENGTH = 1024;
-    private boolean packetSequenceReset = false;
-    protected int serverCharsetIndex;
-
-    //
-    // Use this when reading in rows to avoid thousands of new()
-    // calls, because the byte arrays just get copied out of the
-    // packet anyway
-    //
-    private Buffer reusablePacket = null;
-    private Buffer sendPacket = null;
-    private Buffer sharedSendPacket = null;
-
-    /** Data to the server */
-    protected BufferedOutputStream mysqlOutput = null;
-    protected ConnectionImpl connection;
-    private Deflater deflater = null;
-    protected InputStream mysqlInput = null;
-    private LinkedList packetDebugRingBuffer = null;
-    private RowData streamingData = null;
-
-    /** The connection to the server */
-    protected Socket mysqlConnection = null;
-    private SocketFactory socketFactory = null;
-
-    //
-    // Packet used for 'LOAD DATA LOCAL INFILE'
-    //
-    // We use a SoftReference, so that we don't penalize intermittent
-    // use of this feature
-    //
-    private SoftReference loadFileBufRef;
-
-    //
-    // Used to send large packets to the server versions 4+
-    // We use a SoftReference, so that we don't penalize intermittent
-    // use of this feature
-    //
-    private SoftReference splitBufRef;
-    protected String host = null;
-    protected String seed;
-    private String serverVersion = null;
-    private String socketFactoryClassName = null;
-    private byte[] packetHeaderBuf = new byte[4];
-    private boolean colDecimalNeedsBump = false; // do we need to increment the colDecimal flag?
-    private boolean hadWarnings = false;
-    private boolean has41NewNewProt = false;
-
-    /** Does the server support long column info? */
-    private boolean hasLongColumnInfo = false;
-    private boolean isInteractiveClient = false;
-    private boolean logSlowQueries = false;
-
-    /**
-     * Does the character set of this connection match the character set of the
-     * platform
-     */
-    private boolean platformDbCharsetMatches = true; // changed once we've connected.
-    private boolean profileSql = false;
-    private boolean queryBadIndexUsed = false;
-    private boolean queryNoIndexUsed = false;
-
-    /** Should we use 4.1 protocol extensions? */
-    private boolean use41Extensions = false;
-    private boolean useCompression = false;
-    private boolean useNewLargePackets = false;
-    private boolean useNewUpdateCounts = false; // should we use the new larger update counts?
-    private byte packetSequence = 0;
-    private byte readPacketSequence = -1;
-    private boolean checkPacketSequence = false;
-    private byte protocolVersion = 0;
-    private int maxAllowedPacket = 1024 * 1024;
-    protected int maxThreeBytes = 255 * 255 * 255;
-    protected int port = 3306;
-    protected int serverCapabilities;
-    private int serverMajorVersion = 0;
-    private int serverMinorVersion = 0;
-    private int serverStatus = 0;
-    private int serverSubMinorVersion = 0;
-    private int warningCount = 0;
-    protected long clientParam = 0;
-    protected long lastPacketSentTimeMs = 0;
-    private boolean traceProtocol = false;
-    private boolean enablePacketDebug = false;
-    private Calendar sessionCalendar;
-	private boolean useConnectWithDb;
-	private boolean needToGrabQueryFromPacket;
-	private boolean autoGenerateTestcaseScript;
-	private long threadId;
-	private boolean useNanosForElapsedTime;
-	private long slowQueryThreshold;
-	private String queryTimingUnits;
-	private List statementInterceptors;
-	private boolean useDirectRowUnpack = true;
-	private int useBufferRowSizeThreshold;
-	private int commandCount = 0;
-
-    /**
-     * Constructor:  Connect to the MySQL server and setup a stream connection.
-     *
-     * @param host the hostname to connect to
-     * @param port the port number that the server is listening on
-     * @param props the Properties from DriverManager.getConnection()
-     * @param socketFactoryClassName the socket factory to use
-     * @param conn the Connection that is creating us
-     * @param socketTimeout the timeout to set for the socket (0 means no
-     *        timeout)
-     *
-     * @throws IOException if an IOException occurs during connect.
-     * @throws SQLException if a database access error occurs.
-     */
-    public MysqlIO(String host, int port, Properties props,
-        String socketFactoryClassName, ConnectionImpl conn,
-        int socketTimeout, int useBufferRowSizeThreshold) throws IOException, SQLException {
-        this.connection = conn;
-
-        if (this.connection.getEnablePacketDebug()) {
-            this.packetDebugRingBuffer = new LinkedList();
-        }
-
-        this.useAutoSlowLog = this.connection.getAutoSlowLog();
-        
-        this.useBufferRowSizeThreshold = useBufferRowSizeThreshold;
-        this.useDirectRowUnpack = this.connection.getUseDirectRowUnpack();
-
-        this.logSlowQueries = this.connection.getLogSlowQueries();
-
-        this.reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
-        this.sendPacket = new Buffer(INITIAL_PACKET_SIZE);
-
-        this.port = port;
-        this.host = host;
-
-        this.socketFactoryClassName = socketFactoryClassName;
-        this.socketFactory = createSocketFactory();
-
-        this.mysqlConnection = this.socketFactory.connect(this.host,
-        		this.port, props);
-
-        if (socketTimeout != 0) {
-        	try {
-        		this.mysqlConnection.setSoTimeout(socketTimeout);
-        	} catch (Exception ex) {
-        		/* Ignore if the platform does not support it */
-        	}
-        }
-
-        this.mysqlConnection = this.socketFactory.beforeHandshake();
-
-        if (this.connection.getUseReadAheadInput()) {
-        	this.mysqlInput = new ReadAheadInputStream(this.mysqlConnection.getInputStream(), 16384,
-        			this.connection.getTraceProtocol(),
-        			this.connection.getLog());
-        } else if (this.connection.useUnbufferedInput()) {
-        	this.mysqlInput = this.mysqlConnection.getInputStream();
-        } else {
-        	this.mysqlInput = new BufferedInputStream(this.mysqlConnection.getInputStream(),
-        			16384);
-        }
-
-        this.mysqlOutput = new BufferedOutputStream(this.mysqlConnection.getOutputStream(),
-        		16384);
-
-
-        this.isInteractiveClient = this.connection.getInteractiveClient();
-        this.profileSql = this.connection.getProfileSql();
-        this.sessionCalendar = Calendar.getInstance();
-        this.autoGenerateTestcaseScript = this.connection.getAutoGenerateTestcaseScript();
-
-        this.needToGrabQueryFromPacket = (this.profileSql ||
-        		this.logSlowQueries ||
-        		this.autoGenerateTestcaseScript);
-
-        if (this.connection.getUseNanosForElapsedTime()
-				&& Util.nanoTimeAvailable()) {
-			this.useNanosForElapsedTime = true;
-
-			this.queryTimingUnits = Messages.getString("Nanoseconds");
-		} else {
-			this.queryTimingUnits = Messages.getString("Milliseconds");
-		}
-
-		if (this.connection.getLogSlowQueries()) {
-			calculateSlowQueryThreshold();
-		}
-    }
-
-    protected void initializeStatementInterceptors(String interceptorClasses,
-			Properties props) throws SQLException {
-		this.statementInterceptors = Util.loadExtensions(this.connection, props, 
-				interceptorClasses,
-				"MysqlIo.BadStatementInterceptor");
-	}
-
-    /**
-	 * Does the server send back extra column info?
-	 * 
-	 * @return true if so
-	 */
-    public boolean hasLongColumnInfo() {
-        return this.hasLongColumnInfo;
-    }
-
-    protected boolean isDataAvailable() throws SQLException {
-        try {
-            return this.mysqlInput.available() > 0;
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-    /**
-     * DOCUMENT ME!
-     *
-     * @return Returns the lastPacketSentTimeMs.
-     */
-    protected long getLastPacketSentTimeMs() {
-        return this.lastPacketSentTimeMs;
-    }
-
-    /**
-     * Build a result set. Delegates to buildResultSetWithRows() to build a
-     * JDBC-version-specific ResultSet, given rows as byte data, and field
-     * information.
-     *
-     * @param callingStatement DOCUMENT ME!
-     * @param columnCount the number of columns in the result set
-     * @param maxRows the maximum number of rows to read (-1 means all rows)
-     * @param resultSetType (TYPE_FORWARD_ONLY, TYPE_SCROLL_????)
-     * @param resultSetConcurrency the type of result set (CONCUR_UPDATABLE or
-     *        READ_ONLY)
-     * @param streamResults should the result set be read all at once, or
-     *        streamed?
-     * @param catalog the database name in use when the result set was created
-     * @param isBinaryEncoded is this result set in native encoding?
-     * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
-     *
-     * @return a result set
-     *
-     * @throws SQLException if a database access error occurs
-     */
-    protected ResultSetImpl getResultSet(StatementImpl callingStatement,
-        long columnCount, int maxRows, int resultSetType,
-        int resultSetConcurrency, boolean streamResults, String catalog,
-        boolean isBinaryEncoded, Field[] metadataFromCache)
-        throws SQLException {
-        Buffer packet; // The packet from the server
-        Field[] fields = null;
-
-        // Read in the column information
-
-        if (metadataFromCache == null /* we want the metadata from the server */) {
-            fields = new Field[(int) columnCount];
-
-            for (int i = 0; i < columnCount; i++) {
-            	Buffer fieldPacket = null;
-
-                fieldPacket = readPacket();
-                fields[i] = unpackField(fieldPacket, false);
-            }
-        } else {
-        	for (int i = 0; i < columnCount; i++) {
-        		skipPacket();
-        	}
-        }
-
-        packet = reuseAndReadPacket(this.reusablePacket);
-        
-        readServerStatusForResultSets(packet);
-
-		//
-		// Handle cursor-based fetch first
-		//
-
-		if (this.connection.versionMeetsMinimum(5, 0, 2)
-				&& this.connection.getUseCursorFetch()
-				&& isBinaryEncoded
-				&& callingStatement != null
-				&& callingStatement.getFetchSize() != 0
-				&& callingStatement.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
-			ServerPreparedStatement prepStmt = (com.mysql.jdbc.ServerPreparedStatement) callingStatement;
-
-			boolean usingCursor = true;
-
-			//
-			// Server versions 5.0.5 or newer will only open
-			// a cursor and set this flag if they can, otherwise
-			// they punt and go back to mysql_store_results() behavior
-			//
-
-			if (this.connection.versionMeetsMinimum(5, 0, 5)) {
-				usingCursor = (this.serverStatus &
-						SERVER_STATUS_CURSOR_EXISTS) != 0;
-			}
-
-			if (usingCursor) {
-				RowData rows = new RowDataCursor(
-					this,
-					prepStmt,
-					fields);
-
-				ResultSetImpl rs = buildResultSetWithRows(
-					callingStatement,
-					catalog,
-					fields,
-					rows, resultSetType, resultSetConcurrency, isBinaryEncoded);
-
-				if (usingCursor) {
-		        	rs.setFetchSize(callingStatement.getFetchSize());
-		        }
-
-				return rs;
-			}
-		}
-
-        RowData rowData = null;
-
-        if (!streamResults) {
-            rowData = readSingleRowSet(columnCount, maxRows,
-                    resultSetConcurrency, isBinaryEncoded,
-                    (metadataFromCache == null) ? fields : metadataFromCache);
-        } else {
-            rowData = new RowDataDynamic(this, (int) columnCount,
-            		(metadataFromCache == null) ? fields : metadataFromCache,
-                    isBinaryEncoded);
-            this.streamingData = rowData;
-        }
-
-        ResultSetImpl rs = buildResultSetWithRows(callingStatement, catalog,
-        		(metadataFromCache == null) ? fields : metadataFromCache,
-            rowData, resultSetType, resultSetConcurrency, isBinaryEncoded);
-
-
-
-        return rs;
-    }
-
-    /**
-     * Forcibly closes the underlying socket to MySQL.
-     */
-    protected final void forceClose() {
-        try {
-            if (this.mysqlInput != null) {
-                this.mysqlInput.close();
-            }
-        } catch (IOException ioEx) {
-            // we can't do anything constructive about this
-            // Let the JVM clean it up later
-            this.mysqlInput = null;
-        }
-
-        try {
-            if (this.mysqlOutput != null) {
-                this.mysqlOutput.close();
-            }
-        } catch (IOException ioEx) {
-            // we can't do anything constructive about this
-            // Let the JVM clean it up later
-            this.mysqlOutput = null;
-        }
-
-        try {
-            if (this.mysqlConnection != null) {
-                this.mysqlConnection.close();
-            }
-        } catch (IOException ioEx) {
-            // we can't do anything constructive about this
-            // Let the JVM clean it up later
-            this.mysqlConnection = null;
-        }
-    }
-
-    /**
-     * Reads and discards a single MySQL packet from the input stream.
-     *
-     * @throws SQLException if the network fails while skipping the
-     * packet.
-     */
-    protected final void skipPacket() throws SQLException {
-		try {
-
-			int lengthRead = readFully(this.mysqlInput, this.packetHeaderBuf,
-					0, 4);
-
-			if (lengthRead < 4) {
-				forceClose();
-				throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
-			}
-
-			int packetLength = (this.packetHeaderBuf[0] & 0xff)
-					+ ((this.packetHeaderBuf[1] & 0xff) << 8)
-					+ ((this.packetHeaderBuf[2] & 0xff) << 16);
-
-			if (this.traceProtocol) {
-				StringBuffer traceMessageBuf = new StringBuffer();
-
-				traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
-				traceMessageBuf.append(packetLength);
-				traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
-				traceMessageBuf.append(StringUtils.dumpAsHex(
-						this.packetHeaderBuf, 4));
-
-				this.connection.getLog().logTrace(traceMessageBuf.toString());
-			}
-
-			byte multiPacketSeq = this.packetHeaderBuf[3];
-
-			if (!this.packetSequenceReset) {
-				if (this.enablePacketDebug && this.checkPacketSequence) {
-					checkPacketSequencing(multiPacketSeq);
-				}
-			} else {
-				this.packetSequenceReset = false;
-			}
-
-			this.readPacketSequence = multiPacketSeq;
-
-			skipFully(this.mysqlInput, packetLength);
-		} catch (IOException ioEx) {
-			throw SQLError.createCommunicationsException(this.connection,
-					this.lastPacketSentTimeMs, ioEx);
-		} catch (OutOfMemoryError oom) {
-			try {
-				this.connection.realClose(false, false, true, oom);
-			} finally {
-				throw oom;
-			}
-		}
-	}
-
-    /**
-     * Read one packet from the MySQL server
-     *
-     * @return the packet from the server.
-     *
-     * @throws SQLException DOCUMENT ME!
-     * @throws CommunicationsException DOCUMENT ME!
-     */
-    protected final Buffer readPacket() throws SQLException {
-        try {
-
-            int lengthRead = readFully(this.mysqlInput,
-                    this.packetHeaderBuf, 0, 4);
-
-            if (lengthRead < 4) {
-                forceClose();
-                throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
-            }
-
-            int packetLength = (this.packetHeaderBuf[0] & 0xff) +
-                ((this.packetHeaderBuf[1] & 0xff) << 8) +
-                ((this.packetHeaderBuf[2] & 0xff) << 16);
-            
-            if (packetLength > this.maxAllowedPacket) {
-                throw new PacketTooBigException(packetLength, this.maxAllowedPacket);
-            }
-
-            if (this.traceProtocol) {
-                StringBuffer traceMessageBuf = new StringBuffer();
-
-                traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
-                traceMessageBuf.append(packetLength);
-                traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
-                traceMessageBuf.append(StringUtils.dumpAsHex(
-                        this.packetHeaderBuf, 4));
-
-                this.connection.getLog().logTrace(traceMessageBuf.toString());
-            }
-
-            byte multiPacketSeq = this.packetHeaderBuf[3];
-
-            if (!this.packetSequenceReset) {
-                if (this.enablePacketDebug && this.checkPacketSequence) {
-                    checkPacketSequencing(multiPacketSeq);
-                }
-            } else {
-                this.packetSequenceReset = false;
-            }
-
-            this.readPacketSequence = multiPacketSeq;
-
-            // Read data
-            byte[] buffer = new byte[packetLength + 1];
-            int numBytesRead = readFully(this.mysqlInput, buffer, 0,
-                    packetLength);
-
-            if (numBytesRead != packetLength) {
-                throw new IOException("Short read, expected " +
-                    packetLength + " bytes, only read " + numBytesRead);
-            }
-
-            buffer[packetLength] = 0;
-
-            Buffer packet = new Buffer(buffer);
-            packet.setBufLength(packetLength + 1);
-
-            if (this.traceProtocol) {
-                StringBuffer traceMessageBuf = new StringBuffer();
-
-                traceMessageBuf.append(Messages.getString("MysqlIO.4")); //$NON-NLS-1$
-                traceMessageBuf.append(getPacketDumpToLog(packet,
-                        packetLength));
-
-                this.connection.getLog().logTrace(traceMessageBuf.toString());
-            }
-
-            if (this.enablePacketDebug) {
-                enqueuePacketForDebugging(false, false, 0,
-                    this.packetHeaderBuf, packet);
-            }
-
-            return packet;
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        } catch (OutOfMemoryError oom) {
-        	try {
-    			this.connection.realClose(false, false, true, oom);
-    		} finally {
-    			throw oom;
-    		}
-        }
-    }
-
-    /**
-     * Unpacks the Field information from the given packet. Understands pre 4.1
-     * and post 4.1 server version field packet structures.
-     *
-     * @param packet the packet containing the field information
-     * @param extractDefaultValues should default values be extracted?
-     *
-     * @return the unpacked field
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    protected final Field unpackField(Buffer packet,
-        boolean extractDefaultValues) throws SQLException {
-        if (this.use41Extensions) {
-            // we only store the position of the string and
-            // materialize only if needed...
-            if (this.has41NewNewProt) {
-                // Not used yet, 5.0?
-                int catalogNameStart = packet.getPosition() + 1;
-                int catalogNameLength = packet.fastSkipLenString();
-                catalogNameStart = adjustStartForFieldLength(catalogNameStart, catalogNameLength);
-            }
-
-            int databaseNameStart = packet.getPosition() + 1;
-            int databaseNameLength = packet.fastSkipLenString();
-            databaseNameStart = adjustStartForFieldLength(databaseNameStart, databaseNameLength);
-
-            int tableNameStart = packet.getPosition() + 1;
-            int tableNameLength = packet.fastSkipLenString();
-            tableNameStart = adjustStartForFieldLength(tableNameStart, tableNameLength);
-
-            // orgTableName is never used so skip
-            int originalTableNameStart = packet.getPosition() + 1;
-            int originalTableNameLength = packet.fastSkipLenString();
-            originalTableNameStart = adjustStartForFieldLength(originalTableNameStart, originalTableNameLength);
-
-            // we only store the position again...
-            int nameStart = packet.getPosition() + 1;
-            int nameLength = packet.fastSkipLenString();
-
-            nameStart = adjustStartForFieldLength(nameStart, nameLength);
-
-            // orgColName is not required so skip...
-            int originalColumnNameStart = packet.getPosition() + 1;
-            int originalColumnNameLength = packet.fastSkipLenString();
-            originalColumnNameStart = adjustStartForFieldLength(originalColumnNameStart, originalColumnNameLength);
-
-            packet.readByte();
-
-            short charSetNumber = (short) packet.readInt();
-
-            long colLength = 0;
-
-            if (this.has41NewNewProt) {
-                colLength = packet.readLong();
-            } else {
-                colLength = packet.readLongInt();
-            }
-
-            int colType = packet.readByte() & 0xff;
-
-            short colFlag = 0;
-
-            if (this.hasLongColumnInfo) {
-                colFlag = (short) packet.readInt();
-            } else {
-                colFlag = (short) (packet.readByte() & 0xff);
-            }
-
-            int colDecimals = packet.readByte() & 0xff;
-
-            int defaultValueStart = -1;
-            int defaultValueLength = -1;
-
-            if (extractDefaultValues) {
-                defaultValueStart = packet.getPosition() + 1;
-                defaultValueLength = packet.fastSkipLenString();
-            }
-
-            Field field = new Field(this.connection, packet.getByteBuffer(),
-                    databaseNameStart, databaseNameLength, tableNameStart,
-                    tableNameLength, originalTableNameStart,
-                    originalTableNameLength, nameStart, nameLength,
-                    originalColumnNameStart, originalColumnNameLength,
-                    colLength, colType, colFlag, colDecimals,
-                    defaultValueStart, defaultValueLength, charSetNumber);
-
-            return field;
-        }
-
-        int tableNameStart = packet.getPosition() + 1;
-        int tableNameLength = packet.fastSkipLenString();
-        tableNameStart = adjustStartForFieldLength(tableNameStart, tableNameLength);
-
-        int nameStart = packet.getPosition() + 1;
-        int nameLength = packet.fastSkipLenString();
-        nameStart = adjustStartForFieldLength(nameStart, nameLength);
-
-        int colLength = packet.readnBytes();
-        int colType = packet.readnBytes();
-        packet.readByte(); // We know it's currently 2
-
-        short colFlag = 0;
-
-        if (this.hasLongColumnInfo) {
-            colFlag = (short) (packet.readInt());
-        } else {
-            colFlag = (short) (packet.readByte() & 0xff);
-        }
-
-        int colDecimals = (packet.readByte() & 0xff);
-
-        if (this.colDecimalNeedsBump) {
-            colDecimals++;
-        }
-
-        Field field = new Field(this.connection, packet.getByteBuffer(),
-                nameStart, nameLength, tableNameStart, tableNameLength,
-                colLength, colType, colFlag, colDecimals);
-
-        return field;
-    }
-
-    private int adjustStartForFieldLength(int nameStart, int nameLength) {
-    	if (nameLength < 251) {
-    		return nameStart;
-    	}
-
-		if (nameLength >= 251 && nameLength < 65536) {
-			return nameStart + 2;
-		}
-
-		if (nameLength >= 65536 && nameLength < 16777216) {
-			return nameStart + 3;
-		}
-
-		return nameStart + 8;
-	}
-
-    protected boolean isSetNeededForAutoCommitMode(boolean autoCommitFlag) {
-        if (this.use41Extensions && this.connection.getElideSetAutoCommits()) {
-            boolean autoCommitModeOnServer = ((this.serverStatus &
-                SERVER_STATUS_AUTOCOMMIT) != 0);
-
-            if (!autoCommitFlag && versionMeetsMinimum(5, 0, 0)) {
-                // Just to be safe, check if a transaction is in progress on the server....
-                // if so, then we must be in autoCommit == false
-                // therefore return the opposite of transaction status
-                boolean inTransactionOnServer = ((this.serverStatus &
-                    SERVER_STATUS_IN_TRANS) != 0);
-
-                return !inTransactionOnServer;
-            }
-
-            return autoCommitModeOnServer != autoCommitFlag;
-        }
-
-        return true;
-    }
-
-    protected boolean inTransactionOnServer() {
-    	return (this.serverStatus & SERVER_STATUS_IN_TRANS) != 0;
-    }
-
-    /**
-     * Re-authenticates as the given user and password
-     *
-     * @param userName DOCUMENT ME!
-     * @param password DOCUMENT ME!
-     * @param database DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    protected void changeUser(String userName, String password, String database)
-        throws SQLException {
-        this.packetSequence = -1;
-
-        int passwordLength = 16;
-        int userLength = (userName != null) ? userName.length() : 0;
-        int databaseLength = (database != null) ? database.length() : 0;
-
-        int packLength = ((userLength + passwordLength + databaseLength) * 2) + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
-
-        if ((this.serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
-            Buffer changeUserPacket = new Buffer(packLength + 1);
-            changeUserPacket.writeByte((byte) MysqlDefs.COM_CHANGE_USER);
-
-            if (versionMeetsMinimum(4, 1, 1)) {
-                secureAuth411(changeUserPacket, packLength, userName, password,
-                    database, false);
-            } else {
-                secureAuth(changeUserPacket, packLength, userName, password,
-                    database, false);
-            }
-        } else {
-            // Passwords can be 16 chars long
-            Buffer packet = new Buffer(packLength);
-            packet.writeByte((byte) MysqlDefs.COM_CHANGE_USER);
-
-            // User/Password data
-            packet.writeString(userName);
-
-            if (this.protocolVersion > 9) {
-                packet.writeString(Util.newCrypt(password, this.seed));
-            } else {
-                packet.writeString(Util.oldCrypt(password, this.seed));
-            }
-
-			boolean localUseConnectWithDb = this.useConnectWithDb &&
-				(database != null && database.length() > 0);
-
-            if (localUseConnectWithDb) {
-                packet.writeString(database);
-            }
-
-            send(packet, packet.getPosition());
-            checkErrorPacket();
-
-			if (!localUseConnectWithDb) {
-				changeDatabaseTo(database);
-			}
-        }
-    }
-
-    /**
-     * Checks for errors in the reply packet, and if none, returns the reply
-     * packet, ready for reading
-     *
-     * @return a packet ready for reading.
-     *
-     * @throws SQLException is the packet is an error packet
-     */
-    protected Buffer checkErrorPacket() throws SQLException {
-        return checkErrorPacket(-1);
-    }
-
-    /**
-     * Determines if the database charset is the same as the platform charset
-     */
-    protected void checkForCharsetMismatch() {
-        if (this.connection.getUseUnicode() &&
-                (this.connection.getEncoding() != null)) {
-            String encodingToCheck = jvmPlatformCharset;
-
-            if (encodingToCheck == null) {
-                encodingToCheck = System.getProperty("file.encoding"); //$NON-NLS-1$
-            }
-
-            if (encodingToCheck == null) {
-                this.platformDbCharsetMatches = false;
-            } else {
-                this.platformDbCharsetMatches = encodingToCheck.equals(this.connection.getEncoding());
-            }
-        }
-    }
-
-    protected void clearInputStream() throws SQLException {
-
-        try {
-            int len = this.mysqlInput.available();
-
-            while (len > 0) {
-                this.mysqlInput.skip(len);
-                len = this.mysqlInput.available();
-            }
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-    protected void resetReadPacketSequence() {
-        this.readPacketSequence = 0;
-    }
-
-    protected void dumpPacketRingBuffer() throws SQLException {
-        if ((this.packetDebugRingBuffer != null) &&
-                this.connection.getEnablePacketDebug()) {
-            StringBuffer dumpBuffer = new StringBuffer();
-
-            dumpBuffer.append("Last " + this.packetDebugRingBuffer.size() +
-                " packets received from server, from oldest->newest:\n");
-            dumpBuffer.append("\n");
-
-            for (Iterator ringBufIter = this.packetDebugRingBuffer.iterator();
-                    ringBufIter.hasNext();) {
-                dumpBuffer.append((StringBuffer) ringBufIter.next());
-                dumpBuffer.append("\n");
-            }
-
-            this.connection.getLog().logTrace(dumpBuffer.toString());
-        }
-    }
-
-    /**
-     * Runs an 'EXPLAIN' on the given query and dumps the results to  the log
-     *
-     * @param querySQL DOCUMENT ME!
-     * @param truncatedQuery DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    protected void explainSlowQuery(byte[] querySQL, String truncatedQuery)
-        throws SQLException {
-        if (StringUtils.startsWithIgnoreCaseAndWs(truncatedQuery, "SELECT")) { //$NON-NLS-1$
-
-            PreparedStatement stmt = null;
-            java.sql.ResultSet rs = null;
-
-            try {
-                stmt = (PreparedStatement) this.connection.clientPrepareStatement("EXPLAIN ?"); //$NON-NLS-1$
-                stmt.setBytesNoEscapeNoQuotes(1, querySQL);
-                rs = stmt.executeQuery();
-
-                StringBuffer explainResults = new StringBuffer(Messages.getString(
-                            "MysqlIO.8") + truncatedQuery //$NON-NLS-1$
-                         +Messages.getString("MysqlIO.9")); //$NON-NLS-1$
-
-                ResultSetUtil.appendResultSetSlashGStyle(explainResults, rs);
-
-                this.connection.getLog().logWarn(explainResults.toString());
-            } catch (SQLException sqlEx) {
-            } finally {
-                if (rs != null) {
-                    rs.close();
-                }
-
-                if (stmt != null) {
-                    stmt.close();
-                }
-            }
-        } else {
-        }
-    }
-
-    static int getMaxBuf() {
-        return maxBufferSize;
-    }
-
-    /**
-     * Get the major version of the MySQL server we are talking to.
-     *
-     * @return DOCUMENT ME!
-     */
-    final int getServerMajorVersion() {
-        return this.serverMajorVersion;
-    }
-
-    /**
-     * Get the minor version of the MySQL server we are talking to.
-     *
-     * @return DOCUMENT ME!
-     */
-    final int getServerMinorVersion() {
-        return this.serverMinorVersion;
-    }
-
-    /**
-     * Get the sub-minor version of the MySQL server we are talking to.
-     *
-     * @return DOCUMENT ME!
-     */
-    final int getServerSubMinorVersion() {
-        return this.serverSubMinorVersion;
-    }
-
-    /**
-     * Get the version string of the server we are talking to
-     *
-     * @return DOCUMENT ME!
-     */
-    String getServerVersion() {
-        return this.serverVersion;
-    }
-
-    /**
-     * Initialize communications with the MySQL server. Handles logging on, and
-     * handling initial connection errors.
-     *
-     * @param user DOCUMENT ME!
-     * @param password DOCUMENT ME!
-     * @param database DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     * @throws CommunicationsException DOCUMENT ME!
-     */
-    void doHandshake(String user, String password, String database)
-        throws SQLException {
-        // Read the first packet
-        this.checkPacketSequence = false;
-        this.readPacketSequence = 0;
-
-        Buffer buf = readPacket();
-
-        // Get the protocol version
-        this.protocolVersion = buf.readByte();
-
-        if (this.protocolVersion == -1) {
-            try {
-                this.mysqlConnection.close();
-            } catch (Exception e) {
-                // ignore
-            }
-
-            int errno = 2000;
-
-            errno = buf.readInt();
-
-            String serverErrorMessage = buf.readString();
-
-            StringBuffer errorBuf = new StringBuffer(Messages.getString(
-                        "MysqlIO.10")); //$NON-NLS-1$
-            errorBuf.append(serverErrorMessage);
-            errorBuf.append("\""); //$NON-NLS-1$
-
-            String xOpen = SQLError.mysqlToSqlState(errno,
-                    this.connection.getUseSqlStateCodes());
-
-            throw SQLError.createSQLException(SQLError.get(xOpen) + ", " //$NON-NLS-1$
-                 +errorBuf.toString(), xOpen, errno);
-        }
-
-        this.serverVersion = buf.readString();
-
-        // Parse the server version into major/minor/subminor
-        int point = this.serverVersion.indexOf('.'); //$NON-NLS-1$
-
-        if (point != -1) {
-            try {
-                int n = Integer.parseInt(this.serverVersion.substring(0, point));
-                this.serverMajorVersion = n;
-            } catch (NumberFormatException NFE1) {
-                // ignore
-            }
-
-            String remaining = this.serverVersion.substring(point + 1,
-                    this.serverVersion.length());
-            point = remaining.indexOf('.'); //$NON-NLS-1$
-
-            if (point != -1) {
-                try {
-                    int n = Integer.parseInt(remaining.substring(0, point));
-                    this.serverMinorVersion = n;
-                } catch (NumberFormatException nfe) {
-                    // ignore
-                }
-
-                remaining = remaining.substring(point + 1, remaining.length());
-
-                int pos = 0;
-
-                while (pos < remaining.length()) {
-                    if ((remaining.charAt(pos) < '0') ||
-                            (remaining.charAt(pos) > '9')) {
-                        break;
-                    }
-
-                    pos++;
-                }
-
-                try {
-                    int n = Integer.parseInt(remaining.substring(0, pos));
-                    this.serverSubMinorVersion = n;
-                } catch (NumberFormatException nfe) {
-                    // ignore
-                }
-            }
-        }
-
-        if (versionMeetsMinimum(4, 0, 8)) {
-            this.maxThreeBytes = (256 * 256 * 256) - 1;
-            this.useNewLargePackets = true;
-        } else {
-            this.maxThreeBytes = 255 * 255 * 255;
-            this.useNewLargePackets = false;
-        }
-
-        this.colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0);
-        this.colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); // guess? Not noted in changelog
-        this.useNewUpdateCounts = versionMeetsMinimum(3, 22, 5);
-
-        threadId = buf.readLong();
-        this.seed = buf.readString();
-
-        this.serverCapabilities = 0;
-
-        if (buf.getPosition() < buf.getBufLength()) {
-            this.serverCapabilities = buf.readInt();
-        }
-
-        if (versionMeetsMinimum(4, 1, 1)) {
-            int position = buf.getPosition();
-
-            /* New protocol with 16 bytes to describe server characteristics */
-            this.serverCharsetIndex = buf.readByte() & 0xff;
-            this.serverStatus = buf.readInt();
-            buf.setPosition(position + 16);
-
-            String seedPart2 = buf.readString();
-            StringBuffer newSeed = new StringBuffer(20);
-            newSeed.append(this.seed);
-            newSeed.append(seedPart2);
-            this.seed = newSeed.toString();
-        }
-
-        if (((this.serverCapabilities & CLIENT_COMPRESS) != 0) &&
-                this.connection.getUseCompression()) {
-            this.clientParam |= CLIENT_COMPRESS;
-        }
-
-		this.useConnectWithDb = (database != null) &&
-			(database.length() > 0) &&
-			!this.connection.getCreateDatabaseIfNotExist();
-
-        if (this.useConnectWithDb) {
-            this.clientParam |= CLIENT_CONNECT_WITH_DB;
-        }
-
-        if (((this.serverCapabilities & CLIENT_SSL) == 0) &&
-                this.connection.getUseSSL()) {
-            if (this.connection.getRequireSSL()) {
-                this.connection.close();
-                forceClose();
-                throw SQLError.createSQLException(Messages.getString("MysqlIO.15"), //$NON-NLS-1$
-                    SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
-            }
-
-            this.connection.setUseSSL(false);
-        }
-
-        if ((this.serverCapabilities & CLIENT_LONG_FLAG) != 0) {
-            // We understand other column flags, as well
-            this.clientParam |= CLIENT_LONG_FLAG;
-            this.hasLongColumnInfo = true;
-        }
-
-        // return FOUND rows
-        this.clientParam |= CLIENT_FOUND_ROWS;
-
-        if (this.connection.getAllowLoadLocalInfile()) {
-            this.clientParam |= CLIENT_LOCAL_FILES;
-        }
-
-        if (this.isInteractiveClient) {
-            this.clientParam |= CLIENT_INTERACTIVE;
-        }
-
-        // Authenticate
-        if (this.protocolVersion > 9) {
-            this.clientParam |= CLIENT_LONG_PASSWORD; // for long passwords
-        } else {
-            this.clientParam &= ~CLIENT_LONG_PASSWORD;
-        }
-
-        //
-        // 4.1 has some differences in the protocol
-        //
-        if (versionMeetsMinimum(4, 1, 0)) {
-            if (versionMeetsMinimum(4, 1, 1)) {
-                this.clientParam |= CLIENT_PROTOCOL_41;
-                this.has41NewNewProt = true;
-
-                // Need this to get server status values
-                this.clientParam |= CLIENT_TRANSACTIONS;
-
-                // We always allow multiple result sets
-                this.clientParam |= CLIENT_MULTI_RESULTS;
-
-                // We allow the user to configure whether
-                // or not they want to support multiple queries
-                // (by default, this is disabled).
-                if (this.connection.getAllowMultiQueries()) {
-                    this.clientParam |= CLIENT_MULTI_QUERIES;
-                }
-            } else {
-                this.clientParam |= CLIENT_RESERVED;
-                this.has41NewNewProt = false;
-            }
-
-            this.use41Extensions = true;
-        }
-
-        int passwordLength = 16;
-        int userLength = (user != null) ? user.length() : 0;
-        int databaseLength = (database != null) ? database.length() : 0;
-
-        int packLength = ((userLength + passwordLength + databaseLength) * 2) + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
-
-        Buffer packet = null;
-
-        if (!this.connection.getUseSSL()) {
-            if ((this.serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
-                this.clientParam |= CLIENT_SECURE_CONNECTION;
-
-                if (versionMeetsMinimum(4, 1, 1)) {
-                    secureAuth411(null, packLength, user, password, database,
-                        true);
-                } else {
-                    secureAuth(null, packLength, user, password, database, true);
-                }
-            } else {
-                // Passwords can be 16 chars long
-                packet = new Buffer(packLength);
-
-                if ((this.clientParam & CLIENT_RESERVED) != 0) {
-                    if (versionMeetsMinimum(4, 1, 1)) {
-                        packet.writeLong(this.clientParam);
-                        packet.writeLong(this.maxThreeBytes);
-
-                        // charset, JDBC will connect as 'latin1',
-                        // and use 'SET NAMES' to change to the desired
-                        // charset after the connection is established.
-                        packet.writeByte((byte) 8);
-
-                        // Set of bytes reserved for future use.
-                        packet.writeBytesNoNull(new byte[23]);
-                    } else {
-                        packet.writeLong(this.clientParam);
-                        packet.writeLong(this.maxThreeBytes);
-                    }
-                } else {
-                    packet.writeInt((int) this.clientParam);
-                    packet.writeLongInt(this.maxThreeBytes);
-                }
-
-                // User/Password data
-                packet.writeString(user, CODE_PAGE_1252, this.connection);
-
-                if (this.protocolVersion > 9) {
-                    packet.writeString(Util.newCrypt(password, this.seed), CODE_PAGE_1252, this.connection);
-                } else {
-                    packet.writeString(Util.oldCrypt(password, this.seed), CODE_PAGE_1252, this.connection);
-                }
-
-                if (this.useConnectWithDb) {
-                    packet.writeString(database, CODE_PAGE_1252, this.connection);
-                }
-
-                send(packet, packet.getPosition());
-            }
-        } else {
-            negotiateSSLConnection(user, password, database, packLength);
-        }
-
-        // Check for errors, not for 4.1.1 or newer,
-        // as the new auth protocol doesn't work that way
-        // (see secureAuth411() for more details...)
-        if (!versionMeetsMinimum(4, 1, 1)) {
-            checkErrorPacket();
-        }
-
-        //
-        // Can't enable compression until after handshake
-        //
-        if (((this.serverCapabilities & CLIENT_COMPRESS) != 0) &&
-                this.connection.getUseCompression()) {
-            // The following matches with ZLIB's
-            // compress()
-            this.deflater = new Deflater();
-            this.useCompression = true;
-            this.mysqlInput = new CompressedInputStream(this.connection,
-                    this.mysqlInput);
-        }
-
-        if (!this.useConnectWithDb) {
-            changeDatabaseTo(database);
-        }
-        
-        try {
-        	this.mysqlConnection = this.socketFactory.afterHandshake();
-        } catch (IOException ioEx) {
-        	throw SQLError.createCommunicationsException(this.connection, this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-	private void changeDatabaseTo(String database) throws SQLException {
-		if (database == null || database.length() == 0) {
-			return;
-		}
-
-		try {
-		    sendCommand(MysqlDefs.INIT_DB, database, null, false, null);
-		} catch (Exception ex) {
-			if (this.connection.getCreateDatabaseIfNotExist()) {
-				sendCommand(MysqlDefs.QUERY, "CREATE DATABASE IF NOT EXISTS " +
-					database,
-					null, false, null);
-				sendCommand(MysqlDefs.INIT_DB, database, null, false, null);
-			} else {
-				throw SQLError.createCommunicationsException(this.connection,
-						this.lastPacketSentTimeMs, ex);
-			}
-		}
-	}
-
-    /**
-    * Retrieve one row from the MySQL server. Note: this method is not
-    * thread-safe, but it is only called from methods that are guarded by
-    * synchronizing on this object.
-    *
-    * @param fields DOCUMENT ME!
-    * @param columnCount DOCUMENT ME!
-    * @param isBinaryEncoded DOCUMENT ME!
-    * @param resultSetConcurrency DOCUMENT ME!
-     * @param b
-    *
-    * @return DOCUMENT ME!
-    *
-    * @throws SQLException DOCUMENT ME!
-    */
-    final ResultSetRow nextRow(Field[] fields, int columnCount,
-        boolean isBinaryEncoded, int resultSetConcurrency,
-        boolean useBufferRowIfPossible,
-        boolean useBufferRowExplicit,
-        boolean canReuseRowPacketForBufferRow, Buffer existingRowPacket)
-        throws SQLException {
-
-    	if (this.useDirectRowUnpack && existingRowPacket == null
-				&& !isBinaryEncoded && !useBufferRowIfPossible
-				&& !useBufferRowExplicit) {
-			return nextRowFast(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
-					useBufferRowIfPossible, useBufferRowExplicit, canReuseRowPacketForBufferRow);
-		}
-
-        Buffer rowPacket = null;
-
-        if (existingRowPacket == null) {
-        	rowPacket = checkErrorPacket();
-
-        	if (!useBufferRowExplicit && useBufferRowIfPossible) {
-        		if (rowPacket.getBufLength() > this.useBufferRowSizeThreshold) {
-        			useBufferRowExplicit = true;
-        		}
-        	}
-        } else {
-        	// We attempted to do nextRowFast(), but the packet was a
-        	// multipacket, so we couldn't unpack it directly
-        	rowPacket = existingRowPacket;
-        	checkErrorPacket(existingRowPacket);
-        }
-
-
-        if (!isBinaryEncoded) {
-            //
-            // Didn't read an error, so re-position to beginning
-            // of packet in order to read result set data
-            //
-            rowPacket.setPosition(rowPacket.getPosition() - 1);
-
-            if (!rowPacket.isLastDataPacket()) {
-            	if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
-            			|| (!useBufferRowIfPossible && !useBufferRowExplicit)) {
-
-            		byte[][] rowData = new byte[columnCount][];
-
-            		for (int i = 0; i < columnCount; i++) {
-            			rowData[i] = rowPacket.readLenByteArray(0);
-            		}
-
-            		return new ByteArrayRow(rowData);
-            	}
-
-            	if (!canReuseRowPacketForBufferRow) {
-            		this.reusablePacket = new Buffer(rowPacket.getBufLength());
-            	}
-
-            	return new BufferRow(rowPacket, fields, false);
-
-            }
-
-            readServerStatusForResultSets(rowPacket);
-
-            return null;
-        }
-
-        //
-        // Handle binary-encoded data for server-side
-        // PreparedStatements...
-        //
-        if (!rowPacket.isLastDataPacket()) {
-        	if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
-        			|| (!useBufferRowIfPossible && !useBufferRowExplicit)) {
-        		return unpackBinaryResultSetRow(fields, rowPacket,
-        				resultSetConcurrency);
-        	}
-
-        	if (!canReuseRowPacketForBufferRow) {
-        		this.reusablePacket = new Buffer(rowPacket.getBufLength());
-        	}
-
-            return new BufferRow(rowPacket, fields, true);
-        }
-
-        rowPacket.setPosition(rowPacket.getPosition() - 1);
-        readServerStatusForResultSets(rowPacket);
-
-        return null;
-    }
-
-    final ResultSetRow nextRowFast(Field[] fields, int columnCount,
-            boolean isBinaryEncoded, int resultSetConcurrency,
-            boolean useBufferRowIfPossible,
-            boolean useBufferRowExplicit, boolean canReuseRowPacket)
-			throws SQLException {
-		try {
-			int lengthRead = readFully(this.mysqlInput, this.packetHeaderBuf,
-					0, 4);
-
-			if (lengthRead < 4) {
-				forceClose();
-				throw new RuntimeException(Messages.getString("MysqlIO.43")); //$NON-NLS-1$
-			}
-
-			int packetLength = (this.packetHeaderBuf[0] & 0xff)
-					+ ((this.packetHeaderBuf[1] & 0xff) << 8)
-					+ ((this.packetHeaderBuf[2] & 0xff) << 16);
-
-			// Have we stumbled upon a multi-packet?
-			if (packetLength == this.maxThreeBytes) {
-				reuseAndReadPacket(this.reusablePacket, packetLength);
-
-				// Go back to "old" way which uses packets
-				return nextRow(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
-						useBufferRowIfPossible, useBufferRowExplicit,
-						canReuseRowPacket, this.reusablePacket);
-			}
-
-			// Does this go over the threshold where we should use a BufferRow?
-
-			if (packetLength > this.useBufferRowSizeThreshold) {
-				reuseAndReadPacket(this.reusablePacket, packetLength);
-
-				// Go back to "old" way which uses packets
-				return nextRow(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
-						true, true,
-						false, this.reusablePacket);
-			}
-
-			int remaining = packetLength;
-
-			boolean firstTime = true;
-
-			byte[][] rowData = null;
-
-			for (int i = 0; i < columnCount; i++) {
-
-				int sw = this.mysqlInput.read() & 0xff;
-				remaining--;
-
-				if (firstTime) {
-					if (sw == 255) {
-						// error packet - we assemble it whole for "fidelity"
-						// in case we ever need an entire packet in checkErrorPacket()
-						// but we could've gotten away with just writing the error code
-						// and message in it (for now).
-						Buffer errorPacket = new Buffer(packetLength + HEADER_LENGTH);
-						errorPacket.setPosition(0);
-						errorPacket.writeByte(this.packetHeaderBuf[0]);
-						errorPacket.writeByte(this.packetHeaderBuf[1]);
-						errorPacket.writeByte(this.packetHeaderBuf[2]);
-						errorPacket.writeByte((byte) 1);
-						errorPacket.writeByte((byte)sw);
-						readFully(this.mysqlInput, errorPacket.getByteBuffer(), 5, packetLength - 1);
-						errorPacket.setPosition(4);
-						checkErrorPacket(errorPacket);
-					}
-
-					if (sw == 254 && packetLength < 9) {
-						if (this.use41Extensions) {
-							this.warningCount = (this.mysqlInput.read() & 0xff)
-									| ((this.mysqlInput.read() & 0xff) << 8);
-							remaining -= 2;
-
-							if (this.warningCount > 0) {
-								this.hadWarnings = true; // this is a
-															// 'latch', it's
-															// reset by
-															// sendCommand()
-							}
-
-							this.serverStatus = (this.mysqlInput.read() & 0xff)
-									| ((this.mysqlInput.read() & 0xff) << 8);
-							remaining -= 2;
-
-							if (remaining > 0) {
-								skipFully(this.mysqlInput, remaining);
-							}
-						}
-
-						return null; // last data packet
-					}
-
-					rowData = new byte[columnCount][];
-
-					firstTime = false;
-				}
-
-				int len = 0;
-
-				switch (sw) {
-				case 251:
-					len = NULL_LENGTH;
-					break;
-
-				case 252:
-					len = (this.mysqlInput.read() & 0xff)
-							| ((this.mysqlInput.read() & 0xff) << 8);
-					remaining -= 2;
-					break;
-
-				case 253:
-					len = (this.mysqlInput.read() & 0xff)
-							| ((this.mysqlInput.read() & 0xff) << 8)
-							| ((this.mysqlInput.read() & 0xff) << 16);
-
-					remaining -= 3;
-					break;
-
-				case 254:
-					len = (int) ((this.mysqlInput.read() & 0xff)
-							| ((long) (this.mysqlInput.read() & 0xff) << 8)
-							| ((long) (this.mysqlInput.read() & 0xff) << 16)
-							| ((long) (this.mysqlInput.read() & 0xff) << 24)
-							| ((long) (this.mysqlInput.read() & 0xff) << 32)
-							| ((long) (this.mysqlInput.read() & 0xff) << 40)
-							| ((long) (this.mysqlInput.read() & 0xff) << 48)
-							| ((long) (this.mysqlInput.read() & 0xff) << 56));
-					remaining -= 8;
-					break;
-
-				default:
-					len = sw;
-				}
-
-				if (len == NULL_LENGTH) {
-					rowData[i] = null;
-				} else if (len == 0) {
-					rowData[i] = Constants.EMPTY_BYTE_ARRAY;
-				} else {
-					rowData[i] = new byte[len];
-
-					int bytesRead = readFully(this.mysqlInput, rowData[i], 0,
-							len);
-
-					if (bytesRead != len) {
-						throw SQLError.createCommunicationsException(this.connection,
-			    				this.lastPacketSentTimeMs,
-			    				new IOException(Messages.getString("MysqlIO.43")));
-					}
-
-					remaining -= bytesRead;
-				}
-			}
-
-			if (remaining > 0) {
-				skipFully(this.mysqlInput, remaining);
-			}
-
-			return new ByteArrayRow(rowData);
-		} catch (IOException ioEx) {
-			throw SQLError.createCommunicationsException(this.connection,
-    				this.lastPacketSentTimeMs, ioEx);
-		}
-	}
-
-    /**
-     * Log-off of the MySQL server and close the socket.
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    final void quit() throws SQLException {
-        Buffer packet = new Buffer(6);
-        this.packetSequence = -1;
-        packet.writeByte((byte) MysqlDefs.QUIT);
-        send(packet, packet.getPosition());
-        forceClose();
-    }
-
-    /**
-     * Returns the packet used for sending data (used by PreparedStatement)
-     * Guarded by external synchronization on a mutex.
-     *
-     * @return A packet to send data with
-     */
-    Buffer getSharedSendPacket() {
-        if (this.sharedSendPacket == null) {
-        	this.sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
-        }
-
-        return this.sharedSendPacket;
-    }
-
-    void closeStreamer(RowData streamer) throws SQLException {
-        if (this.streamingData == null) {
-            throw SQLError.createSQLException(Messages.getString("MysqlIO.17") //$NON-NLS-1$
-                 +streamer + Messages.getString("MysqlIO.18")); //$NON-NLS-1$
-        }
-
-        if (streamer != this.streamingData) {
-            throw SQLError.createSQLException(Messages.getString("MysqlIO.19") //$NON-NLS-1$
-                 +streamer + Messages.getString("MysqlIO.20") //$NON-NLS-1$
-                 +Messages.getString("MysqlIO.21") //$NON-NLS-1$
-                 +Messages.getString("MysqlIO.22")); //$NON-NLS-1$
-        }
-
-        this.streamingData = null;
-    }
-
-    boolean tackOnMoreStreamingResults(ResultSetImpl addingTo) throws SQLException {
-    	if ((this.serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0) {
-    		
-			boolean moreRowSetsExist = true;
-			ResultSetImpl currentResultSet = addingTo;
-			boolean firstTime = true;
-			
-			while (moreRowSetsExist) {
-				if (!firstTime && currentResultSet.reallyResult()) {
-					break;
-				}
-				
-				firstTime = false;
-				
-				Buffer fieldPacket = checkErrorPacket();
-	            fieldPacket.setPosition(0);
-	            
-	            java.sql.Statement owningStatement = addingTo.getStatement();
-	            
-	            int maxRows = owningStatement.getMaxRows();
-	            
-	            // fixme for catalog, isBinary
-	            
-	            ResultSetImpl newResultSet = readResultsForQueryOrUpdate(
-	            		(StatementImpl)owningStatement,
-	                    maxRows, owningStatement.getResultSetType(), 
-	                    owningStatement.getResultSetConcurrency(),
-	                    true, owningStatement.getConnection().getCatalog(), fieldPacket, 
-	                    addingTo.isBinaryEncoded,
-	                    -1L, null);
-
-	            currentResultSet.setNextResultSet(newResultSet);
-
-	            currentResultSet = newResultSet;
-
-	            moreRowSetsExist = (this.serverStatus & MysqlIO.SERVER_MORE_RESULTS_EXISTS) != 0;
-	            
-	            if (!currentResultSet.reallyResult() && !moreRowSetsExist) {
-	            	// special case, we can stop "streaming"
-	            	return false;
-	            }
-			}
-			
-			return true;
-    	}
-
-    	return false;
-    }
-    
-    ResultSetImpl readAllResults(StatementImpl callingStatement, int maxRows,
-        int resultSetType, int resultSetConcurrency, boolean streamResults,
-        String catalog, Buffer resultPacket, boolean isBinaryEncoded,
-        long preSentColumnCount, Field[] metadataFromCache)
-        throws SQLException {
-        resultPacket.setPosition(resultPacket.getPosition() - 1);
-
-        ResultSetImpl topLevelResultSet = readResultsForQueryOrUpdate(callingStatement,
-                maxRows, resultSetType, resultSetConcurrency, streamResults,
-                catalog, resultPacket, isBinaryEncoded, preSentColumnCount,
-                metadataFromCache);
-
-        ResultSetImpl currentResultSet = topLevelResultSet;
-
-        boolean checkForMoreResults = ((this.clientParam &
-            CLIENT_MULTI_RESULTS) != 0);
-
-        boolean serverHasMoreResults = (this.serverStatus &
-            SERVER_MORE_RESULTS_EXISTS) != 0;
-
-        //
-        // TODO: We need to support streaming of multiple result sets
-        //
-        if (serverHasMoreResults && streamResults) {
-            //clearInputStream();
-//
-            //throw SQLError.createSQLException(Messages.getString("MysqlIO.23"), //$NON-NLS-1$
-                //SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
-        	if (topLevelResultSet.getUpdateCount() != -1) {
-        		tackOnMoreStreamingResults(topLevelResultSet);
-        	}
-        	
-        	reclaimLargeReusablePacket();
-        	
-        	return topLevelResultSet;
-        }
-
-        boolean moreRowSetsExist = checkForMoreResults & serverHasMoreResults;
-
-        while (moreRowSetsExist) {
-        	Buffer fieldPacket = checkErrorPacket();
-            fieldPacket.setPosition(0);
-
-            ResultSetImpl newResultSet = readResultsForQueryOrUpdate(callingStatement,
-                    maxRows, resultSetType, resultSetConcurrency,
-                    streamResults, catalog, fieldPacket, isBinaryEncoded,
-                    preSentColumnCount, metadataFromCache);
-
-            currentResultSet.setNextResultSet(newResultSet);
-
-            currentResultSet = newResultSet;
-
-            moreRowSetsExist = (this.serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0;
-        }
-
-        if (!streamResults) {
-            clearInputStream();
-        }
-
-        reclaimLargeReusablePacket();
-
-        return topLevelResultSet;
-    }
-
-    /**
-     * Sets the buffer size to max-buf
-     */
-    void resetMaxBuf() {
-        this.maxAllowedPacket = this.connection.getMaxAllowedPacket();
-    }
-
-    /**
-     * Send a command to the MySQL server If data is to be sent with command,
-     * it should be put in extraData.
-     *
-     * Raw packets can be sent by setting queryPacket to something other
-     * than null.
-     *
-     * @param command the MySQL protocol 'command' from MysqlDefs
-     * @param extraData any 'string' data for the command
-     * @param queryPacket a packet pre-loaded with data for the protocol (i.e.
-     * from a client-side prepared statement).
-     * @param skipCheck do not call checkErrorPacket() if true
-     * @param extraDataCharEncoding the character encoding of the extraData
-     * parameter.
-     *
-     * @return the response packet from the server
-     *
-     * @throws SQLException if an I/O error or SQL error occurs
-     */
-
-    final Buffer sendCommand(int command, String extraData, Buffer queryPacket,
-        boolean skipCheck, String extraDataCharEncoding)
-        throws SQLException {
-    	this.commandCount++;
-    	
-        //
-        // We cache these locally, per-command, as the checks
-        // for them are in very 'hot' sections of the I/O code
-        // and we save 10-15% in overall performance by doing this...
-        //
-        this.enablePacketDebug = this.connection.getEnablePacketDebug();
-        this.traceProtocol = this.connection.getTraceProtocol();
-        this.readPacketSequence = 0;
-
-        try {
-
-            checkForOutstandingStreamingData();
-
-            // Clear serverStatus...this value is guarded by an
-            // external mutex, as you can only ever be processing
-            // one command at a time
-            this.serverStatus = 0;
-            this.hadWarnings = false;
-            this.warningCount = 0;
-
-            this.queryNoIndexUsed = false;
-            this.queryBadIndexUsed = false;
-
-            //
-            // Compressed input stream needs cleared at beginning
-            // of each command execution...
-            //
-            if (this.useCompression) {
-                int bytesLeft = this.mysqlInput.available();
-
-                if (bytesLeft > 0) {
-                    this.mysqlInput.skip(bytesLeft);
-                }
-            }
-
-            try {
-                clearInputStream();
-
-                //
-                // PreparedStatements construct their own packets,
-                // for efficiency's sake.
-                //
-                // If this is a generic query, we need to re-use
-                // the sending packet.
-                //
-                if (queryPacket == null) {
-                    int packLength = HEADER_LENGTH + COMP_HEADER_LENGTH + 1 +
-                        ((extraData != null) ? extraData.length() : 0) + 2;
-
-                    if (this.sendPacket == null) {
-                        this.sendPacket = new Buffer(packLength);
-                    }
-
-                    this.packetSequence = -1;
-                    this.readPacketSequence = 0;
-                    this.checkPacketSequence = true;
-                    this.sendPacket.clear();
-
-                    this.sendPacket.writeByte((byte) command);
-
-                    if ((command == MysqlDefs.INIT_DB) ||
-                            (command == MysqlDefs.CREATE_DB) ||
-                            (command == MysqlDefs.DROP_DB) ||
-                            (command == MysqlDefs.QUERY) ||
-                            (command == MysqlDefs.COM_PREPARE)) {
-                        if (extraDataCharEncoding == null) {
-                            this.sendPacket.writeStringNoNull(extraData);
-                        } else {
-                            this.sendPacket.writeStringNoNull(extraData,
-                                extraDataCharEncoding,
-                                this.connection.getServerCharacterEncoding(),
-                                this.connection.parserKnowsUnicode(), this.connection);
-                        }
-                    } else if (command == MysqlDefs.PROCESS_KILL) {
-                        long id = Long.parseLong(extraData);
-                        this.sendPacket.writeLong(id);
-                    }
-
-                    send(this.sendPacket, this.sendPacket.getPosition());
-                } else {
-                    this.packetSequence = -1;
-                    send(queryPacket, queryPacket.getPosition()); // packet passed by PreparedStatement
-                }
-            } catch (SQLException sqlEx) {
-                // don't wrap SQLExceptions
-                throw sqlEx;
-            } catch (Exception ex) {
-                throw SQLError.createCommunicationsException(this.connection,
-                    this.lastPacketSentTimeMs, ex);
-            }
-
-            Buffer returnPacket = null;
-
-            if (!skipCheck) {
-                if ((command == MysqlDefs.COM_EXECUTE) ||
-                        (command == MysqlDefs.COM_RESET_STMT)) {
-                    this.readPacketSequence = 0;
-                    this.packetSequenceReset = true;
-                }
-
-                returnPacket = checkErrorPacket(command);
-            }
-
-            return returnPacket;
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-    private int statementExecutionDepth = 0;
-	private boolean useAutoSlowLog;
-
-    /**
-     * Send a query stored in a packet directly to the server.
-     *
-     * @param callingStatement DOCUMENT ME!
-     * @param resultSetConcurrency DOCUMENT ME!
-     * @param characterEncoding DOCUMENT ME!
-     * @param queryPacket DOCUMENT ME!
-     * @param maxRows DOCUMENT ME!
-     * @param conn DOCUMENT ME!
-     * @param resultSetType DOCUMENT ME!
-     * @param resultSetConcurrency DOCUMENT ME!
-     * @param streamResults DOCUMENT ME!
-     * @param catalog DOCUMENT ME!
-     * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
-     *
-     * @return DOCUMENT ME!
-     *
-     * @throws Exception DOCUMENT ME!
-     */
-    final ResultSetInternalMethods sqlQueryDirect(StatementImpl callingStatement, String query,
-    		String characterEncoding, Buffer queryPacket, int maxRows,
-    		int resultSetType, int resultSetConcurrency,
-    		boolean streamResults, String catalog, Field[] cachedMetadata)
-    throws Exception {
-    	this.statementExecutionDepth++;
-
-    	try {
-	    	if (this.statementInterceptors != null) {
-	    		ResultSetInternalMethods interceptedResults =
-	    			invokeStatementInterceptorsPre(query, callingStatement);
-
-	    		if (interceptedResults != null) {
-	    			return interceptedResults;
-	    		}
-	    	}
-
-	    	long queryStartTime = 0;
-	    	long queryEndTime = 0;
-
-	    	if (query != null) {
-
-	    		// We don't know exactly how many bytes we're going to get
-	    		// from the query. Since we're dealing with Unicode, the
-	    		// max is 2, so pad it (2 * query) + space for headers
-	    		int packLength = HEADER_LENGTH + 1 + (query.length() * 2) + 2;
-
-	    		String statementComment = this.connection.getStatementComment();
-
-	    		byte[] commentAsBytes = null;
-
-	    		if (statementComment != null) {
-	    			commentAsBytes = StringUtils.getBytes(statementComment, null,
-	    					characterEncoding, this.connection
-	    					.getServerCharacterEncoding(),
-	    					this.connection.parserKnowsUnicode());
-
-	    			packLength += commentAsBytes.length;
-	    			packLength += 6; // for /*[space] [space]*/
-	    		}
-
-	    		if (this.sendPacket == null) {
-	    			this.sendPacket = new Buffer(packLength);
-	    		} else {
-	    			this.sendPacket.clear();
-	    		}
-
-	    		this.sendPacket.writeByte((byte) MysqlDefs.QUERY);
-
-	    		if (commentAsBytes != null) {
-	    			this.sendPacket.writeBytesNoNull(Constants.SLASH_STAR_SPACE_AS_BYTES);
-	    			this.sendPacket.writeBytesNoNull(commentAsBytes);
-	    			this.sendPacket.writeBytesNoNull(Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
-	    		}
-
-	    		if (characterEncoding != null) {
-	    			if (this.platformDbCharsetMatches) {
-	    				this.sendPacket.writeStringNoNull(query, characterEncoding,
-	    						this.connection.getServerCharacterEncoding(),
-	    						this.connection.parserKnowsUnicode(),
-	    						this.connection);
-	    			} else {
-	    				if (StringUtils.startsWithIgnoreCaseAndWs(query, "LOAD DATA")) { //$NON-NLS-1$
-	    					this.sendPacket.writeBytesNoNull(query.getBytes());
-	    				} else {
-	    					this.sendPacket.writeStringNoNull(query,
-	    							characterEncoding,
-	    							this.connection.getServerCharacterEncoding(),
-	    							this.connection.parserKnowsUnicode(),
-	    							this.connection);
-	    				}
-	    			}
-	    		} else {
-	    			this.sendPacket.writeStringNoNull(query);
-	    		}
-
-	    		queryPacket = this.sendPacket;
-	    	}
-
-	    	byte[] queryBuf = null;
-	    	int oldPacketPosition = 0;
-
-	    	if (needToGrabQueryFromPacket) {
-	    		queryBuf = queryPacket.getByteBuffer();
-
-	    		// save the packet position
-	    		oldPacketPosition = queryPacket.getPosition();
-
-	    		queryStartTime = getCurrentTimeNanosOrMillis();
-	    	}
-
-	    	// Send query command and sql query string
-	    	Buffer resultPacket = sendCommand(MysqlDefs.QUERY, null, queryPacket,
-	    			false, null);
-
-	    	long fetchBeginTime = 0;
-	    	long fetchEndTime = 0;
-
-	    	String profileQueryToLog = null;
-
-	    	boolean queryWasSlow = false;
-
-	    	if (this.profileSql || this.logSlowQueries) {
-	    		queryEndTime = System.currentTimeMillis();
-
-	    		boolean shouldExtractQuery = false;
-
-	    		if (this.profileSql) {
-	    			shouldExtractQuery = true;
-	    		} else if (this.logSlowQueries) {
-	    			long queryTime = queryEndTime - queryStartTime;
-	    			
-	    			boolean logSlow = false;
-	    			
-	    			if (this.useAutoSlowLog) {
-	    				logSlow = queryTime > this.connection.getSlowQueryThresholdMillis();
-	    			} else {
-	    				logSlow = this.connection.isAbonormallyLongQuery(queryTime);
-	    				
-	    				this.connection.reportQueryTime(queryTime);
-	    			}
-	    			
-	    			if (logSlow) {
-	    				shouldExtractQuery = true;
-	    				queryWasSlow = true;
-	    			}
-	    		}
-
-	    		if (shouldExtractQuery) {
-	    			// Extract the actual query from the network packet
-	    			boolean truncated = false;
-
-	    			int extractPosition = oldPacketPosition;
-
-	    			if (oldPacketPosition > this.connection.getMaxQuerySizeToLog()) {
-	    				extractPosition = this.connection.getMaxQuerySizeToLog() + 5;
-	    				truncated = true;
-	    			}
-
-	    			profileQueryToLog = new String(queryBuf, 5,
-	    					(extractPosition - 5));
-
-	    			if (truncated) {
-	    				profileQueryToLog += Messages.getString("MysqlIO.25"); //$NON-NLS-1$
-	    			}
-	    		}
-
-	    		fetchBeginTime = queryEndTime;
-	    	}
-
-	    	if (this.autoGenerateTestcaseScript) {
-	    		String testcaseQuery = null;
-
-	    		if (query != null) {
-	    			testcaseQuery = query;
-	    		} else {
-	    			testcaseQuery = new String(queryBuf, 5,
-	    					(oldPacketPosition - 5));
-	    		}
-
-	    		StringBuffer debugBuf = new StringBuffer(testcaseQuery.length() + 32);
-	    		this.connection.generateConnectionCommentBlock(debugBuf);
-	    		debugBuf.append(testcaseQuery);
-	    		debugBuf.append(';');
-	    		this.connection.dumpTestcaseQuery(debugBuf.toString());
-	    	}
-
-	    	ResultSetInternalMethods rs = readAllResults(callingStatement, maxRows, resultSetType,
-	    			resultSetConcurrency, streamResults, catalog, resultPacket,
-	    			false, -1L, cachedMetadata);
-
-	    	if (queryWasSlow) {
-	    		StringBuffer mesgBuf = new StringBuffer(48 +
-	    				profileQueryToLog.length());
-
-	    		mesgBuf.append(Messages.getString("MysqlIO.SlowQuery",
-	    				new Object[] {new Long(this.slowQueryThreshold),
-	    				queryTimingUnits,
-	    				new Long(queryEndTime - queryStartTime)}));
-	    		mesgBuf.append(profileQueryToLog);
-
-	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
-
-	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_SLOW_QUERY,
-	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
-	    				(callingStatement != null) ? callingStatement.getId() : 999,
-	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
-	    						(int) (queryEndTime - queryStartTime), queryTimingUnits, null,
-	    						new Throwable(), mesgBuf.toString()));
-
-	    		if (this.connection.getExplainSlowQueries()) {
-	    			if (oldPacketPosition < MAX_QUERY_SIZE_TO_EXPLAIN) {
-	    				explainSlowQuery(queryPacket.getBytes(5,
-	    						(oldPacketPosition - 5)), profileQueryToLog);
-	    			} else {
-	    				this.connection.getLog().logWarn(Messages.getString(
-	    						"MysqlIO.28") //$NON-NLS-1$
-	    						+MAX_QUERY_SIZE_TO_EXPLAIN +
-	    						Messages.getString("MysqlIO.29")); //$NON-NLS-1$
-	    			}
-	    		}
-	    	}
-
-	    	if (this.logSlowQueries) {
-
-	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
-
-	    		if (this.queryBadIndexUsed) {
-	    			eventSink.consumeEvent(new ProfilerEvent(
-	    					ProfilerEvent.TYPE_SLOW_QUERY, "", catalog, //$NON-NLS-1$
-	    					this.connection.getId(),
-	    					(callingStatement != null) ? callingStatement.getId()
-	    							: 999, ((ResultSetImpl)rs).resultId,
-	    							System.currentTimeMillis(),
-	    							(queryEndTime - queryStartTime), this.queryTimingUnits,
-	    							null,
-	    							new Throwable(),
-	    							Messages.getString("MysqlIO.33") //$NON-NLS-1$
-	    							+profileQueryToLog));
-	    		}
-
-	    		if (this.queryNoIndexUsed) {
-	    			eventSink.consumeEvent(new ProfilerEvent(
-	    					ProfilerEvent.TYPE_SLOW_QUERY, "", catalog, //$NON-NLS-1$
-	    					this.connection.getId(),
-	    					(callingStatement != null) ? callingStatement.getId()
-	    							: 999, ((ResultSetImpl)rs).resultId,
-	    							System.currentTimeMillis(),
-	    							(queryEndTime - queryStartTime), this.queryTimingUnits,
-	    							null,
-	    							new Throwable(),
-	    							Messages.getString("MysqlIO.35") //$NON-NLS-1$
-	    							+profileQueryToLog));
-	    		}
-	    	}
-
-	    	if (this.profileSql) {
-	    		fetchEndTime = getCurrentTimeNanosOrMillis();
-
-	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
-
-	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_QUERY,
-	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
-	    				(callingStatement != null) ? callingStatement.getId() : 999,
-	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
-	    						(queryEndTime - queryStartTime), this.queryTimingUnits,
-	    						null,
-	    						new Throwable(), profileQueryToLog));
-
-	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_FETCH,
-	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
-	    				(callingStatement != null) ? callingStatement.getId() : 999,
-	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
-	    						(fetchEndTime - fetchBeginTime), this.queryTimingUnits,
-	    						null,
-	    						new Throwable(), null));
-	    	}
-
-	    	if (this.hadWarnings) {
-	    		scanForAndThrowDataTruncation();
-	    	}
-
-	    	if (this.statementInterceptors != null) {
-	    		ResultSetInternalMethods interceptedResults = invokeStatementInterceptorsPost(
-	    				query, callingStatement, rs);
-
-	    		if (interceptedResults != null) {
-	    			rs = interceptedResults;
-	    		}
-	    	}
-
-	    	return rs;
-    	} finally {
-    		this.statementExecutionDepth--;
-    	}
-    }
-
-    private ResultSetInternalMethods invokeStatementInterceptorsPre(String sql,
-			Statement interceptedStatement) throws SQLException {
-		ResultSetInternalMethods previousResultSet = null;
-
-		Iterator interceptors = this.statementInterceptors.iterator();
-
-		while (interceptors.hasNext()) {
-			StatementInterceptor interceptor = ((StatementInterceptor) interceptors
-					.next());
-
-			boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
-			boolean shouldExecute = (executeTopLevelOnly && this.statementExecutionDepth == 1)
-					|| (!executeTopLevelOnly);
-
-			if (shouldExecute) {
-				String sqlToInterceptor = sql;
-
-				if (interceptedStatement instanceof PreparedStatement) {
-					sqlToInterceptor = ((PreparedStatement) interceptedStatement)
-							.asSql();
-				}
-
-				ResultSetInternalMethods interceptedResultSet = interceptor
-						.preProcess(sqlToInterceptor, interceptedStatement,
-								this.connection);
-
-				if (interceptedResultSet != null) {
-					previousResultSet = interceptedResultSet;
-				}
-			}
-		}
-
-		return previousResultSet;
-	}
-
-	private ResultSetInternalMethods invokeStatementInterceptorsPost(
-			String sql, Statement interceptedStatement,
-			ResultSetInternalMethods originalResultSet) throws SQLException {
-		Iterator interceptors = this.statementInterceptors.iterator();
-
-		while (interceptors.hasNext()) {
-			StatementInterceptor interceptor = ((StatementInterceptor) interceptors
-					.next());
-
-			boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
-			boolean shouldExecute = (executeTopLevelOnly && this.statementExecutionDepth == 1)
-					|| (!executeTopLevelOnly);
-
-			if (shouldExecute) {
-				String sqlToInterceptor = sql;
-
-				if (interceptedStatement instanceof PreparedStatement) {
-					sqlToInterceptor = ((PreparedStatement) interceptedStatement)
-							.asSql();
-				}
-
-				ResultSetInternalMethods interceptedResultSet = interceptor
-						.postProcess(sqlToInterceptor, interceptedStatement,
-								originalResultSet, this.connection);
-
-				if (interceptedResultSet != null) {
-					originalResultSet = interceptedResultSet;
-				}
-			}
-		}
-
-		return originalResultSet;
-	}
-
-	private void calculateSlowQueryThreshold() {
-		this.slowQueryThreshold = this.connection.getSlowQueryThresholdMillis();
-
-		if (this.connection.getUseNanosForElapsedTime()) {
-			long nanosThreshold = this.connection.getSlowQueryThresholdNanos();
-
-			if (nanosThreshold != 0) {
-				this.slowQueryThreshold = nanosThreshold;
-			} else {
-				this.slowQueryThreshold *= 1000000; // 1 million millis in a nano
-			}
-		}
-	}
-
-	protected long getCurrentTimeNanosOrMillis() {
-		if (this.useNanosForElapsedTime) {
-			return Util.getCurrentTimeNanosOrMillis();
-		}
-
-		return System.currentTimeMillis();
-	}
-
-    /**
-     * Returns the host this IO is connected to
-     *
-     * @return DOCUMENT ME!
-     */
-    String getHost() {
-        return this.host;
-    }
-
-    /**
-     * Is the version of the MySQL server we are connected to the given
-     * version?
-     *
-     * @param major the major version
-     * @param minor the minor version
-     * @param subminor the subminor version
-     *
-     * @return true if the version of the MySQL server we are connected  is the
-     *         given version
-     */
-    boolean isVersion(int major, int minor, int subminor) {
-        return ((major == getServerMajorVersion()) &&
-        (minor == getServerMinorVersion()) &&
-        (subminor == getServerSubMinorVersion()));
-    }
-
-    /**
-     * Does the version of the MySQL server we are connected to meet the given
-     * minimums?
-     *
-     * @param major DOCUMENT ME!
-     * @param minor DOCUMENT ME!
-     * @param subminor DOCUMENT ME!
-     *
-     * @return DOCUMENT ME!
-     */
-    boolean versionMeetsMinimum(int major, int minor, int subminor) {
-        if (getServerMajorVersion() >= major) {
-            if (getServerMajorVersion() == major) {
-                if (getServerMinorVersion() >= minor) {
-                    if (getServerMinorVersion() == minor) {
-                        return (getServerSubMinorVersion() >= subminor);
-                    }
-
-                    // newer than major.minor
-                    return true;
-                }
-
-                // older than major.minor
-                return false;
-            }
-
-            // newer than major
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the hex dump of the given packet, truncated to
-     * MAX_PACKET_DUMP_LENGTH if packetLength exceeds that value.
-     *
-     * @param packetToDump the packet to dump in hex
-     * @param packetLength the number of bytes to dump
-     *
-     * @return the hex dump of the given packet
-     */
-    private final static String getPacketDumpToLog(Buffer packetToDump,
-        int packetLength) {
-        if (packetLength < MAX_PACKET_DUMP_LENGTH) {
-            return packetToDump.dump(packetLength);
-        }
-
-        StringBuffer packetDumpBuf = new StringBuffer(MAX_PACKET_DUMP_LENGTH * 4);
-        packetDumpBuf.append(packetToDump.dump(MAX_PACKET_DUMP_LENGTH));
-        packetDumpBuf.append(Messages.getString("MysqlIO.36")); //$NON-NLS-1$
-        packetDumpBuf.append(MAX_PACKET_DUMP_LENGTH);
-        packetDumpBuf.append(Messages.getString("MysqlIO.37")); //$NON-NLS-1$
-
-        return packetDumpBuf.toString();
-    }
-
-    private final int readFully(InputStream in, byte[] b, int off, int len)
-        throws IOException {
-        if (len < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        int n = 0;
-
-        while (n < len) {
-            int count = in.read(b, off + n, len - n);
-
-            if (count < 0) {
-                throw new EOFException(Messages.getString("MysqlIO.EOF",
-                		new Object[] {new Integer(len), new Integer(n)}));
-            }
-
-            n += count;
-        }
-
-        return n;
-    }
-
-    private final long skipFully(InputStream in, long len) throws IOException {
-    	if (len < 0) {
-    		throw new IOException("Negative skip length not allowed");
-    	}
-
-    	long n = 0;
-
-    	while (n < len) {
-    		long count = in.skip(len - n);
-
-    		if (count < 0) {
-    			throw new EOFException(Messages.getString("MysqlIO.EOF",
-                		new Object[] {new Long(len), new Long(n)}));
-    		}
-
-    		n += count;
-    	}
-
-    	return n;
-    }
-
-    /**
-     * Reads one result set off of the wire, if the result is actually an
-     * update count, creates an update-count only result set.
-     *
-     * @param callingStatement DOCUMENT ME!
-     * @param maxRows the maximum rows to return in the result set.
-     * @param resultSetType scrollability
-     * @param resultSetConcurrency updatability
-     * @param streamResults should the driver leave the results on the wire,
-     *        and read them only when needed?
-     * @param catalog the catalog in use
-     * @param resultPacket the first packet of information in the result set
-     * @param isBinaryEncoded is this result set from a prepared statement?
-     * @param preSentColumnCount do we already know the number of columns?
-     * @param unpackFieldInfo should we unpack the field information?
-     *
-     * @return a result set that either represents the rows, or an update count
-     *
-     * @throws SQLException if an error occurs while reading the rows
-     */
-    protected final ResultSetImpl readResultsForQueryOrUpdate(
-        StatementImpl callingStatement, int maxRows, int resultSetType,
-        int resultSetConcurrency, boolean streamResults, String catalog,
-        Buffer resultPacket, boolean isBinaryEncoded, long preSentColumnCount,
-        Field[] metadataFromCache) throws SQLException {
-        long columnCount = resultPacket.readFieldLength();
-
-        if (columnCount == 0) {
-            return buildResultSetWithUpdates(callingStatement, resultPacket);
-        } else if (columnCount == Buffer.NULL_LENGTH) {
-            String charEncoding = null;
-
-            if (this.connection.getUseUnicode()) {
-                charEncoding = this.connection.getEncoding();
-            }
-
-            String fileName = null;
-
-            if (this.platformDbCharsetMatches) {
-                fileName = ((charEncoding != null)
-                    ? resultPacket.readString(charEncoding)
-                    : resultPacket.readString());
-            } else {
-                fileName = resultPacket.readString();
-            }
-
-            return sendFileToServer(callingStatement, fileName);
-        } else {
-            com.mysql.jdbc.ResultSetImpl results = getResultSet(callingStatement,
-                    columnCount, maxRows, resultSetType, resultSetConcurrency,
-                    streamResults, catalog, isBinaryEncoded,
-                    metadataFromCache);
-
-            return results;
-        }
-    }
-
-    private int alignPacketSize(int a, int l) {
-        return ((((a) + (l)) - 1) & ~((l) - 1));
-    }
-
-    private com.mysql.jdbc.ResultSetImpl buildResultSetWithRows(
-        StatementImpl callingStatement, String catalog,
-        com.mysql.jdbc.Field[] fields, RowData rows, int resultSetType,
-        int resultSetConcurrency, boolean isBinaryEncoded)
-        throws SQLException {
-        ResultSetImpl rs = null;
-
-        switch (resultSetConcurrency) {
-        case java.sql.ResultSet.CONCUR_READ_ONLY:
-            rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
-                    this.connection, callingStatement, false);
-
-            if (isBinaryEncoded) {
-                rs.setBinaryEncoded();
-            }
-
-            break;
-
-        case java.sql.ResultSet.CONCUR_UPDATABLE:
-            rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
-                    this.connection, callingStatement, true);
-
-            break;
-
-        default:
-            return com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
-                this.connection, callingStatement, false);
-        }
-
-        rs.setResultSetType(resultSetType);
-        rs.setResultSetConcurrency(resultSetConcurrency);
-
-        return rs;
-    }
-
-    private com.mysql.jdbc.ResultSetImpl buildResultSetWithUpdates(
-        StatementImpl callingStatement, Buffer resultPacket)
-        throws SQLException {
-        long updateCount = -1;
-        long updateID = -1;
-        String info = null;
-
-        try {
-            if (this.useNewUpdateCounts) {
-                updateCount = resultPacket.newReadLength();
-                updateID = resultPacket.newReadLength();
-            } else {
-                updateCount = resultPacket.readLength();
-                updateID = resultPacket.readLength();
-            }
-
-            if (this.use41Extensions) {
-                this.serverStatus = resultPacket.readInt();
-
-                this.warningCount = resultPacket.readInt();
-
-                if (this.warningCount > 0) {
-                    this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
-                }
-
-                resultPacket.readByte(); // advance pointer
-
-                if (this.profileSql) {
-                    this.queryNoIndexUsed = (this.serverStatus &
-                        SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
-                    this.queryBadIndexUsed = (this.serverStatus &
-                        SERVER_QUERY_NO_INDEX_USED) != 0;
-                }
-            }
-
-            if (this.connection.isReadInfoMsgEnabled()) {
-                info = resultPacket.readString();
-            }
-        } catch (Exception ex) {
-            SQLException sqlEx = SQLError.createSQLException(SQLError.get(
-                    SQLError.SQL_STATE_GENERAL_ERROR), SQLError.SQL_STATE_GENERAL_ERROR, -1);
-            sqlEx.initCause(ex);
-            
-            throw sqlEx;
-        }
-
-        ResultSetInternalMethods updateRs = com.mysql.jdbc.ResultSetImpl.getInstance(updateCount,
-                updateID, this.connection, callingStatement);
-
-        if (info != null) {
-            ((com.mysql.jdbc.ResultSetImpl)updateRs).setServerInfo(info);
-        }
-
-        return (com.mysql.jdbc.ResultSetImpl)updateRs;
-    }
-
-    private void checkForOutstandingStreamingData() throws SQLException {
-        if (this.streamingData != null) {
-        	boolean shouldClobber = this.connection.getClobberStreamingResults();
-
-            if (!shouldClobber) {
-                throw SQLError.createSQLException(Messages.getString("MysqlIO.39") //$NON-NLS-1$
-                     +this.streamingData +
-                    Messages.getString("MysqlIO.40") //$NON-NLS-1$
-                     +Messages.getString("MysqlIO.41") //$NON-NLS-1$
-                     +Messages.getString("MysqlIO.42")); //$NON-NLS-1$
-            }
-
-            // Close the result set
-            this.streamingData.getOwner().realClose(false);
-
-            // clear any pending data....
-            clearInputStream();
-        }
-    }
-
-    private Buffer compressPacket(Buffer packet, int offset, int packetLen,
-        int headerLength) throws SQLException {
-        packet.writeLongInt(packetLen - headerLength);
-        packet.writeByte((byte) 0); // wrapped packet has 0 packet seq.
-
-        int lengthToWrite = 0;
-        int compressedLength = 0;
-        byte[] bytesToCompress = packet.getByteBuffer();
-        byte[] compressedBytes = null;
-        int offsetWrite = 0;
-
-        if (packetLen < MIN_COMPRESS_LEN) {
-            lengthToWrite = packetLen;
-            compressedBytes = packet.getByteBuffer();
-            compressedLength = 0;
-            offsetWrite = offset;
-        } else {
-            compressedBytes = new byte[bytesToCompress.length * 2];
-
-            this.deflater.reset();
-            this.deflater.setInput(bytesToCompress, offset, packetLen);
-            this.deflater.finish();
-
-            int compLen = this.deflater.deflate(compressedBytes);
-
-            if (compLen > packetLen) {
-                lengthToWrite = packetLen;
-                compressedBytes = packet.getByteBuffer();
-                compressedLength = 0;
-                offsetWrite = offset;
-            } else {
-                lengthToWrite = compLen;
-                headerLength += COMP_HEADER_LENGTH;
-                compressedLength = packetLen;
-            }
-        }
-
-        Buffer compressedPacket = new Buffer(packetLen + headerLength);
-
-        compressedPacket.setPosition(0);
-        compressedPacket.writeLongInt(lengthToWrite);
-        compressedPacket.writeByte(this.packetSequence);
-        compressedPacket.writeLongInt(compressedLength);
-        compressedPacket.writeBytesNoNull(compressedBytes, offsetWrite,
-            lengthToWrite);
-
-        return compressedPacket;
-    }
-
-    private final void readServerStatusForResultSets(Buffer rowPacket)
-        throws SQLException {
-        if (this.use41Extensions) {
-            rowPacket.readByte(); // skips the 'last packet' flag
-
-            this.warningCount = rowPacket.readInt();
-
-            if (this.warningCount > 0) {
-                this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
-            }
-
-            this.serverStatus = rowPacket.readInt();
-
-            if (this.profileSql) {
-                this.queryNoIndexUsed = (this.serverStatus &
-                    SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
-                this.queryBadIndexUsed = (this.serverStatus &
-                    SERVER_QUERY_NO_INDEX_USED) != 0;
-            }
-        }
-    }
-
-    private SocketFactory createSocketFactory() throws SQLException {
-        try {
-            if (this.socketFactoryClassName == null) {
-                throw SQLError.createSQLException(Messages.getString("MysqlIO.75"), //$NON-NLS-1$
-                    SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
-            }
-
-            return (SocketFactory) (Class.forName(this.socketFactoryClassName)
-                                         .newInstance());
-        } catch (Exception ex) {
-            SQLException sqlEx = SQLError.createSQLException(Messages.getString("MysqlIO.76") //$NON-NLS-1$
-                 +this.socketFactoryClassName +
-                Messages.getString("MysqlIO.77"),
-                SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
-            
-            sqlEx.initCause(ex);
-            
-            throw sqlEx;
-        }
-    }
-
-    private void enqueuePacketForDebugging(boolean isPacketBeingSent,
-        boolean isPacketReused, int sendLength, byte[] header, Buffer packet)
-        throws SQLException {
-        if ((this.packetDebugRingBuffer.size() + 1) > this.connection.getPacketDebugBufferSize()) {
-            this.packetDebugRingBuffer.removeFirst();
-        }
-
-        StringBuffer packetDump = null;
-
-        if (!isPacketBeingSent) {
-            int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH,
-                    packet.getBufLength());
-
-            Buffer packetToDump = new Buffer(4 + bytesToDump);
-
-            packetToDump.setPosition(0);
-            packetToDump.writeBytesNoNull(header);
-            packetToDump.writeBytesNoNull(packet.getBytes(0, bytesToDump));
-
-            String packetPayload = packetToDump.dump(bytesToDump);
-
-            packetDump = new StringBuffer(96 + packetPayload.length());
-
-            packetDump.append("Server ");
-
-            if (isPacketReused) {
-                packetDump.append("(re-used)");
-            } else {
-                packetDump.append("(new)");
-            }
-
-            packetDump.append(" ");
-            packetDump.append(packet.toSuperString());
-            packetDump.append(" --------------------> Client\n");
-            packetDump.append("\nPacket payload:\n\n");
-            packetDump.append(packetPayload);
-
-            if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
-                packetDump.append("\nNote: Packet of " + packet.getBufLength() +
-                    " bytes truncated to " + MAX_PACKET_DUMP_LENGTH +
-                    " bytes.\n");
-            }
-        } else {
-            int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH, sendLength);
-
-            String packetPayload = packet.dump(bytesToDump);
-
-            packetDump = new StringBuffer(64 + 4 + packetPayload.length());
-
-            packetDump.append("Client ");
-            packetDump.append(packet.toSuperString());
-            packetDump.append("--------------------> Server\n");
-            packetDump.append("\nPacket payload:\n\n");
-            packetDump.append(packetPayload);
-
-            if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
-                packetDump.append("\nNote: Packet of " + sendLength +
-                    " bytes truncated to " + MAX_PACKET_DUMP_LENGTH +
-                    " bytes.\n");
-            }
-        }
-
-        this.packetDebugRingBuffer.addLast(packetDump);
-    }
-
-    private RowData readSingleRowSet(long columnCount, int maxRows,
-        int resultSetConcurrency, boolean isBinaryEncoded, Field[] fields)
-        throws SQLException {
-        RowData rowData;
-        ArrayList rows = new ArrayList();
-
-        boolean useBufferRowExplicit = useBufferRowExplicit(fields);
-
-        // Now read the data
-        ResultSetRow row = nextRow(fields, (int) columnCount, isBinaryEncoded,
-                resultSetConcurrency, false, useBufferRowExplicit, false, null);
-
-        int rowCount = 0;
-
-        if (row != null) {
-            rows.add(row);
-            rowCount = 1;
-        }
-
-        while (row != null) {
-        	row = nextRow(fields, (int) columnCount, isBinaryEncoded,
-                    resultSetConcurrency, false, useBufferRowExplicit, false, null);
-
-            if (row != null) {
-            	if ((maxRows == -1) || (rowCount < maxRows)) {
-            		rows.add(row);
-            		rowCount++;
-            	}
-            }
-        }
-
-        rowData = new RowDataStatic(rows);
-
-        return rowData;
-    }
-
-    public static boolean useBufferRowExplicit(Field[] fields) {
-    	if (fields == null) {
-    		return false;
-    	}
-
-		for (int i = 0; i < fields.length; i++) {
-			switch (fields[i].getSQLType()) {
-			case Types.BLOB:
-			case Types.CLOB:
-			case Types.LONGVARBINARY:
-			case Types.LONGVARCHAR:
-				return true;
-			}
-		}
-
-		return false;
-	}
-
-	/**
-     * Don't hold on to overly-large packets
-     */
-    private void reclaimLargeReusablePacket() {
-        if ((this.reusablePacket != null) &&
-                (this.reusablePacket.getCapacity() > 1048576)) {
-            this.reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
-        }
-    }
-
-    /**
-     * Re-use a packet to read from the MySQL server
-     *
-     * @param reuse DOCUMENT ME!
-     *
-     * @return DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     * @throws SQLException DOCUMENT ME!
-     */
-    private final Buffer reuseAndReadPacket(Buffer reuse) throws SQLException {
-    	return reuseAndReadPacket(reuse, -1);
-    }
-
-    private final Buffer reuseAndReadPacket(Buffer reuse, int existingPacketLength)
-        throws SQLException {
-
-    	try {
-    		reuse.setWasMultiPacket(false);
-    		int packetLength = 0;
-
-    		if (existingPacketLength == -1) {
-	    		int lengthRead = readFully(this.mysqlInput,
-	    				this.packetHeaderBuf, 0, 4);
-
-	    		if (lengthRead < 4) {
-	    			forceClose();
-	    			throw new IOException(Messages.getString("MysqlIO.43")); //$NON-NLS-1$
-	    		}
-
-	    		packetLength = (this.packetHeaderBuf[0] & 0xff) +
-	    		((this.packetHeaderBuf[1] & 0xff) << 8) +
-	    		((this.packetHeaderBuf[2] & 0xff) << 16);
-    		} else {
-    			packetLength = existingPacketLength;
-    		}
-
-    		if (this.traceProtocol) {
-    			StringBuffer traceMessageBuf = new StringBuffer();
-
-    			traceMessageBuf.append(Messages.getString("MysqlIO.44")); //$NON-NLS-1$
-    			traceMessageBuf.append(packetLength);
-    			traceMessageBuf.append(Messages.getString("MysqlIO.45")); //$NON-NLS-1$
-    			traceMessageBuf.append(StringUtils.dumpAsHex(
-    					this.packetHeaderBuf, 4));
-
-    			this.connection.getLog().logTrace(traceMessageBuf.toString());
-    		}
-
-    		byte multiPacketSeq = this.packetHeaderBuf[3];
-
-    		if (!this.packetSequenceReset) {
-    			if (this.enablePacketDebug && this.checkPacketSequence) {
-    				checkPacketSequencing(multiPacketSeq);
-    			}
-    		} else {
-    			this.packetSequenceReset = false;
-    		}
-
-    		this.readPacketSequence = multiPacketSeq;
-
-    		// Set the Buffer to it's original state
-    		reuse.setPosition(0);
-
-    		// Do we need to re-alloc the byte buffer?
-    		//
-    		// Note: We actually check the length of the buffer,
-    		// rather than getBufLength(), because getBufLength() is not
-    		// necesarily the actual length of the byte array
-    		// used as the buffer
-    		if (reuse.getByteBuffer().length <= packetLength) {
-    			reuse.setByteBuffer(new byte[packetLength + 1]);
-    		}
-
-    		// Set the new length
-    		reuse.setBufLength(packetLength);
-
-    		// Read the data from the server
-    		int numBytesRead = readFully(this.mysqlInput,
-    				reuse.getByteBuffer(), 0, packetLength);
-
-    		if (numBytesRead != packetLength) {
-    			throw new IOException("Short read, expected " +
-    					packetLength + " bytes, only read " + numBytesRead);
-    		}
-
-    		if (this.traceProtocol) {
-    			StringBuffer traceMessageBuf = new StringBuffer();
-
-    			traceMessageBuf.append(Messages.getString("MysqlIO.46")); //$NON-NLS-1$
-    			traceMessageBuf.append(getPacketDumpToLog(reuse,
-    					packetLength));
-
-    			this.connection.getLog().logTrace(traceMessageBuf.toString());
-    		}
-
-    		if (this.enablePacketDebug) {
-    			enqueuePacketForDebugging(false, true, 0,
-    					this.packetHeaderBuf, reuse);
-    		}
-
-    		boolean isMultiPacket = false;
-
-    		if (packetLength == this.maxThreeBytes) {
-    			reuse.setPosition(this.maxThreeBytes);
-
-    			int packetEndPoint = packetLength;
-
-    			// it's multi-packet
-    			isMultiPacket = true;
-
-    			packetLength = readRemainingMultiPackets(reuse, multiPacketSeq,
-						packetEndPoint);
-    		}
-
-    		if (!isMultiPacket) {
-    			reuse.getByteBuffer()[packetLength] = 0; // Null-termination
-    		}
-
-    		return reuse;
-    	} catch (IOException ioEx) {
-    		throw SQLError.createCommunicationsException(this.connection,
-    				this.lastPacketSentTimeMs, ioEx);
-    	} catch (OutOfMemoryError oom) {
-    		try {
-    			// _Try_ this
-    			clearInputStream();
-    		} finally {
-    			try {
-    				this.connection.realClose(false, false, true, oom);
-    			} finally {
-    				throw oom;
-    			}
-    		}
-    	}
-
-    }
-
-	private int readRemainingMultiPackets(Buffer reuse, byte multiPacketSeq,
-			int packetEndPoint) throws IOException, SQLException {
-		int lengthRead;
-		int packetLength;
-		lengthRead = readFully(this.mysqlInput,
-				this.packetHeaderBuf, 0, 4);
-
-		if (lengthRead < 4) {
-			forceClose();
-			throw new IOException(Messages.getString("MysqlIO.47")); //$NON-NLS-1$
-		}
-
-		packetLength = (this.packetHeaderBuf[0] & 0xff) +
-			((this.packetHeaderBuf[1] & 0xff) << 8) +
-			((this.packetHeaderBuf[2] & 0xff) << 16);
-
-		Buffer multiPacket = new Buffer(packetLength);
-		boolean firstMultiPkt = true;
-
-		while (true) {
-			if (!firstMultiPkt) {
-				lengthRead = readFully(this.mysqlInput,
-						this.packetHeaderBuf, 0, 4);
-
-				if (lengthRead < 4) {
-					forceClose();
-					throw new IOException(Messages.getString(
-					"MysqlIO.48")); //$NON-NLS-1$
-				}
-
-				packetLength = (this.packetHeaderBuf[0] & 0xff) +
-				((this.packetHeaderBuf[1] & 0xff) << 8) +
-				((this.packetHeaderBuf[2] & 0xff) << 16);
-			} else {
-				firstMultiPkt = false;
-			}
-
-			if (!this.useNewLargePackets && (packetLength == 1)) {
-				clearInputStream();
-
-				break;
-			} else if (packetLength < this.maxThreeBytes) {
-				byte newPacketSeq = this.packetHeaderBuf[3];
-
-				if (newPacketSeq != (multiPacketSeq + 1)) {
-					throw new IOException(Messages.getString(
-					"MysqlIO.49")); //$NON-NLS-1$
-				}
-
-				multiPacketSeq = newPacketSeq;
-
-				// Set the Buffer to it's original state
-				multiPacket.setPosition(0);
-
-				// Set the new length
-				multiPacket.setBufLength(packetLength);
-
-				// Read the data from the server
-				byte[] byteBuf = multiPacket.getByteBuffer();
-				int lengthToWrite = packetLength;
-
-				int bytesRead = readFully(this.mysqlInput, byteBuf,
-						0, packetLength);
-
-				if (bytesRead != lengthToWrite) {
-					throw SQLError.createCommunicationsException(this.connection,
-							this.lastPacketSentTimeMs,
-							SQLError.createSQLException(Messages.getString(
-							"MysqlIO.50") //$NON-NLS-1$
-							+lengthToWrite +
-							Messages.getString("MysqlIO.51") +
-							bytesRead //$NON-NLS-1$
-							+".")); //$NON-NLS-1$
-				}
-
-				reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
-
-				packetEndPoint += lengthToWrite;
-
-				break; // end of multipacket sequence
-			}
-
-			byte newPacketSeq = this.packetHeaderBuf[3];
-
-			if (newPacketSeq != (multiPacketSeq + 1)) {
-				throw new IOException(Messages.getString(
-				"MysqlIO.53")); //$NON-NLS-1$
-			}
-
-			multiPacketSeq = newPacketSeq;
-
-			// Set the Buffer to it's original state
-			multiPacket.setPosition(0);
-
-			// Set the new length
-			multiPacket.setBufLength(packetLength);
-
-			// Read the data from the server
-			byte[] byteBuf = multiPacket.getByteBuffer();
-			int lengthToWrite = packetLength;
-
-			int bytesRead = readFully(this.mysqlInput, byteBuf, 0,
-					packetLength);
-
-			if (bytesRead != lengthToWrite) {
-				throw SQLError.createCommunicationsException(this.connection,
-						this.lastPacketSentTimeMs,
-						SQLError.createSQLException(Messages.getString(
-						"MysqlIO.54") //$NON-NLS-1$
-						+lengthToWrite +
-						Messages.getString("MysqlIO.55") //$NON-NLS-1$
-						+bytesRead + ".")); //$NON-NLS-1$
-			}
-
-			reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
-
-			packetEndPoint += lengthToWrite;
-		}
-
-		reuse.setPosition(0);
-		reuse.setWasMultiPacket(true);
-		return packetLength;
-	}
-
-    /**
-         * @param multiPacketSeq
-         * @throws CommunicationsException
-         */
-    private void checkPacketSequencing(byte multiPacketSeq)
-        throws SQLException {
-        if ((multiPacketSeq == -128) && (this.readPacketSequence != 127)) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs,
-                new IOException("Packets out of order, expected packet # -128, but received packet # " +
-                    multiPacketSeq));
-        }
-
-        if ((this.readPacketSequence == -1) && (multiPacketSeq != 0)) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs,
-                new IOException("Packets out of order, expected packet # -1, but received packet # " +
-                    multiPacketSeq));
-        }
-
-        if ((multiPacketSeq != -128) && (this.readPacketSequence != -1) &&
-                (multiPacketSeq != (this.readPacketSequence + 1))) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs,
-                new IOException("Packets out of order, expected packet # " +
-                    (this.readPacketSequence + 1) + ", but received packet # " +
-                    multiPacketSeq));
-        }
-    }
-
-    void enableMultiQueries() throws SQLException {
-    	Buffer buf = getSharedSendPacket();
-
-    	buf.clear();
-    	buf.writeByte((byte)MysqlDefs.COM_SET_OPTION);
-    	buf.writeInt(0);
-    	sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
-    }
-
-    void disableMultiQueries() throws SQLException {
-    	Buffer buf = getSharedSendPacket();
-
-    	buf.clear();
-    	buf.writeByte((byte)MysqlDefs.COM_SET_OPTION);
-    	buf.writeInt(1);
-    	sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
-    }
-
-    private final void send(Buffer packet, int packetLen)
-        throws SQLException {
-        try {
-            if (packetLen > this.maxAllowedPacket) {
-                throw new PacketTooBigException(packetLen, this.maxAllowedPacket);
-            }
-
-			if (this.connection.getMaintainTimeStats()) {
-				this.lastPacketSentTimeMs = System.currentTimeMillis();
-			}
-
-            if ((this.serverMajorVersion >= 4) &&
-                    (packetLen >= this.maxThreeBytes)) {
-                sendSplitPackets(packet);
-            } else {
-                this.packetSequence++;
-
-                Buffer packetToSend = packet;
-
-                packetToSend.setPosition(0);
-
-                if (this.useCompression) {
-                    int originalPacketLen = packetLen;
-
-                    packetToSend = compressPacket(packet, 0, packetLen,
-                            HEADER_LENGTH);
-                    packetLen = packetToSend.getPosition();
-
-                    if (this.traceProtocol) {
-                        StringBuffer traceMessageBuf = new StringBuffer();
-
-                        traceMessageBuf.append(Messages.getString("MysqlIO.57")); //$NON-NLS-1$
-                        traceMessageBuf.append(getPacketDumpToLog(
-                                packetToSend, packetLen));
-                        traceMessageBuf.append(Messages.getString("MysqlIO.58")); //$NON-NLS-1$
-                        traceMessageBuf.append(getPacketDumpToLog(packet,
-                                originalPacketLen));
-
-                        this.connection.getLog().logTrace(traceMessageBuf.toString());
-                    }
-                } else {
-                    packetToSend.writeLongInt(packetLen - HEADER_LENGTH);
-                    packetToSend.writeByte(this.packetSequence);
-
-                    if (this.traceProtocol) {
-                        StringBuffer traceMessageBuf = new StringBuffer();
-
-                        traceMessageBuf.append(Messages.getString("MysqlIO.59")); //$NON-NLS-1$
-                        traceMessageBuf.append(packetToSend.dump(packetLen));
-
-                        this.connection.getLog().logTrace(traceMessageBuf.toString());
-                    }
-                }
-
-
-                this.mysqlOutput.write(packetToSend.getByteBuffer(), 0,
-                		packetLen);
-                this.mysqlOutput.flush();
-            }
-
-            if (this.enablePacketDebug) {
-                enqueuePacketForDebugging(true, false, packetLen + 5,
-                    this.packetHeaderBuf, packet);
-            }
-
-            //
-            // Don't hold on to large packets
-            //
-            if (packet == this.sharedSendPacket) {
-                reclaimLargeSharedSendPacket();
-            }
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-    /**
-     * Reads and sends a file to the server for LOAD DATA LOCAL INFILE
-     *
-     * @param callingStatement DOCUMENT ME!
-     * @param fileName the file name to send.
-     *
-     * @return DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    private final ResultSetImpl sendFileToServer(StatementImpl callingStatement,
-        String fileName) throws SQLException {
-
-        Buffer filePacket = (this.loadFileBufRef == null) ? null
-                                                          : (Buffer) (this.loadFileBufRef.get());
-
-        int bigPacketLength = Math.min(this.connection.getMaxAllowedPacket() -
-                (HEADER_LENGTH * 3),
-                alignPacketSize(this.connection.getMaxAllowedPacket() - 16, 4096) -
-                (HEADER_LENGTH * 3));
-
-        int oneMeg = 1024 * 1024;
-
-        int smallerPacketSizeAligned = Math.min(oneMeg - (HEADER_LENGTH * 3),
-        		alignPacketSize(oneMeg - 16, 4096) - (HEADER_LENGTH * 3));
-
-        int packetLength = Math.min(smallerPacketSizeAligned, bigPacketLength);
-
-        if (filePacket == null) {
-        	try {
-        		filePacket = new Buffer((packetLength + HEADER_LENGTH));
-        		this.loadFileBufRef = new SoftReference(filePacket);
-        	} catch (OutOfMemoryError oom) {
-        		throw SQLError.createSQLException("Could not allocate packet of " + packetLength
-        				+ " bytes required for LOAD DATA LOCAL INFILE operation."
-						+ " Try increasing max heap allocation for JVM or decreasing server variable "
-						+ "'max_allowed_packet'", SQLError.SQL_STATE_MEMORY_ALLOCATION_FAILURE);
-
-        	}
-        }
-
-        filePacket.clear();
-        send(filePacket, 0);
-
-        byte[] fileBuf = new byte[packetLength];
-
-        BufferedInputStream fileIn = null;
-
-        try {
-        	if (!this.connection.getAllowLoadLocalInfile()) {
-        		throw SQLError.createSQLException(
-        				Messages.getString("MysqlIO.LoadDataLocalNotAllowed"),
-        				SQLError.SQL_STATE_GENERAL_ERROR);
-        	}
-
-        	InputStream hookedStream = null;
-
-        	if (callingStatement != null) {
-        	    hookedStream = callingStatement.getLocalInfileInputStream();
-        	}
-
-        	if (hookedStream != null) {
-        	    fileIn = new BufferedInputStream(hookedStream);
-        	} else if (!this.connection.getAllowUrlInLocalInfile()) {
-                fileIn = new BufferedInputStream(new FileInputStream(fileName));
-            } else {
-                // First look for ':'
-                if (fileName.indexOf(':') != -1) {
-                    try {
-                        URL urlFromFileName = new URL(fileName);
-                        fileIn = new BufferedInputStream(urlFromFileName.openStream());
-                    } catch (MalformedURLException badUrlEx) {
-                        // we fall back to trying this as a file input stream
-                        fileIn = new BufferedInputStream(new FileInputStream(
-                                    fileName));
-                    }
-                } else {
-                    fileIn = new BufferedInputStream(new FileInputStream(
-                                fileName));
-                }
-            }
-
-            int bytesRead = 0;
-
-            while ((bytesRead = fileIn.read(fileBuf)) != -1) {
-                filePacket.clear();
-                filePacket.writeBytesNoNull(fileBuf, 0, bytesRead);
-                send(filePacket, filePacket.getPosition());
-            }
-        } catch (IOException ioEx) {
-            StringBuffer messageBuf = new StringBuffer(Messages.getString(
-                        "MysqlIO.60")); //$NON-NLS-1$
-
-            if (!this.connection.getParanoid()) {
-                messageBuf.append("'"); //$NON-NLS-1$
-
-                if (fileName != null) {
-                    messageBuf.append(fileName);
-                }
-
-                messageBuf.append("'"); //$NON-NLS-1$
-            }
-
-            messageBuf.append(Messages.getString("MysqlIO.63")); //$NON-NLS-1$
-
-            if (!this.connection.getParanoid()) {
-                messageBuf.append(Messages.getString("MysqlIO.64")); //$NON-NLS-1$
-                messageBuf.append(Util.stackTraceToString(ioEx));
-            }
-
-            throw SQLError.createSQLException(messageBuf.toString(),
-                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-        } finally {
-            if (fileIn != null) {
-                try {
-                    fileIn.close();
-                } catch (Exception ex) {
-                    SQLException sqlEx = SQLError.createSQLException(Messages.getString("MysqlIO.65"), //$NON-NLS-1$
-                        SQLError.SQL_STATE_GENERAL_ERROR);
-                    sqlEx.initCause(ex);
-                    
-                    throw sqlEx;
-                }
-
-                fileIn = null;
-            } else {
-                // file open failed, but server needs one packet
-                filePacket.clear();
-                send(filePacket, filePacket.getPosition());
-                checkErrorPacket(); // to clear response off of queue
-            }
-        }
-
-        // send empty packet to mark EOF
-        filePacket.clear();
-        send(filePacket, filePacket.getPosition());
-
-        Buffer resultPacket = checkErrorPacket();
-
-        return buildResultSetWithUpdates(callingStatement, resultPacket);
-    }
-
-    /**
-     * Checks for errors in the reply packet, and if none, returns the reply
-     * packet, ready for reading
-     *
-     * @param command the command being issued (if used)
-     *
-     * @return DOCUMENT ME!
-     *
-     * @throws SQLException if an error packet was received
-     * @throws CommunicationsException DOCUMENT ME!
-     */
-    private Buffer checkErrorPacket(int command) throws SQLException {
-        int statusCode = 0;
-        Buffer resultPacket = null;
-        this.serverStatus = 0;
-
-        try {
-            // Check return value, if we get a java.io.EOFException,
-            // the server has gone away. We'll pass it on up the
-            // exception chain and let someone higher up decide
-            // what to do (barf, reconnect, etc).
-            resultPacket = reuseAndReadPacket(this.reusablePacket);
-        } catch (SQLException sqlEx) {
-            // Don't wrap SQL Exceptions
-            throw sqlEx;
-        } catch (Exception fallThru) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, fallThru);
-        }
-
-        checkErrorPacket(resultPacket);
-
-        return resultPacket;
-    }
-
-    private void checkErrorPacket(Buffer resultPacket) throws SQLException {
-
-        int statusCode = resultPacket.readByte();
-
-        // Error handling
-        if (statusCode == (byte) 0xff) {
-            String serverErrorMessage;
-            int errno = 2000;
-
-            if (this.protocolVersion > 9) {
-                errno = resultPacket.readInt();
-
-                String xOpen = null;
-
-                serverErrorMessage =
-                	resultPacket.readString(this.connection.getErrorMessageEncoding());
-
-                if (serverErrorMessage.charAt(0) == '#') { //$NON-NLS-1$
-
-                    // we have an SQLState
-                    if (serverErrorMessage.length() > 6) {
-                        xOpen = serverErrorMessage.substring(1, 6);
-                        serverErrorMessage = serverErrorMessage.substring(6);
-
-                        if (xOpen.equals("HY000")) { //$NON-NLS-1$
-                            xOpen = SQLError.mysqlToSqlState(errno,
-                                    this.connection.getUseSqlStateCodes());
-                        }
-                    } else {
-                        xOpen = SQLError.mysqlToSqlState(errno,
-                                this.connection.getUseSqlStateCodes());
-                    }
-                } else {
-                    xOpen = SQLError.mysqlToSqlState(errno,
-                            this.connection.getUseSqlStateCodes());
-                }
-
-                clearInputStream();
-
-                StringBuffer errorBuf = new StringBuffer();
-
-                String xOpenErrorMessage = SQLError.get(xOpen);
-
-                if (!this.connection.getUseOnlyServerErrorMessages()) {
-                    if (xOpenErrorMessage != null) {
-                        errorBuf.append(xOpenErrorMessage);
-                        errorBuf.append(Messages.getString("MysqlIO.68")); //$NON-NLS-1$
-                    }
-                }
-
-                errorBuf.append(serverErrorMessage);
-
-                if (!this.connection.getUseOnlyServerErrorMessages()) {
-                    if (xOpenErrorMessage != null) {
-                        errorBuf.append("\""); //$NON-NLS-1$
-                    }
-                }
-
-                appendInnodbStatusInformation(xOpen, errorBuf);
-
-                if (xOpen != null && xOpen.startsWith("22")) {
-                	throw new MysqlDataTruncation(errorBuf.toString(), 0, true, false, 0, 0);
-                } else {
-                	throw SQLError.createSQLException(errorBuf.toString(), xOpen, errno);
-                }
-            }
-
-            serverErrorMessage = resultPacket.readString(
-            		this.connection.getErrorMessageEncoding());
-            clearInputStream();
-
-            if (serverErrorMessage.indexOf(Messages.getString("MysqlIO.70")) != -1) { //$NON-NLS-1$
-                throw SQLError.createSQLException(SQLError.get(
-                        SQLError.SQL_STATE_COLUMN_NOT_FOUND) +
-                    ", " //$NON-NLS-1$
-                     +serverErrorMessage, SQLError.SQL_STATE_COLUMN_NOT_FOUND,
-                    -1);
-            }
-
-            StringBuffer errorBuf = new StringBuffer(Messages.getString(
-                        "MysqlIO.72")); //$NON-NLS-1$
-            errorBuf.append(serverErrorMessage);
-            errorBuf.append("\""); //$NON-NLS-1$
-
-            throw SQLError.createSQLException(SQLError.get(
-                    SQLError.SQL_STATE_GENERAL_ERROR) + ", " //$NON-NLS-1$
-                 +errorBuf.toString(), SQLError.SQL_STATE_GENERAL_ERROR, -1);
-        }
-    }
-
-    private void appendInnodbStatusInformation(String xOpen,
-			StringBuffer errorBuf) throws SQLException {
-		if (this.connection.getIncludeInnodbStatusInDeadlockExceptions()
-				&& xOpen != null
-				&& (xOpen.startsWith("40") || xOpen.startsWith("41"))
-				&& this.streamingData == null) {
-			ResultSet rs = null;
-
-			try {
-				rs = sqlQueryDirect(null, "SHOW ENGINE INNODB STATUS",
-						this.connection.getEncoding(), null, -1,
-						ResultSet.TYPE_FORWARD_ONLY,
-						ResultSet.CONCUR_READ_ONLY, false, this.connection
-								.getCatalog(), null);
-
-				if (rs.next()) {
-					errorBuf.append("\n\n");
-					errorBuf.append(rs.getString(1));
-				} else {
-					errorBuf.append(Messages
-							.getString("MysqlIO.NoInnoDBStatusFound"));
-				}
-			} catch (Exception ex) {
-				errorBuf.append(Messages
-						.getString("MysqlIO.InnoDBStatusFailed"));
-				errorBuf.append("\n\n");
-				errorBuf.append(Util.stackTraceToString(ex));
-			} finally {
-				if (rs != null) {
-					rs.close();
-				}
-			}
-		}
-	}
-
-    /**
-     * Sends a large packet to the server as a series of smaller packets
-     *
-     * @param packet DOCUMENT ME!
-     *
-     * @throws SQLException DOCUMENT ME!
-     * @throws CommunicationsException DOCUMENT ME!
-     */
-    private final void sendSplitPackets(Buffer packet)
-        throws SQLException {
-        try {
-            //
-            // Big packets are handled by splitting them in packets of MAX_THREE_BYTES
-            // length. The last packet is always a packet that is < MAX_THREE_BYTES.
-            // (The last packet may even have a length of 0)
-            //
-            //
-            // NB: Guarded by execSQL. If the driver changes architecture, this
-            // will need to be synchronized in some other way
-            //
-            Buffer headerPacket = (this.splitBufRef == null) ? null
-                                                             : (Buffer) (this.splitBufRef.get());
-
-            //
-            // Store this packet in a soft reference...It can be re-used if not GC'd (so clients
-            // that use it frequently won't have to re-alloc the 16M buffer), but we don't
-            // penalize infrequent users of large packets by keeping 16M allocated all of the time
-            //
-            if (headerPacket == null) {
-                headerPacket = new Buffer((this.maxThreeBytes +
-                        HEADER_LENGTH));
-                this.splitBufRef = new SoftReference(headerPacket);
-            }
-
-            int len = packet.getPosition();
-            int splitSize = this.maxThreeBytes;
-            int originalPacketPos = HEADER_LENGTH;
-            byte[] origPacketBytes = packet.getByteBuffer();
-            byte[] headerPacketBytes = headerPacket.getByteBuffer();
-
-            while (len >= this.maxThreeBytes) {
-                this.packetSequence++;
-
-                headerPacket.setPosition(0);
-                headerPacket.writeLongInt(splitSize);
-
-                headerPacket.writeByte(this.packetSequence);
-                System.arraycopy(origPacketBytes, originalPacketPos,
-                    headerPacketBytes, 4, splitSize);
-
-                int packetLen = splitSize + HEADER_LENGTH;
-
-                //
-                // Swap a compressed packet in, if we're using
-                // compression...
-                //
-                if (!this.useCompression) {
-                    this.mysqlOutput.write(headerPacketBytes, 0,
-                        splitSize + HEADER_LENGTH);
-                    this.mysqlOutput.flush();
-                } else {
-                    Buffer packetToSend;
-
-                    headerPacket.setPosition(0);
-                    packetToSend = compressPacket(headerPacket, HEADER_LENGTH,
-                            splitSize, HEADER_LENGTH);
-                    packetLen = packetToSend.getPosition();
-
-                    this.mysqlOutput.write(packetToSend.getByteBuffer(), 0,
-                        packetLen);
-                    this.mysqlOutput.flush();
-                }
-
-                originalPacketPos += splitSize;
-                len -= splitSize;
-            }
-
-            //
-            // Write last packet
-            //
-            headerPacket.clear();
-            headerPacket.setPosition(0);
-            headerPacket.writeLongInt(len - HEADER_LENGTH);
-            this.packetSequence++;
-            headerPacket.writeByte(this.packetSequence);
-
-            if (len != 0) {
-                System.arraycopy(origPacketBytes, originalPacketPos,
-                    headerPacketBytes, 4, len - HEADER_LENGTH);
-            }
-
-            int packetLen = len - HEADER_LENGTH;
-
-            //
-            // Swap a compressed packet in, if we're using
-            // compression...
-            //
-            if (!this.useCompression) {
-                this.mysqlOutput.write(headerPacket.getByteBuffer(), 0, len);
-                this.mysqlOutput.flush();
-            } else {
-                Buffer packetToSend;
-
-                headerPacket.setPosition(0);
-                packetToSend = compressPacket(headerPacket, HEADER_LENGTH,
-                        packetLen, HEADER_LENGTH);
-                packetLen = packetToSend.getPosition();
-
-                this.mysqlOutput.write(packetToSend.getByteBuffer(), 0,
-                    packetLen);
-                this.mysqlOutput.flush();
-            }
-        } catch (IOException ioEx) {
-            throw SQLError.createCommunicationsException(this.connection,
-                this.lastPacketSentTimeMs, ioEx);
-        }
-    }
-
-    private void reclaimLargeSharedSendPacket() {
-        if ((this.sharedSendPacket != null) &&
-                (this.sharedSendPacket.getCapacity() > 1048576)) {
-            this.sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
-        }
-    }
-
-    boolean hadWarnings() {
-    	return this.hadWarnings;
-    }
-
-    void scanForAndThrowDataTruncation() throws SQLException {
-        if ((this.streamingData == null) && versionMeetsMinimum(4, 1, 0) &&
-                this.connection.getJdbcCompliantTruncation() && this.warningCount > 0) {
-            SQLError.convertShowWarningsToSQLWarnings(this.connection,
-                this.warningCount, true);
-        }
-    }
-
-    /**
-     * Secure authentication for 4.1 and newer servers.
-     *
-     * @param packet DOCUMENT ME!
-     * @param packLength
-     * @param user
-     * @param password
-     * @param database DOCUMENT ME!
-     * @param writeClientParams
-     *
-     * @throws SQLException
-     */
-    private void secureAuth(Buffer packet, int packLength, String user,
-        String password, String database, boolean writeClientParams)
-        throws SQLException {
-        // Passwords can be 16 chars long
-        if (packet == null) {
-            packet = new Buffer(packLength);
-        }
-
-        if (writeClientParams) {
-            if (this.use41Extensions) {
-                if (versionMeetsMinimum(4, 1, 1)) {
-                    packet.writeLong(this.clientParam);
-                    packet.writeLong(this.maxThreeBytes);
-
-                    // charset, JDBC will connect as 'latin1',
-                    // and use 'SET NAMES' to change to the desired
-                    // charset after the connection is established.
-                    packet.writeByte((byte) 8);
-
-                    // Set of bytes reserved for future use.
-                    packet.writeBytesNoNull(new byte[23]);
-                } else {
-                    packet.writeLong(this.clientParam);
-                    packet.writeLong(this.maxThreeBytes);
-                }
-            } else {
-                packet.writeInt((int) this.clientParam);
-                packet.writeLongInt(this.maxThreeBytes);
-            }
-        }
-
-        // User/Password data
-        packet.writeString(user, CODE_PAGE_1252, this.connection);
-
-        if (password.length() != 0) {
-            /* Prepare false scramble  */
-            packet.writeString(FALSE_SCRAMBLE, CODE_PAGE_1252, this.connection);
-        } else {
-            /* For empty password*/
-            packet.writeString("", CODE_PAGE_1252, this.connection); //$NON-NLS-1$
-        }
-
-        if (this.useConnectWithDb) {
-            packet.writeString(database, CODE_PAGE_1252, this.connection);
-        }
-
-        send(packet, packet.getPosition());
-
-        //
-        // Don't continue stages if password is empty
-        //
-        if (password.length() > 0) {
-            Buffer b = readPacket();
-
-            b.setPosition(0);
-
-            byte[] replyAsBytes = b.getByteBuffer();
-
-            if ((replyAsBytes.length == 25) && (replyAsBytes[0] != 0)) {
-                // Old passwords will have '*' at the first byte of hash */
-                if (replyAsBytes[0] != '*') {
-                    try {
-                        /* Build full password hash as it is required to decode scramble */
-                        byte[] buff = Security.passwordHashStage1(password);
-
-                        /* Store copy as we'll need it later */
-                        byte[] passwordHash = new byte[buff.length];
-                        System.arraycopy(buff, 0, passwordHash, 0, buff.length);
-
-                        /* Finally hash complete password using hash we got from server */
-                        passwordHash = Security.passwordHashStage2(passwordHash,
-                                replyAsBytes);
-
-                        byte[] packetDataAfterSalt = new byte[replyAsBytes.length -
-                            5];
-
-                        System.arraycopy(replyAsBytes, 4, packetDataAfterSalt,
-                            0, replyAsBytes.length - 5);
-
-                        byte[] mysqlScrambleBuff = new byte[20];
-
-                        /* Decypt and store scramble 4 = hash for stage2 */
-                        Security.passwordCrypt(packetDataAfterSalt,
-                            mysqlScrambleBuff, passwordHash, 20);
-
-                        /* Encode scramble with password. Recycle buffer */
-                        Security.passwordCrypt(mysqlScrambleBuff, buff, buff, 20);
-
-                        Buffer packet2 = new Buffer(25);
-                        packet2.writeBytesNoNull(buff);
-
-                        this.packetSequence++;
-
-                        send(packet2, 24);
-                    } catch (NoSuchAlgorithmException nse) {
-                        throw SQLError.createSQLException(Messages.getString("MysqlIO.91") //$NON-NLS-1$
-                             +Messages.getString("MysqlIO.92"), //$NON-NLS-1$
-                            SQLError.SQL_STATE_GENERAL_ERROR);
-                    }
-                } else {
-                    try {
-                        /* Create password to decode scramble */
-                        byte[] passwordHash = Security.createKeyFromOldPassword(password);
-
-                        /* Decypt and store scramble 4 = hash for stage2 */
-                        byte[] netReadPos4 = new byte[replyAsBytes.length - 5];
-
-                        System.arraycopy(replyAsBytes, 4, netReadPos4, 0,
-                            replyAsBytes.length - 5);
-
-                        byte[] mysqlScrambleBuff = new byte[20];
-
-                        /* Decypt and store scramble 4 = hash for stage2 */
-                        Security.passwordCrypt(netReadPos4, mysqlScrambleBuff,
-                            passwordHash, 20);
-
-                        /* Finally scramble decoded scramble with password */
-                        String scrambledPassword = Util.scramble(new String(
-                                    mysqlScrambleBuff), password);
-
-                        Buffer packet2 = new Buffer(packLength);
-                        packet2.writeString(scrambledPassword, CODE_PAGE_1252, this.connection);
-                        this.packetSequence++;
-
-                        send(packet2, 24);
-                    } catch (NoSuchAlgorithmException nse) {
-                        throw SQLError.createSQLException(Messages.getString("MysqlIO.93") //$NON-NLS-1$
-                             +Messages.getString("MysqlIO.94"), //$NON-NLS-1$
-                            SQLError.SQL_STATE_GENERAL_ERROR);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Secure authentication for 4.1.1 and newer servers.
-     *
-     * @param packet DOCUMENT ME!
-     * @param packLength
-     * @param user
-     * @param password
-     * @param database DOCUMENT ME!
-     * @param writeClientParams
-     *
-     * @throws SQLException
-     */
-    void secureAuth411(Buffer packet, int packLength, String user,
-        String password, String database, boolean writeClientParams)
-        throws SQLException {
-        //	SERVER:  public_seed=create_random_string()
-        //			 send(public_seed)
-        //
-        //	CLIENT:  recv(public_seed)
-        //			 hash_stage1=sha1("password")
-        //			 hash_stage2=sha1(hash_stage1)
-        //			 reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
-        //
-        //			 // this three steps are done in scramble()
-        //
-        //			 send(reply)
-        //
-        //
-        //	SERVER:  recv(reply)
-        //			 hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
-        //			 candidate_hash2=sha1(hash_stage1)
-        //			 check(candidate_hash2==hash_stage2)
-        // Passwords can be 16 chars long
-        if (packet == null) {
-            packet = new Buffer(packLength);
-        }
-
-        if (writeClientParams) {
-            if (this.use41Extensions) {
-                if (versionMeetsMinimum(4, 1, 1)) {
-                    packet.writeLong(this.clientParam);
-                    packet.writeLong(this.maxThreeBytes);
-
-                    // charset, JDBC will connect as 'utf8',
-                    // and use 'SET NAMES' to change to the desired
-                    // charset after the connection is established.
-                    packet.writeByte((byte) UTF8_CHARSET_INDEX);
-
-                    // Set of bytes reserved for future use.
-                    packet.writeBytesNoNull(new byte[23]);
-                } else {
-                    packet.writeLong(this.clientParam);
-                    packet.writeLong(this.maxThreeBytes);
-                }
-            } else {
-                packet.writeInt((int) this.clientParam);
-                packet.writeLongInt(this.maxThreeBytes);
-            }
-        }
-
-        // User/Password data
-        packet.writeString(user, "utf-8", this.connection);
-
-        if (password.length() != 0) {
-            packet.writeByte((byte) 0x14);
-
-            try {
-                packet.writeBytesNoNull(Security.scramble411(password, this.seed));
-            } catch (NoSuchAlgorithmException nse) {
-                throw SQLError.createSQLException(Messages.getString("MysqlIO.95") //$NON-NLS-1$
-                     +Messages.getString("MysqlIO.96"), //$NON-NLS-1$
-                    SQLError.SQL_STATE_GENERAL_ERROR);
-            }
-        } else {
-            /* For empty password*/
-            packet.writeByte((byte) 0);
-        }
-
-        if (this.useConnectWithDb) {
-            packet.writeString(database, "utf-8", this.connection);
-        }
-
-        send(packet, packet.getPosition());
-
-        byte savePacketSequence = this.packetSequence++;
-
-        Buffer reply = checkErrorPacket();
-
-        if (reply.isLastDataPacket()) {
-            /*
-                  By sending this very specific reply server asks us to send scrambled
-                  password in old format. The reply contains scramble_323.
-            */
-            this.packetSequence = ++savePacketSequence;
-            packet.clear();
-
-            String seed323 = this.seed.substring(0, 8);
-            packet.writeString(Util.newCrypt(password, seed323));
-            send(packet, packet.getPosition());
-
-            /* Read what server thinks about out new auth message report */
-            checkErrorPacket();
-        }
-    }
-
-    /**
-     * Un-packs binary-encoded result set data for one row
-     *
-     * @param fields
-     * @param binaryData
-     * @param resultSetConcurrency DOCUMENT ME!
-     *
-     * @return byte[][]
-     *
-     * @throws SQLException DOCUMENT ME!
-     */
-    private final ResultSetRow unpackBinaryResultSetRow(Field[] fields,
-        Buffer binaryData, int resultSetConcurrency) throws SQLException {
-        int numFields = fields.length;
-
-        byte[][] unpackedRowData = new byte[numFields][];
-
-        //
-        // Unpack the null bitmask, first
-        //
-
-        /* Reserve place for null-marker bytes */
-        int nullCount = (numFields + 9) / 8;
-
-        byte[] nullBitMask = new byte[nullCount];
-
-        for (int i = 0; i < nullCount; i++) {
-            nullBitMask[i] = binaryData.readByte();
-        }
-
-        int nullMaskPos = 0;
-        int bit = 4; // first two bits are reserved for future use
-
-        //
-        // TODO: Benchmark if moving check for updatable result
-        //       sets out of loop is worthwhile?
-        //
-
-        for (int i = 0; i < numFields; i++) {
-            if ((nullBitMask[nullMaskPos] & bit) != 0) {
-                unpackedRowData[i] = null;
-            } else {
-            	if (resultSetConcurrency != ResultSetInternalMethods.CONCUR_UPDATABLE) {
-            		extractNativeEncodedColumn(binaryData, fields, i,
-            				unpackedRowData);
-            	} else {
-            		unpackNativeEncodedColumn(binaryData, fields, i,
-            				unpackedRowData);
-            	}
-            }
-
-        	if (((bit <<= 1) & 255) == 0) {
-        		bit = 1; /* To next byte */
-
-        		nullMaskPos++;
-        	}
-        }
-
-        return new ByteArrayRow(unpackedRowData);
-    }
-
-
-    private final void extractNativeEncodedColumn(Buffer binaryData,
-    		Field[] fields, int columnIndex, byte[][] unpackedRowData) throws SQLException {
-    	Field curField = fields[columnIndex];
-
-    	switch (curField.getMysqlType()) {
-    	case MysqlDefs.FIELD_TYPE_NULL:
-    		break; // for dummy binds
-
-    	case MysqlDefs.FIELD_TYPE_TINY:
-
-    		unpackedRowData[columnIndex] = new byte[] {binaryData.readByte()};
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_SHORT:
-    	case MysqlDefs.FIELD_TYPE_YEAR:
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(2);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_LONG:
-    	case MysqlDefs.FIELD_TYPE_INT24:
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(4);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_LONGLONG:
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(8);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_FLOAT:
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(4);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_DOUBLE:
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(8);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_TIME:
-
-    		int length = (int) binaryData.readFieldLength();
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(length);
-
-    		break;
-    	case MysqlDefs.FIELD_TYPE_DATE:
-
-    		length = (int) binaryData.readFieldLength();
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(length);
-
-    		break;
-    	case MysqlDefs.FIELD_TYPE_DATETIME:
-    	case MysqlDefs.FIELD_TYPE_TIMESTAMP:
-    		length = (int) binaryData.readFieldLength();
-
-    		unpackedRowData[columnIndex] = binaryData.getBytes(length);
-    		break;
-    	case MysqlDefs.FIELD_TYPE_TINY_BLOB:
-    	case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
-    	case MysqlDefs.FIELD_TYPE_LONG_BLOB:
-    	case MysqlDefs.FIELD_TYPE_BLOB:
-    	case MysqlDefs.FIELD_TYPE_VAR_STRING:
-    	case MysqlDefs.FIELD_TYPE_VARCHAR:
-    	case MysqlDefs.FIELD_TYPE_STRING:
-    	case MysqlDefs.FIELD_TYPE_DECIMAL:
-    	case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
-    	case MysqlDefs.FIELD_TYPE_GEOMETRY:
-    		unpackedRowData[columnIndex] = binaryData.readLenByteArray(0);
-
-    		break;
-    	case MysqlDefs.FIELD_TYPE_BIT:
-    		unpackedRowData[columnIndex] = binaryData.readLenByteArray(0);
-
-    		break;
-    	default:
-    		throw SQLError.createSQLException(Messages.getString("MysqlIO.97") //$NON-NLS-1$
-    				+curField.getMysqlType() +
-					Messages.getString("MysqlIO.98") + columnIndex +
-					Messages.getString("MysqlIO.99") //$NON-NLS-1$ //$NON-NLS-2$
-					+ fields.length + Messages.getString("MysqlIO.100"), //$NON-NLS-1$
-					SQLError.SQL_STATE_GENERAL_ERROR);
-    	}
-    }
-
-    private final void unpackNativeEncodedColumn(Buffer binaryData,
-    		Field[] fields, int columnIndex, byte[][] unpackedRowData)
-    throws SQLException {
-    	Field curField = fields[columnIndex];
-
-    	switch (curField.getMysqlType()) {
-    	case MysqlDefs.FIELD_TYPE_NULL:
-    		break; // for dummy binds
-
-    	case MysqlDefs.FIELD_TYPE_TINY:
-
-    		byte tinyVal = binaryData.readByte();
-
-    		if (!curField.isUnsigned()) {
-    			unpackedRowData[columnIndex] = String.valueOf(tinyVal)
-    			.getBytes();
-    		} else {
-    			short unsignedTinyVal = (short) (tinyVal & 0xff);
-
-    			unpackedRowData[columnIndex] = String.valueOf(unsignedTinyVal)
-    			.getBytes();
-    		}
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_SHORT:
-    	case MysqlDefs.FIELD_TYPE_YEAR:
-
-    		short shortVal = (short) binaryData.readInt();
-
-    		if (!curField.isUnsigned()) {
-    			unpackedRowData[columnIndex] = String.valueOf(shortVal)
-    			.getBytes();
-    		} else {
-    			int unsignedShortVal = shortVal & 0xffff;
-
-    			unpackedRowData[columnIndex] = String.valueOf(unsignedShortVal)
-    			.getBytes();
-    		}
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_LONG:
-    	case MysqlDefs.FIELD_TYPE_INT24:
-
-    		int intVal = (int) binaryData.readLong();
-
-    		if (!curField.isUnsigned()) {
-    			unpackedRowData[columnIndex] = String.valueOf(intVal)
-    			.getBytes();
-    		} else {
-    			long longVal = intVal & 0xffffffffL;
-
-    			unpackedRowData[columnIndex] = String.valueOf(longVal)
-    			.getBytes();
-    		}
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_LONGLONG:
-
-    		long longVal = binaryData.readLongLong();
-
-    		if (!curField.isUnsigned()) {
-    			unpackedRowData[columnIndex] = String.valueOf(longVal)
-    			.getBytes();
-    		} else {
-    			BigInteger asBigInteger = ResultSetImpl.convertLongToUlong(longVal);
-
-    			unpackedRowData[columnIndex] = asBigInteger.toString()
-    			.getBytes();
-    		}
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_FLOAT:
-
-    		float floatVal = Float.intBitsToFloat(binaryData.readIntAsLong());
-
-    		unpackedRowData[columnIndex] = String.valueOf(floatVal).getBytes();
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_DOUBLE:
-
-    		double doubleVal = Double.longBitsToDouble(binaryData.readLongLong());
-
-    		unpackedRowData[columnIndex] = String.valueOf(doubleVal).getBytes();
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_TIME:
-
-    		int length = (int) binaryData.readFieldLength();
-
-    		int hour = 0;
-    		int minute = 0;
-    		int seconds = 0;
-
-    		if (length != 0) {
-    			binaryData.readByte(); // skip tm->neg
-    			binaryData.readLong(); // skip daysPart
-    			hour = binaryData.readByte();
-    			minute = binaryData.readByte();
-    			seconds = binaryData.readByte();
-
-    			if (length > 8) {
-    				binaryData.readLong(); // ignore 'secondsPart'
-    			}
-    		}
-
-
-    		byte[] timeAsBytes = new byte[8];
-
-    		timeAsBytes[0] = (byte) Character.forDigit(hour / 10, 10);
-    		timeAsBytes[1] = (byte) Character.forDigit(hour % 10, 10);
-
-    		timeAsBytes[2] = (byte) ':';
-
-    		timeAsBytes[3] = (byte) Character.forDigit(minute / 10,
-    				10);
-    		timeAsBytes[4] = (byte) Character.forDigit(minute % 10,
-    				10);
-
-    		timeAsBytes[5] = (byte) ':';
-
-    		timeAsBytes[6] = (byte) Character.forDigit(seconds / 10,
-    				10);
-    		timeAsBytes[7] = (byte) Character.forDigit(seconds % 10,
-    				10);
-
-    		unpackedRowData[columnIndex] = timeAsBytes;
-
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_DATE:
-    		length = (int) binaryData.readFieldLength();
-
-    		int year = 0;
-    		int month = 0;
-    		int day = 0;
-
-    		hour = 0;
-    		minute = 0;
-    		seconds = 0;
-
-    		if (length != 0) {
-    			year = binaryData.readInt();
-    			month = binaryData.readByte();
-    			day = binaryData.readByte();
-    		}
-
-    		if ((year == 0) && (month == 0) && (day == 0)) {
-    			if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(
-    					this.connection.getZeroDateTimeBehavior())) {
-    				unpackedRowData[columnIndex] = null;
-
-    				break;
-    			} else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(
-    					this.connection.getZeroDateTimeBehavior())) {
-    				throw SQLError.createSQLException("Value '0000-00-00' can not be represented as java.sql.Date",
-    						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-    			}
-
-    			year = 1;
-    			month = 1;
-    			day = 1;
-    		}
-
-
-    		byte[] dateAsBytes = new byte[10];
-
-    		dateAsBytes[0] = (byte) Character.forDigit(year / 1000,
-    				10);
-
-    		int after1000 = year % 1000;
-
-    		dateAsBytes[1] = (byte) Character.forDigit(after1000 / 100,
-    				10);
-
-    		int after100 = after1000 % 100;
-
-    		dateAsBytes[2] = (byte) Character.forDigit(after100 / 10,
-    				10);
-    		dateAsBytes[3] = (byte) Character.forDigit(after100 % 10,
-    				10);
-
-    		dateAsBytes[4] = (byte) '-';
-
-    		dateAsBytes[5] = (byte) Character.forDigit(month / 10,
-    				10);
-    		dateAsBytes[6] = (byte) Character.forDigit(month % 10,
-    				10);
-
-    		dateAsBytes[7] = (byte) '-';
-
-    		dateAsBytes[8] = (byte) Character.forDigit(day / 10, 10);
-    		dateAsBytes[9] = (byte) Character.forDigit(day % 10, 10);
-
-    		unpackedRowData[columnIndex] = dateAsBytes;
-
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_DATETIME:
-    	case MysqlDefs.FIELD_TYPE_TIMESTAMP:
-    		length = (int) binaryData.readFieldLength();
-
-    		year = 0;
-    		month = 0;
-    		day = 0;
-
-    		hour = 0;
-    		minute = 0;
-    		seconds = 0;
-
-    		int nanos = 0;
-
-    		if (length != 0) {
-    			year = binaryData.readInt();
-    			month = binaryData.readByte();
-    			day = binaryData.readByte();
-
-    			if (length > 4) {
-    				hour = binaryData.readByte();
-    				minute = binaryData.readByte();
-    				seconds = binaryData.readByte();
-    			}
-
-    			//if (length > 7) {
-    			//    nanos = (int)binaryData.readLong();
-    			//}
-    		}
-
-    		if ((year == 0) && (month == 0) && (day == 0)) {
-    			if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL.equals(
-    					this.connection.getZeroDateTimeBehavior())) {
-    				unpackedRowData[columnIndex] = null;
-
-    				break;
-    			} else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION.equals(
-    					this.connection.getZeroDateTimeBehavior())) {
-    				throw SQLError.createSQLException("Value '0000-00-00' can not be represented as java.sql.Timestamp",
-    						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-    			}
-
-    			year = 1;
-    			month = 1;
-    			day = 1;
-    		}
-
-
-    		int stringLength = 19;
-
-    		byte[] nanosAsBytes = Integer.toString(nanos).getBytes();
-
-    		stringLength += (1 + nanosAsBytes.length); // '.' + # of digits
-
-    		byte[] datetimeAsBytes = new byte[stringLength];
-
-    		datetimeAsBytes[0] = (byte) Character.forDigit(year / 1000,
-    				10);
-
-    		after1000 = year % 1000;
-
-    		datetimeAsBytes[1] = (byte) Character.forDigit(after1000 / 100,
-    				10);
-
-    		after100 = after1000 % 100;
-
-    		datetimeAsBytes[2] = (byte) Character.forDigit(after100 / 10,
-    				10);
-    		datetimeAsBytes[3] = (byte) Character.forDigit(after100 % 10,
-    				10);
-
-    		datetimeAsBytes[4] = (byte) '-';
-
-    		datetimeAsBytes[5] = (byte) Character.forDigit(month / 10,
-    				10);
-    		datetimeAsBytes[6] = (byte) Character.forDigit(month % 10,
-    				10);
-
-    		datetimeAsBytes[7] = (byte) '-';
-
-    		datetimeAsBytes[8] = (byte) Character.forDigit(day / 10,
-    				10);
-    		datetimeAsBytes[9] = (byte) Character.forDigit(day % 10,
-    				10);
-
-    		datetimeAsBytes[10] = (byte) ' ';
-
-    		datetimeAsBytes[11] = (byte) Character.forDigit(hour / 10,
-    				10);
-    		datetimeAsBytes[12] = (byte) Character.forDigit(hour % 10,
-    				10);
-
-    		datetimeAsBytes[13] = (byte) ':';
-
-    		datetimeAsBytes[14] = (byte) Character.forDigit(minute / 10,
-    				10);
-    		datetimeAsBytes[15] = (byte) Character.forDigit(minute % 10,
-    				10);
-
-    		datetimeAsBytes[16] = (byte) ':';
-
-    		datetimeAsBytes[17] = (byte) Character.forDigit(seconds / 10,
-    				10);
-    		datetimeAsBytes[18] = (byte) Character.forDigit(seconds % 10,
-    				10);
-
-    		datetimeAsBytes[19] = (byte) '.';
-
-    		int nanosOffset = 20;
-
-    		for (int j = 0; j < nanosAsBytes.length; j++) {
-    			datetimeAsBytes[nanosOffset + j] = nanosAsBytes[j];
-    		}
-
-    		unpackedRowData[columnIndex] = datetimeAsBytes;
-
-
-    		break;
-
-    	case MysqlDefs.FIELD_TYPE_TINY_BLOB:
-    	case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
-    	case MysqlDefs.FIELD_TYPE_LONG_BLOB:
-    	case MysqlDefs.FIELD_TYPE_BLOB:
-    	case MysqlDefs.FIELD_TYPE_VAR_STRING:
-    	case MysqlDefs.FIELD_TYPE_STRING:
-    	case MysqlDefs.FIELD_TYPE_VARCHAR:
-    	case MysqlDefs.FIELD_TYPE_DECIMAL:
-    	case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
-    	case MysqlDefs.FIELD_TYPE_BIT:
-    		unpackedRowData[columnIndex] = binaryData.readLenByteArray(0);
-
-    		break;
-
-    	default:
-    		throw SQLError.createSQLException(Messages.getString("MysqlIO.97") //$NON-NLS-1$
-    				+curField.getMysqlType() +
-    				Messages.getString("MysqlIO.98") + columnIndex +
-    				Messages.getString("MysqlIO.99") //$NON-NLS-1$ //$NON-NLS-2$
-    				+ fields.length + Messages.getString("MysqlIO.100"), //$NON-NLS-1$
-    				SQLError.SQL_STATE_GENERAL_ERROR);
-    	}
-    }
-
-    /**
-     * Negotiates the SSL communications channel used when connecting
-     * to a MySQL server that understands SSL.
-     *
-     * @param user
-     * @param password
-     * @param database
-     * @param packLength
-     * @throws SQLException
-     * @throws CommunicationsException
-     */
-    private void negotiateSSLConnection(String user, String password,
-        String database, int packLength)
-        throws SQLException {
-        if (!ExportControlled.enabled()) {
-            throw new ConnectionFeatureNotAvailableException(this.connection,
-                this.lastPacketSentTimeMs, null);
-        }
-
-        boolean doSecureAuth = false;
-
-        if ((this.serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
-            this.clientParam |= CLIENT_SECURE_CONNECTION;
-            doSecureAuth = true;
-        }
-
-        this.clientParam |= CLIENT_SSL;
-
-        Buffer packet = new Buffer(packLength);
-
-        if (this.use41Extensions) {
-            packet.writeLong(this.clientParam);
-        } else {
-            packet.writeInt((int) this.clientParam);
-        }
-
-        send(packet, packet.getPosition());
-
-        ExportControlled.transformSocketToSSLSocket(this);
-
-        packet.clear();
-
-        if (doSecureAuth) {
-            if (versionMeetsMinimum(4, 1, 1)) {
-                secureAuth411(null, packLength, user, password, database, true);
-            } else {
-                secureAuth411(null, packLength, user, password, database, true);
-            }
-        } else {
-            if (this.use41Extensions) {
-                packet.writeLong(this.clientParam);
-                packet.writeLong(this.maxThreeBytes);
-            } else {
-                packet.writeInt((int) this.clientParam);
-                packet.writeLongInt(this.maxThreeBytes);
-            }
-
-            // User/Password data
-            packet.writeString(user);
-
-            if (this.protocolVersion > 9) {
-                packet.writeString(Util.newCrypt(password, this.seed));
-            } else {
-                packet.writeString(Util.oldCrypt(password, this.seed));
-            }
-
-            if (((this.serverCapabilities & CLIENT_CONNECT_WITH_DB) != 0) &&
-                    (database != null) && (database.length() > 0)) {
-                packet.writeString(database);
-            }
-
-            send(packet, packet.getPosition());
-        }
-    }
-
-	protected int getServerStatus() {
-		return this.serverStatus;
-	}
-
-	protected List fetchRowsViaCursor(List fetchedRows, long statementId,
-			Field[] columnTypes, int fetchSize, boolean useBufferRowExplicit) throws SQLException {
-
-		if (fetchedRows == null) {
-			fetchedRows = new ArrayList(fetchSize);
-		} else {
-			fetchedRows.clear();
-		}
-
-		this.sharedSendPacket.clear();
-
-		this.sharedSendPacket.writeByte((byte) MysqlDefs.COM_FETCH);
-		this.sharedSendPacket.writeLong(statementId);
-		this.sharedSendPacket.writeLong(fetchSize);
-
-		sendCommand(MysqlDefs.COM_FETCH, null, this.sharedSendPacket, true,
-				null);
-
-		ResultSetRow row = null;
-
-		while ((row = nextRow(columnTypes, columnTypes.length, true,
-				ResultSet.CONCUR_READ_ONLY, false, useBufferRowExplicit, false, null)) != null) {
-			fetchedRows.add(row);
-		}
-
-		return fetchedRows;
-	}
-
-	protected long getThreadId() {
-		return this.threadId;
-	}
-
-	protected boolean useNanosForElapsedTime() {
-		return this.useNanosForElapsedTime;
-	}
-
-	protected long getSlowQueryThreshold() {
-		return this.slowQueryThreshold;
-	}
-
-	protected String getQueryTimingUnits() {
-		return this.queryTimingUnits;
-	}
-	
-	protected int getCommandCount() {
-		return this.commandCount;
-	}
-}
\ No newline at end of file

Added: trunk/src/com/mysql/jdbc/MysqlIO.java
===================================================================
--- trunk/src/com/mysql/jdbc/MysqlIO.java	                        (rev 0)
+++ trunk/src/com/mysql/jdbc/MysqlIO.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -0,0 +1,96 @@
+package com.mysql.jdbc;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Properties;
+
+public interface MysqlIO {
+
+    void doHandshake(String user, String password, String database)
+        throws SQLException;
+
+    ResultSetImpl readAllResults(StatementImpl callingStatement, int maxRows,
+        int resultSetType, int resultSetConcurrency, boolean streamResults,
+        String catalog, Buffer resultPacket, boolean isBinaryEncoded,
+        long preSentColumnCount, Field[] metadataFromCache) throws SQLException;
+    
+    ResultSetRow nextRow(Field[] fields, int columnCount,
+        boolean isBinaryEncoded, int resultSetConcurrency,
+        boolean useBufferRowIfPossible,
+        boolean useBufferRowExplicit,
+        boolean canReuseRowPacketForBufferRow, Buffer existingRowPacket)
+        throws SQLException;
+
+    long getThreadId();
+
+    void changeUser(String userName, String password, String database)
+        throws SQLException;
+
+    void forceClose();
+
+    boolean isDataAvailable() throws SQLException;
+
+    boolean inTransactionOnServer();
+
+    int serverCharsetIndex();
+
+    void setServerCharsetIndex(int serverCharsetIndex);
+
+    void checkForCharsetMismatch();
+
+    long getLastPacketSentTimeMs();
+
+    void initializeStatementInterceptors(String interceptorClasses,
+        Properties props) throws SQLException;
+
+    ResultSetInternalMethods sqlQueryDirect(StatementImpl callingStatement,
+        String query, String characterEncoding, Buffer queryPacket,
+        int maxRows, int resultSetType, int resultSetConcurrency,
+        boolean streamResults, String catalog, Field[] cachedMetadata)
+        throws Exception;
+
+    String getHost();
+
+    String getServerVersion();
+
+    int getServerMajorVersion();
+
+    int getServerMinorVersion();
+
+    int getServerSubMinorVersion();
+
+    boolean versionMeetsMinimum(int major, int minor, int subminor);
+    
+    int getServerStatus();
+    
+    public boolean hasLongColumnInfo();
+
+    void resetMaxBuf();
+
+    boolean isSetNeededForAutoCommitMode(boolean autoCommitFlag);
+
+    Buffer sendCommand(int command, String extraData, Buffer queryPacket,
+        boolean skipCheck, String extraDataCharEncoding) throws SQLException;
+
+    int getCommandCount();
+
+    void quit() throws SQLException;
+
+    void disableMultiQueries() throws SQLException;
+
+    void enableMultiQueries() throws SQLException;
+
+    boolean tackOnMoreStreamingResults(ResultSetImpl addingTo)
+        throws SQLException;
+
+    void clearInputStream() throws SQLException;
+
+    void closeStreamer(RowData streamer) throws SQLException;
+
+    List fetchRowsViaCursor(List fetchedRows, long statementId,
+        Field[] columnTypes, int fetchSize, boolean useBufferRowExplicit)
+        throws SQLException;
+    
+    Buffer getSharedSendPacket();
+
+}

Copied: trunk/src/com/mysql/jdbc/MysqlIOprotocol.java (from rev 6709, trunk/src/com/mysql/jdbc/MysqlIO.java)
===================================================================
--- trunk/src/com/mysql/jdbc/MysqlIOprotocol.java	                        (rev 0)
+++ trunk/src/com/mysql/jdbc/MysqlIOprotocol.java	2008-01-15 21:56:02 UTC (rev 6710)
@@ -0,0 +1,4543 @@
+/*
+      Copyright (C) 2002-2007 MySQL AB
+
+      This program is free software; you can redistribute it and/or modify
+      it under the terms of version 2 of the GNU General Public License as
+      published by the Free Software Foundation.
+
+      There are special exceptions to the terms and conditions of the GPL
+      as it is applied to this software. View the full text of the
+      exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
+      software distribution.
+
+      This program is distributed in the hope that it will be useful,
+      but WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+      GNU General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, write to the Free Software
+      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+ */
+package com.mysql.jdbc;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.SoftReference;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.zip.Deflater;
+
+import com.mysql.jdbc.profiler.ProfilerEvent;
+import com.mysql.jdbc.profiler.ProfilerEventHandler;
+import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;
+import com.mysql.jdbc.util.ReadAheadInputStream;
+import com.mysql.jdbc.util.ResultSetUtil;
+
+
+/**
+ * This class is used by Connection for communicating with the MySQL server.
+ *
+ * @author Mark Matthews
+ * @version $Id$
+ *
+ * @see java.sql.Connection
+ */
+class MysqlIOprotocol implements MysqlIO {
+    private static final int UTF8_CHARSET_INDEX = 33;
+    private static final String CODE_PAGE_1252 = "Cp1252";
+	protected static final int NULL_LENGTH = ~0;
+    protected static final int COMP_HEADER_LENGTH = 3;
+    protected static final int MIN_COMPRESS_LEN = 50;
+    protected static final int HEADER_LENGTH = 4;
+    protected static final int AUTH_411_OVERHEAD = 33;
+    private static final int CLIENT_COMPRESS = 32; /* Can use compression
+    protcol */
+    protected static final int CLIENT_CONNECT_WITH_DB = 8;
+    private static final int CLIENT_FOUND_ROWS = 2;
+    private static final int CLIENT_LOCAL_FILES = 128; /* Can use LOAD DATA
+    LOCAL */
+
+    /* Found instead of
+       affected rows */
+    private static final int CLIENT_LONG_FLAG = 4; /* Get all column flags */
+    private static final int CLIENT_LONG_PASSWORD = 1; /* new more secure
+    passwords */
+    private static final int CLIENT_PROTOCOL_41 = 512; // for > 4.1.1
+    private static final int CLIENT_INTERACTIVE = 1024;
+    protected static final int CLIENT_SSL = 2048;
+    private static final int CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
+    protected static final int CLIENT_RESERVED = 16384; // for 4.1.0 only
+    protected static final int CLIENT_SECURE_CONNECTION = 32768;
+    private static final int CLIENT_MULTI_QUERIES = 65536; // Enable/disable multiquery support
+    private static final int CLIENT_MULTI_RESULTS = 131072; // Enable/disable multi-results
+    private static final int SERVER_STATUS_IN_TRANS = 1;
+    private static final int SERVER_STATUS_AUTOCOMMIT = 2; // Server in auto_commit mode
+    static final int SERVER_MORE_RESULTS_EXISTS = 8; // Multi query - next query exists
+    private static final int SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
+    private static final int SERVER_QUERY_NO_INDEX_USED = 32;
+	private static final int  SERVER_STATUS_CURSOR_EXISTS = 64;
+    private static final String FALSE_SCRAMBLE = "xxxxxxxx"; //$NON-NLS-1$
+    protected static final int MAX_QUERY_SIZE_TO_LOG = 1024; // truncate logging of queries at 1K
+    protected static final int MAX_QUERY_SIZE_TO_EXPLAIN = 1024 * 1024; // don't explain queries above 1MB
+    protected static final int INITIAL_PACKET_SIZE = 1024;
+    /**
+     * We store the platform 'encoding' here, only used to avoid munging
+     * filenames for LOAD DATA LOCAL INFILE...
+     */
+    private static String jvmPlatformCharset = null;
+
+    /**
+     * We need to have a 'marker' for all-zero datetimes so that ResultSet
+     * can decide what to do based on connection setting
+     */
+    protected final static String ZERO_DATE_VALUE_MARKER = "0000-00-00";
+    protected final static String ZERO_DATETIME_VALUE_MARKER = "0000-00-00 00:00:00";
+
+    static {
+        OutputStreamWriter outWriter = null;
+
+        //
+        // Use the I/O system to get the encoding (if possible), to avoid
+        // security restrictions on System.getProperty("file.encoding") in
+        // applets (why is that restricted?)
+        //
+        try {
+            outWriter = new OutputStreamWriter(new ByteArrayOutputStream());
+            jvmPlatformCharset = outWriter.getEncoding();
+        } finally {
+            try {
+                if (outWriter != null) {
+                    outWriter.close();
+                }
+            } catch (IOException ioEx) {
+                // ignore
+            }
+        }
+    }
+
+    /** Max number of bytes to dump when tracing the protocol */
+    private final static int MAX_PACKET_DUMP_LENGTH = 1024;
+    private boolean packetSequenceReset = false;
+    private int serverCharsetIndex;
+
+    //
+    // Use this when reading in rows to avoid thousands of new()
+    // calls, because the byte arrays just get copied out of the
+    // packet anyway
+    //
+    private Buffer reusablePacket = null;
+    private Buffer sendPacket = null;
+    private Buffer sharedSendPacket = null;
+
+    /** Data to the server */
+    protected BufferedOutputStream mysqlOutput = null;
+    protected ConnectionImpl connection;
+    private Deflater deflater = null;
+    protected InputStream mysqlInput = null;
+    private LinkedList packetDebugRingBuffer = null;
+    private RowData streamingData = null;
+
+    /** The connection to the server */
+    protected Socket mysqlConnection = null;
+    private SocketFactory socketFactory = null;
+
+    //
+    // Packet used for 'LOAD DATA LOCAL INFILE'
+    //
+    // We use a SoftReference, so that we don't penalize intermittent
+    // use of this feature
+    //
+    private SoftReference loadFileBufRef;
+
+    //
+    // Used to send large packets to the server versions 4+
+    // We use a SoftReference, so that we don't penalize intermittent
+    // use of this feature
+    //
+    private SoftReference splitBufRef;
+    protected String host = null;
+    protected String seed;
+    private String serverVersion = null;
+    private String socketFactoryClassName = null;
+    private byte[] packetHeaderBuf = new byte[4];
+    private boolean colDecimalNeedsBump = false; // do we need to increment the colDecimal flag?
+    private boolean hadWarnings = false;
+    private boolean has41NewNewProt = false;
+
+    /** Does the server support long column info? */
+    private boolean hasLongColumnInfo = false;
+    private boolean isInteractiveClient = false;
+    private boolean logSlowQueries = false;
+
+    /**
+     * Does the character set of this connection match the character set of the
+     * platform
+     */
+    private boolean platformDbCharsetMatches = true; // changed once we've connected.
+    private boolean profileSql = false;
+    private boolean queryBadIndexUsed = false;
+    private boolean queryNoIndexUsed = false;
+
+    /** Should we use 4.1 protocol extensions? */
+    private boolean use41Extensions = false;
+    private boolean useCompression = false;
+    private boolean useNewLargePackets = false;
+    private boolean useNewUpdateCounts = false; // should we use the new larger update counts?
+    private byte packetSequence = 0;
+    private byte readPacketSequence = -1;
+    private boolean checkPacketSequence = false;
+    private byte protocolVersion = 0;
+    private int maxAllowedPacket = 1024 * 1024;
+    protected int maxThreeBytes = 255 * 255 * 255;
+    protected int port = 3306;
+    protected int serverCapabilities;
+    private int serverMajorVersion = 0;
+    private int serverMinorVersion = 0;
+    private int serverStatus = 0;
+    private int serverSubMinorVersion = 0;
+    private int warningCount = 0;
+    protected long clientParam = 0;
+    protected long lastPacketSentTimeMs = 0;
+    private boolean traceProtocol = false;
+    private boolean enablePacketDebug = false;
+    private Calendar sessionCalendar;
+	private boolean useConnectWithDb;
+	private boolean needToGrabQueryFromPacket;
+	private boolean autoGenerateTestcaseScript;
+	private long threadId;
+	private boolean useNanosForElapsedTime;
+	private long slowQueryThreshold;
+	private String queryTimingUnits;
+	private List statementInterceptors;
+	private boolean useDirectRowUnpack = true;
+	private int useBufferRowSizeThreshold;
+	private int commandCount = 0;
+
+    /**
+     * Constructor:  Connect to the MySQL server and setup a stream connection.
+     *
+     * @param host the hostname to connect to
+     * @param port the port number that the server is listening on
+     * @param props the Properties from DriverManager.getConnection()
+     * @param socketFactoryClassName the socket factory to use
+     * @param conn the Connection that is creating us
+     * @param socketTimeout the timeout to set for the socket (0 means no
+     *        timeout)
+     *
+     * @throws IOException if an IOException occurs during connect.
+     * @throws SQLException if a database access error occurs.
+     */
+    public MysqlIOprotocol(String host, int port, Properties props,
+        String socketFactoryClassName, ConnectionImpl conn,
+        int socketTimeout, int useBufferRowSizeThreshold) throws IOException, SQLException {
+        this.connection = conn;
+
+        if (this.connection.getEnablePacketDebug()) {
+            this.packetDebugRingBuffer = new LinkedList();
+        }
+
+        this.useAutoSlowLog = this.connection.getAutoSlowLog();
+        
+        this.useBufferRowSizeThreshold = useBufferRowSizeThreshold;
+        this.useDirectRowUnpack = this.connection.getUseDirectRowUnpack();
+
+        this.logSlowQueries = this.connection.getLogSlowQueries();
+
+        this.reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
+        this.sendPacket = new Buffer(INITIAL_PACKET_SIZE);
+
+        this.port = port;
+        this.host = host;
+
+        this.socketFactoryClassName = socketFactoryClassName;
+        this.socketFactory = createSocketFactory();
+
+        this.mysqlConnection = this.socketFactory.connect(this.host,
+        		this.port, props);
+
+        if (socketTimeout != 0) {
+        	try {
+        		this.mysqlConnection.setSoTimeout(socketTimeout);
+        	} catch (Exception ex) {
+        		/* Ignore if the platform does not support it */
+        	}
+        }
+
+        this.mysqlConnection = this.socketFactory.beforeHandshake();
+
+        if (this.connection.getUseReadAheadInput()) {
+        	this.mysqlInput = new ReadAheadInputStream(this.mysqlConnection.getInputStream(), 16384,
+        			this.connection.getTraceProtocol(),
+        			this.connection.getLog());
+        } else if (this.connection.useUnbufferedInput()) {
+        	this.mysqlInput = this.mysqlConnection.getInputStream();
+        } else {
+        	this.mysqlInput = new BufferedInputStream(this.mysqlConnection.getInputStream(),
+        			16384);
+        }
+
+        this.mysqlOutput = new BufferedOutputStream(this.mysqlConnection.getOutputStream(),
+        		16384);
+
+
+        this.isInteractiveClient = this.connection.getInteractiveClient();
+        this.profileSql = this.connection.getProfileSql();
+        this.sessionCalendar = Calendar.getInstance();
+        this.autoGenerateTestcaseScript = this.connection.getAutoGenerateTestcaseScript();
+
+        this.needToGrabQueryFromPacket = (this.profileSql ||
+        		this.logSlowQueries ||
+        		this.autoGenerateTestcaseScript);
+
+        if (this.connection.getUseNanosForElapsedTime()
+				&& Util.nanoTimeAvailable()) {
+			this.useNanosForElapsedTime = true;
+
+			this.queryTimingUnits = Messages.getString("Nanoseconds");
+		} else {
+			this.queryTimingUnits = Messages.getString("Milliseconds");
+		}
+
+		if (this.connection.getLogSlowQueries()) {
+			calculateSlowQueryThreshold();
+		}
+    }
+
+    public void initializeStatementInterceptors(String interceptorClasses,
+			Properties props) throws SQLException {
+		this.statementInterceptors = Util.loadExtensions(this.connection, props, 
+				interceptorClasses,
+				"MysqlIo.BadStatementInterceptor");
+	}
+
+    /**
+	 * Does the server send back extra column info?
+	 * 
+	 * @return true if so
+	 */
+    public boolean hasLongColumnInfo() {
+        return this.hasLongColumnInfo;
+    }
+
+    public boolean isDataAvailable() throws SQLException {
+        try {
+            return this.mysqlInput.available() > 0;
+        } catch (IOException ioEx) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs, ioEx);
+        }
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @return Returns the lastPacketSentTimeMs.
+     */
+    public long getLastPacketSentTimeMs() {
+        return this.lastPacketSentTimeMs;
+    }
+
+    /**
+     * Build a result set. Delegates to buildResultSetWithRows() to build a
+     * JDBC-version-specific ResultSet, given rows as byte data, and field
+     * information.
+     *
+     * @param callingStatement DOCUMENT ME!
+     * @param columnCount the number of columns in the result set
+     * @param maxRows the maximum number of rows to read (-1 means all rows)
+     * @param resultSetType (TYPE_FORWARD_ONLY, TYPE_SCROLL_????)
+     * @param resultSetConcurrency the type of result set (CONCUR_UPDATABLE or
+     *        READ_ONLY)
+     * @param streamResults should the result set be read all at once, or
+     *        streamed?
+     * @param catalog the database name in use when the result set was created
+     * @param isBinaryEncoded is this result set in native encoding?
+     * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
+     *
+     * @return a result set
+     *
+     * @throws SQLException if a database access error occurs
+     */
+    protected ResultSetImpl getResultSet(StatementImpl callingStatement,
+        long columnCount, int maxRows, int resultSetType,
+        int resultSetConcurrency, boolean streamResults, String catalog,
+        boolean isBinaryEncoded, Field[] metadataFromCache)
+        throws SQLException {
+        Buffer packet; // The packet from the server
+        Field[] fields = null;
+
+        // Read in the column information
+
+        if (metadataFromCache == null /* we want the metadata from the server */) {
+            fields = new Field[(int) columnCount];
+
+            for (int i = 0; i < columnCount; i++) {
+            	Buffer fieldPacket = null;
+
+                fieldPacket = readPacket();
+                fields[i] = unpackField(fieldPacket, false);
+            }
+        } else {
+        	for (int i = 0; i < columnCount; i++) {
+        		skipPacket();
+        	}
+        }
+
+        packet = reuseAndReadPacket(this.reusablePacket);
+        
+        readServerStatusForResultSets(packet);
+
+		//
+		// Handle cursor-based fetch first
+		//
+
+		if (this.connection.versionMeetsMinimum(5, 0, 2)
+				&& this.connection.getUseCursorFetch()
+				&& isBinaryEncoded
+				&& callingStatement != null
+				&& callingStatement.getFetchSize() != 0
+				&& callingStatement.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
+			ServerPreparedStatement prepStmt = (com.mysql.jdbc.ServerPreparedStatement) callingStatement;
+
+			boolean usingCursor = true;
+
+			//
+			// Server versions 5.0.5 or newer will only open
+			// a cursor and set this flag if they can, otherwise
+			// they punt and go back to mysql_store_results() behavior
+			//
+
+			if (this.connection.versionMeetsMinimum(5, 0, 5)) {
+				usingCursor = (this.serverStatus &
+						SERVER_STATUS_CURSOR_EXISTS) != 0;
+			}
+
+			if (usingCursor) {
+				RowData rows = new RowDataCursor(
+					this,
+					prepStmt,
+					fields);
+
+				ResultSetImpl rs = buildResultSetWithRows(
+					callingStatement,
+					catalog,
+					fields,
+					rows, resultSetType, resultSetConcurrency, isBinaryEncoded);
+
+				if (usingCursor) {
+		        	rs.setFetchSize(callingStatement.getFetchSize());
+		        }
+
+				return rs;
+			}
+		}
+
+        RowData rowData = null;
+
+        if (!streamResults) {
+            rowData = readSingleRowSet(columnCount, maxRows,
+                    resultSetConcurrency, isBinaryEncoded,
+                    (metadataFromCache == null) ? fields : metadataFromCache);
+        } else {
+            rowData = new RowDataDynamic(this, (int) columnCount,
+            		(metadataFromCache == null) ? fields : metadataFromCache,
+                    isBinaryEncoded);
+            this.streamingData = rowData;
+        }
+
+        ResultSetImpl rs = buildResultSetWithRows(callingStatement, catalog,
+        		(metadataFromCache == null) ? fields : metadataFromCache,
+            rowData, resultSetType, resultSetConcurrency, isBinaryEncoded);
+
+
+
+        return rs;
+    }
+
+    /**
+     * Forcibly closes the underlying socket to MySQL.
+     */
+    public final void forceClose() {
+        try {
+            if (this.mysqlInput != null) {
+                this.mysqlInput.close();
+            }
+        } catch (IOException ioEx) {
+            // we can't do anything constructive about this
+            // Let the JVM clean it up later
+            this.mysqlInput = null;
+        }
+
+        try {
+            if (this.mysqlOutput != null) {
+                this.mysqlOutput.close();
+            }
+        } catch (IOException ioEx) {
+            // we can't do anything constructive about this
+            // Let the JVM clean it up later
+            this.mysqlOutput = null;
+        }
+
+        try {
+            if (this.mysqlConnection != null) {
+                this.mysqlConnection.close();
+            }
+        } catch (IOException ioEx) {
+            // we can't do anything constructive about this
+            // Let the JVM clean it up later
+            this.mysqlConnection = null;
+        }
+    }
+
+    /**
+     * Reads and discards a single MySQL packet from the input stream.
+     *
+     * @throws SQLException if the network fails while skipping the
+     * packet.
+     */
+    protected final void skipPacket() throws SQLException {
+		try {
+
+			int lengthRead = readFully(this.mysqlInput, this.packetHeaderBuf,
+					0, 4);
+
+			if (lengthRead < 4) {
+				forceClose();
+				throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
+			}
+
+			int packetLength = (this.packetHeaderBuf[0] & 0xff)
+					+ ((this.packetHeaderBuf[1] & 0xff) << 8)
+					+ ((this.packetHeaderBuf[2] & 0xff) << 16);
+
+			if (this.traceProtocol) {
+				StringBuffer traceMessageBuf = new StringBuffer();
+
+				traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
+				traceMessageBuf.append(packetLength);
+				traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
+				traceMessageBuf.append(StringUtils.dumpAsHex(
+						this.packetHeaderBuf, 4));
+
+				this.connection.getLog().logTrace(traceMessageBuf.toString());
+			}
+
+			byte multiPacketSeq = this.packetHeaderBuf[3];
+
+			if (!this.packetSequenceReset) {
+				if (this.enablePacketDebug && this.checkPacketSequence) {
+					checkPacketSequencing(multiPacketSeq);
+				}
+			} else {
+				this.packetSequenceReset = false;
+			}
+
+			this.readPacketSequence = multiPacketSeq;
+
+			skipFully(this.mysqlInput, packetLength);
+		} catch (IOException ioEx) {
+			throw SQLError.createCommunicationsException(this.connection,
+					this.lastPacketSentTimeMs, ioEx);
+		} catch (OutOfMemoryError oom) {
+			try {
+				this.connection.realClose(false, false, true, oom);
+			} finally {
+				throw oom;
+			}
+		}
+	}
+
+    /**
+     * Read one packet from the MySQL server
+     *
+     * @return the packet from the server.
+     *
+     * @throws SQLException DOCUMENT ME!
+     * @throws CommunicationsException DOCUMENT ME!
+     */
+    protected final Buffer readPacket() throws SQLException {
+        try {
+
+            int lengthRead = readFully(this.mysqlInput,
+                    this.packetHeaderBuf, 0, 4);
+
+            if (lengthRead < 4) {
+                forceClose();
+                throw new IOException(Messages.getString("MysqlIO.1")); //$NON-NLS-1$
+            }
+
+            int packetLength = (this.packetHeaderBuf[0] & 0xff) +
+                ((this.packetHeaderBuf[1] & 0xff) << 8) +
+                ((this.packetHeaderBuf[2] & 0xff) << 16);
+            
+            if (packetLength > this.maxAllowedPacket) {
+                throw new PacketTooBigException(packetLength, this.maxAllowedPacket);
+            }
+
+            if (this.traceProtocol) {
+                StringBuffer traceMessageBuf = new StringBuffer();
+
+                traceMessageBuf.append(Messages.getString("MysqlIO.2")); //$NON-NLS-1$
+                traceMessageBuf.append(packetLength);
+                traceMessageBuf.append(Messages.getString("MysqlIO.3")); //$NON-NLS-1$
+                traceMessageBuf.append(StringUtils.dumpAsHex(
+                        this.packetHeaderBuf, 4));
+
+                this.connection.getLog().logTrace(traceMessageBuf.toString());
+            }
+
+            byte multiPacketSeq = this.packetHeaderBuf[3];
+
+            if (!this.packetSequenceReset) {
+                if (this.enablePacketDebug && this.checkPacketSequence) {
+                    checkPacketSequencing(multiPacketSeq);
+                }
+            } else {
+                this.packetSequenceReset = false;
+            }
+
+            this.readPacketSequence = multiPacketSeq;
+
+            // Read data
+            byte[] buffer = new byte[packetLength + 1];
+            int numBytesRead = readFully(this.mysqlInput, buffer, 0,
+                    packetLength);
+
+            if (numBytesRead != packetLength) {
+                throw new IOException("Short read, expected " +
+                    packetLength + " bytes, only read " + numBytesRead);
+            }
+
+            buffer[packetLength] = 0;
+
+            Buffer packet = new Buffer(buffer);
+            packet.setBufLength(packetLength + 1);
+
+            if (this.traceProtocol) {
+                StringBuffer traceMessageBuf = new StringBuffer();
+
+                traceMessageBuf.append(Messages.getString("MysqlIO.4")); //$NON-NLS-1$
+                traceMessageBuf.append(getPacketDumpToLog(packet,
+                        packetLength));
+
+                this.connection.getLog().logTrace(traceMessageBuf.toString());
+            }
+
+            if (this.enablePacketDebug) {
+                enqueuePacketForDebugging(false, false, 0,
+                    this.packetHeaderBuf, packet);
+            }
+
+            return packet;
+        } catch (IOException ioEx) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs, ioEx);
+        } catch (OutOfMemoryError oom) {
+        	try {
+    			this.connection.realClose(false, false, true, oom);
+    		} finally {
+    			throw oom;
+    		}
+        }
+    }
+
+    /**
+     * Unpacks the Field information from the given packet. Understands pre 4.1
+     * and post 4.1 server version field packet structures.
+     *
+     * @param packet the packet containing the field information
+     * @param extractDefaultValues should default values be extracted?
+     *
+     * @return the unpacked field
+     *
+     * @throws SQLException DOCUMENT ME!
+     */
+    protected final Field unpackField(Buffer packet,
+        boolean extractDefaultValues) throws SQLException {
+        if (this.use41Extensions) {
+            // we only store the position of the string and
+            // materialize only if needed...
+            if (this.has41NewNewProt) {
+                // Not used yet, 5.0?
+                int catalogNameStart = packet.getPosition() + 1;
+                int catalogNameLength = packet.fastSkipLenString();
+                catalogNameStart = adjustStartForFieldLength(catalogNameStart, catalogNameLength);
+            }
+
+            int databaseNameStart = packet.getPosition() + 1;
+            int databaseNameLength = packet.fastSkipLenString();
+            databaseNameStart = adjustStartForFieldLength(databaseNameStart, databaseNameLength);
+
+            int tableNameStart = packet.getPosition() + 1;
+            int tableNameLength = packet.fastSkipLenString();
+            tableNameStart = adjustStartForFieldLength(tableNameStart, tableNameLength);
+
+            // orgTableName is never used so skip
+            int originalTableNameStart = packet.getPosition() + 1;
+            int originalTableNameLength = packet.fastSkipLenString();
+            originalTableNameStart = adjustStartForFieldLength(originalTableNameStart, originalTableNameLength);
+
+            // we only store the position again...
+            int nameStart = packet.getPosition() + 1;
+            int nameLength = packet.fastSkipLenString();
+
+            nameStart = adjustStartForFieldLength(nameStart, nameLength);
+
+            // orgColName is not required so skip...
+            int originalColumnNameStart = packet.getPosition() + 1;
+            int originalColumnNameLength = packet.fastSkipLenString();
+            originalColumnNameStart = adjustStartForFieldLength(originalColumnNameStart, originalColumnNameLength);
+
+            packet.readByte();
+
+            short charSetNumber = (short) packet.readInt();
+
+            long colLength = 0;
+
+            if (this.has41NewNewProt) {
+                colLength = packet.readLong();
+            } else {
+                colLength = packet.readLongInt();
+            }
+
+            int colType = packet.readByte() & 0xff;
+
+            short colFlag = 0;
+
+            if (this.hasLongColumnInfo) {
+                colFlag = (short) packet.readInt();
+            } else {
+                colFlag = (short) (packet.readByte() & 0xff);
+            }
+
+            int colDecimals = packet.readByte() & 0xff;
+
+            int defaultValueStart = -1;
+            int defaultValueLength = -1;
+
+            if (extractDefaultValues) {
+                defaultValueStart = packet.getPosition() + 1;
+                defaultValueLength = packet.fastSkipLenString();
+            }
+
+            Field field = new Field(this.connection, packet.getByteBuffer(),
+                    databaseNameStart, databaseNameLength, tableNameStart,
+                    tableNameLength, originalTableNameStart,
+                    originalTableNameLength, nameStart, nameLength,
+                    originalColumnNameStart, originalColumnNameLength,
+                    colLength, colType, colFlag, colDecimals,
+                    defaultValueStart, defaultValueLength, charSetNumber);
+
+            return field;
+        }
+
+        int tableNameStart = packet.getPosition() + 1;
+        int tableNameLength = packet.fastSkipLenString();
+        tableNameStart = adjustStartForFieldLength(tableNameStart, tableNameLength);
+
+        int nameStart = packet.getPosition() + 1;
+        int nameLength = packet.fastSkipLenString();
+        nameStart = adjustStartForFieldLength(nameStart, nameLength);
+
+        int colLength = packet.readnBytes();
+        int colType = packet.readnBytes();
+        packet.readByte(); // We know it's currently 2
+
+        short colFlag = 0;
+
+        if (this.hasLongColumnInfo) {
+            colFlag = (short) (packet.readInt());
+        } else {
+            colFlag = (short) (packet.readByte() & 0xff);
+        }
+
+        int colDecimals = (packet.readByte() & 0xff);
+
+        if (this.colDecimalNeedsBump) {
+            colDecimals++;
+        }
+
+        Field field = new Field(this.connection, packet.getByteBuffer(),
+                nameStart, nameLength, tableNameStart, tableNameLength,
+                colLength, colType, colFlag, colDecimals);
+
+        return field;
+    }
+
+    private int adjustStartForFieldLength(int nameStart, int nameLength) {
+    	if (nameLength < 251) {
+    		return nameStart;
+    	}
+
+		if (nameLength >= 251 && nameLength < 65536) {
+			return nameStart + 2;
+		}
+
+		if (nameLength >= 65536 && nameLength < 16777216) {
+			return nameStart + 3;
+		}
+
+		return nameStart + 8;
+	}
+
+    public boolean isSetNeededForAutoCommitMode(boolean autoCommitFlag) {
+        if (this.use41Extensions && this.connection.getElideSetAutoCommits()) {
+            boolean autoCommitModeOnServer = ((this.serverStatus &
+                SERVER_STATUS_AUTOCOMMIT) != 0);
+
+            if (!autoCommitFlag && versionMeetsMinimum(5, 0, 0)) {
+                // Just to be safe, check if a transaction is in progress on the server....
+                // if so, then we must be in autoCommit == false
+                // therefore return the opposite of transaction status
+                boolean inTransactionOnServer = ((this.serverStatus &
+                    SERVER_STATUS_IN_TRANS) != 0);
+
+                return !inTransactionOnServer;
+            }
+
+            return autoCommitModeOnServer != autoCommitFlag;
+        }
+
+        return true;
+    }
+
+    public boolean inTransactionOnServer() {
+    	return (this.serverStatus & SERVER_STATUS_IN_TRANS) != 0;
+    }
+
+    /**
+     * Re-authenticates as the given user and password
+     *
+     * @param userName DOCUMENT ME!
+     * @param password DOCUMENT ME!
+     * @param database DOCUMENT ME!
+     *
+     * @throws SQLException DOCUMENT ME!
+     */
+    public void changeUser(String userName, String password, String database)
+        throws SQLException {
+        this.packetSequence = -1;
+
+        int passwordLength = 16;
+        int userLength = (userName != null) ? userName.length() : 0;
+        int databaseLength = (database != null) ? database.length() : 0;
+
+        int packLength = ((userLength + passwordLength + databaseLength) * 2) + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
+
+        if ((this.serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
+            Buffer changeUserPacket = new Buffer(packLength + 1);
+            changeUserPacket.writeByte((byte) MysqlDefs.COM_CHANGE_USER);
+
+            if (versionMeetsMinimum(4, 1, 1)) {
+                secureAuth411(changeUserPacket, packLength, userName, password,
+                    database, false);
+            } else {
+                secureAuth(changeUserPacket, packLength, userName, password,
+                    database, false);
+            }
+        } else {
+            // Passwords can be 16 chars long
+            Buffer packet = new Buffer(packLength);
+            packet.writeByte((byte) MysqlDefs.COM_CHANGE_USER);
+
+            // User/Password data
+            packet.writeString(userName);
+
+            if (this.protocolVersion > 9) {
+                packet.writeString(Util.newCrypt(password, this.seed));
+            } else {
+                packet.writeString(Util.oldCrypt(password, this.seed));
+            }
+
+			boolean localUseConnectWithDb = this.useConnectWithDb &&
+				(database != null && database.length() > 0);
+
+            if (localUseConnectWithDb) {
+                packet.writeString(database);
+            }
+
+            send(packet, packet.getPosition());
+            checkErrorPacket();
+
+			if (!localUseConnectWithDb) {
+				changeDatabaseTo(database);
+			}
+        }
+    }
+
+    /**
+     * Checks for errors in the reply packet, and if none, returns the reply
+     * packet, ready for reading
+     *
+     * @return a packet ready for reading.
+     *
+     * @throws SQLException is the packet is an error packet
+     */
+    protected Buffer checkErrorPacket() throws SQLException {
+        return checkErrorPacket(-1);
+    }
+
+    /**
+     * Determines if the database charset is the same as the platform charset
+     */
+    public void checkForCharsetMismatch() {
+        if (this.connection.getUseUnicode() &&
+                (this.connection.getEncoding() != null)) {
+            String encodingToCheck = jvmPlatformCharset;
+
+            if (encodingToCheck == null) {
+                encodingToCheck = System.getProperty("file.encoding"); //$NON-NLS-1$
+            }
+
+            if (encodingToCheck == null) {
+                this.platformDbCharsetMatches = false;
+            } else {
+                this.platformDbCharsetMatches = encodingToCheck.equals(this.connection.getEncoding());
+            }
+        }
+    }
+
+    public void clearInputStream() throws SQLException {
+
+        try {
+            int len = this.mysqlInput.available();
+
+            while (len > 0) {
+                this.mysqlInput.skip(len);
+                len = this.mysqlInput.available();
+            }
+        } catch (IOException ioEx) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs, ioEx);
+        }
+    }
+
+    protected void resetReadPacketSequence() {
+        this.readPacketSequence = 0;
+    }
+
+    protected void dumpPacketRingBuffer() throws SQLException {
+        if ((this.packetDebugRingBuffer != null) &&
+                this.connection.getEnablePacketDebug()) {
+            StringBuffer dumpBuffer = new StringBuffer();
+
+            dumpBuffer.append("Last " + this.packetDebugRingBuffer.size() +
+                " packets received from server, from oldest->newest:\n");
+            dumpBuffer.append("\n");
+
+            for (Iterator ringBufIter = this.packetDebugRingBuffer.iterator();
+                    ringBufIter.hasNext();) {
+                dumpBuffer.append((StringBuffer) ringBufIter.next());
+                dumpBuffer.append("\n");
+            }
+
+            this.connection.getLog().logTrace(dumpBuffer.toString());
+        }
+    }
+
+    /**
+     * Runs an 'EXPLAIN' on the given query and dumps the results to  the log
+     *
+     * @param querySQL DOCUMENT ME!
+     * @param truncatedQuery DOCUMENT ME!
+     *
+     * @throws SQLException DOCUMENT ME!
+     */
+    protected void explainSlowQuery(byte[] querySQL, String truncatedQuery)
+        throws SQLException {
+        if (StringUtils.startsWithIgnoreCaseAndWs(truncatedQuery, "SELECT")) { //$NON-NLS-1$
+
+            PreparedStatement stmt = null;
+            java.sql.ResultSet rs = null;
+
+            try {
+                stmt = (PreparedStatement) this.connection.clientPrepareStatement("EXPLAIN ?"); //$NON-NLS-1$
+                stmt.setBytesNoEscapeNoQuotes(1, querySQL);
+                rs = stmt.executeQuery();
+
+                StringBuffer explainResults = new StringBuffer(Messages.getString(
+                            "MysqlIO.8") + truncatedQuery //$NON-NLS-1$
+                         +Messages.getString("MysqlIO.9")); //$NON-NLS-1$
+
+                ResultSetUtil.appendResultSetSlashGStyle(explainResults, rs);
+
+                this.connection.getLog().logWarn(explainResults.toString());
+            } catch (SQLException sqlEx) {
+            } finally {
+                if (rs != null) {
+                    rs.close();
+                }
+
+                if (stmt != null) {
+                    stmt.close();
+                }
+            }
+        } else {
+        }
+    }
+
+    /**
+     * Get the major version of the MySQL server we are talking to.
+     *
+     * @return DOCUMENT ME!
+     */
+    public final int getServerMajorVersion() {
+        return this.serverMajorVersion;
+    }
+
+    /**
+     * Get the minor version of the MySQL server we are talking to.
+     *
+     * @return DOCUMENT ME!
+     */
+    public final int getServerMinorVersion() {
+        return this.serverMinorVersion;
+    }
+
+    /**
+     * Get the sub-minor version of the MySQL server we are talking to.
+     *
+     * @return DOCUMENT ME!
+     */
+    public final int getServerSubMinorVersion() {
+        return this.serverSubMinorVersion;
+    }
+
+    /**
+     * Get the version string of the server we are talking to
+     *
+     * @return DOCUMENT ME!
+     */
+    public String getServerVersion() {
+        return this.serverVersion;
+    }
+
+    /**
+     * Initialize communications with the MySQL server. Handles logging on, and
+     * handling initial connection errors.
+     *
+     * @param user DOCUMENT ME!
+     * @param password DOCUMENT ME!
+     * @param database DOCUMENT ME!
+     *
+     * @throws SQLException DOCUMENT ME!
+     * @throws CommunicationsException DOCUMENT ME!
+     */
+    public void doHandshake(String user, String password, String database)
+        throws SQLException {
+        // Read the first packet
+        this.checkPacketSequence = false;
+        this.readPacketSequence = 0;
+
+        Buffer buf = readPacket();
+
+        // Get the protocol version
+        this.protocolVersion = buf.readByte();
+
+        if (this.protocolVersion == -1) {
+            try {
+                this.mysqlConnection.close();
+            } catch (Exception e) {
+                // ignore
+            }
+
+            int errno = 2000;
+
+            errno = buf.readInt();
+
+            String serverErrorMessage = buf.readString();
+
+            StringBuffer errorBuf = new StringBuffer(Messages.getString(
+                        "MysqlIO.10")); //$NON-NLS-1$
+            errorBuf.append(serverErrorMessage);
+            errorBuf.append("\""); //$NON-NLS-1$
+
+            String xOpen = SQLError.mysqlToSqlState(errno,
+                    this.connection.getUseSqlStateCodes());
+
+            throw SQLError.createSQLException(SQLError.get(xOpen) + ", " //$NON-NLS-1$
+                 +errorBuf.toString(), xOpen, errno);
+        }
+
+        this.serverVersion = buf.readString();
+
+        // Parse the server version into major/minor/subminor
+        int point = this.serverVersion.indexOf('.'); //$NON-NLS-1$
+
+        if (point != -1) {
+            try {
+                int n = Integer.parseInt(this.serverVersion.substring(0, point));
+                this.serverMajorVersion = n;
+            } catch (NumberFormatException NFE1) {
+                // ignore
+            }
+
+            String remaining = this.serverVersion.substring(point + 1,
+                    this.serverVersion.length());
+            point = remaining.indexOf('.'); //$NON-NLS-1$
+
+            if (point != -1) {
+                try {
+                    int n = Integer.parseInt(remaining.substring(0, point));
+                    this.serverMinorVersion = n;
+                } catch (NumberFormatException nfe) {
+                    // ignore
+                }
+
+                remaining = remaining.substring(point + 1, remaining.length());
+
+                int pos = 0;
+
+                while (pos < remaining.length()) {
+                    if ((remaining.charAt(pos) < '0') ||
+                            (remaining.charAt(pos) > '9')) {
+                        break;
+                    }
+
+                    pos++;
+                }
+
+                try {
+                    int n = Integer.parseInt(remaining.substring(0, pos));
+                    this.serverSubMinorVersion = n;
+                } catch (NumberFormatException nfe) {
+                    // ignore
+                }
+            }
+        }
+
+        if (versionMeetsMinimum(4, 0, 8)) {
+            this.maxThreeBytes = (256 * 256 * 256) - 1;
+            this.useNewLargePackets = true;
+        } else {
+            this.maxThreeBytes = 255 * 255 * 255;
+            this.useNewLargePackets = false;
+        }
+
+        this.colDecimalNeedsBump = versionMeetsMinimum(3, 23, 0);
+        this.colDecimalNeedsBump = !versionMeetsMinimum(3, 23, 15); // guess? Not noted in changelog
+        this.useNewUpdateCounts = versionMeetsMinimum(3, 22, 5);
+
+        threadId = buf.readLong();
+        this.seed = buf.readString();
+
+        this.serverCapabilities = 0;
+
+        if (buf.getPosition() < buf.getBufLength()) {
+            this.serverCapabilities = buf.readInt();
+        }
+
+        if (versionMeetsMinimum(4, 1, 1)) {
+            int position = buf.getPosition();
+
+            /* New protocol with 16 bytes to describe server characteristics */
+            this.serverCharsetIndex = buf.readByte() & 0xff;
+            this.serverStatus = buf.readInt();
+            buf.setPosition(position + 16);
+
+            String seedPart2 = buf.readString();
+            StringBuffer newSeed = new StringBuffer(20);
+            newSeed.append(this.seed);
+            newSeed.append(seedPart2);
+            this.seed = newSeed.toString();
+        }
+
+        if (((this.serverCapabilities & CLIENT_COMPRESS) != 0) &&
+                this.connection.getUseCompression()) {
+            this.clientParam |= CLIENT_COMPRESS;
+        }
+
+		this.useConnectWithDb = (database != null) &&
+			(database.length() > 0) &&
+			!this.connection.getCreateDatabaseIfNotExist();
+
+        if (this.useConnectWithDb) {
+            this.clientParam |= CLIENT_CONNECT_WITH_DB;
+        }
+
+        if (((this.serverCapabilities & CLIENT_SSL) == 0) &&
+                this.connection.getUseSSL()) {
+            if (this.connection.getRequireSSL()) {
+                this.connection.close();
+                forceClose();
+                throw SQLError.createSQLException(Messages.getString("MysqlIO.15"), //$NON-NLS-1$
+                    SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
+            }
+
+            this.connection.setUseSSL(false);
+        }
+
+        if ((this.serverCapabilities & CLIENT_LONG_FLAG) != 0) {
+            // We understand other column flags, as well
+            this.clientParam |= CLIENT_LONG_FLAG;
+            this.hasLongColumnInfo = true;
+        }
+
+        // return FOUND rows
+        this.clientParam |= CLIENT_FOUND_ROWS;
+
+        if (this.connection.getAllowLoadLocalInfile()) {
+            this.clientParam |= CLIENT_LOCAL_FILES;
+        }
+
+        if (this.isInteractiveClient) {
+            this.clientParam |= CLIENT_INTERACTIVE;
+        }
+
+        // Authenticate
+        if (this.protocolVersion > 9) {
+            this.clientParam |= CLIENT_LONG_PASSWORD; // for long passwords
+        } else {
+            this.clientParam &= ~CLIENT_LONG_PASSWORD;
+        }
+
+        //
+        // 4.1 has some differences in the protocol
+        //
+        if (versionMeetsMinimum(4, 1, 0)) {
+            if (versionMeetsMinimum(4, 1, 1)) {
+                this.clientParam |= CLIENT_PROTOCOL_41;
+                this.has41NewNewProt = true;
+
+                // Need this to get server status values
+                this.clientParam |= CLIENT_TRANSACTIONS;
+
+                // We always allow multiple result sets
+                this.clientParam |= CLIENT_MULTI_RESULTS;
+
+                // We allow the user to configure whether
+                // or not they want to support multiple queries
+                // (by default, this is disabled).
+                if (this.connection.getAllowMultiQueries()) {
+                    this.clientParam |= CLIENT_MULTI_QUERIES;
+                }
+            } else {
+                this.clientParam |= CLIENT_RESERVED;
+                this.has41NewNewProt = false;
+            }
+
+            this.use41Extensions = true;
+        }
+
+        int passwordLength = 16;
+        int userLength = (user != null) ? user.length() : 0;
+        int databaseLength = (database != null) ? database.length() : 0;
+
+        int packLength = ((userLength + passwordLength + databaseLength) * 2) + 7 + HEADER_LENGTH + AUTH_411_OVERHEAD;
+
+        Buffer packet = null;
+
+        if (!this.connection.getUseSSL()) {
+            if ((this.serverCapabilities & CLIENT_SECURE_CONNECTION) != 0) {
+                this.clientParam |= CLIENT_SECURE_CONNECTION;
+
+                if (versionMeetsMinimum(4, 1, 1)) {
+                    secureAuth411(null, packLength, user, password, database,
+                        true);
+                } else {
+                    secureAuth(null, packLength, user, password, database, true);
+                }
+            } else {
+                // Passwords can be 16 chars long
+                packet = new Buffer(packLength);
+
+                if ((this.clientParam & CLIENT_RESERVED) != 0) {
+                    if (versionMeetsMinimum(4, 1, 1)) {
+                        packet.writeLong(this.clientParam);
+                        packet.writeLong(this.maxThreeBytes);
+
+                        // charset, JDBC will connect as 'latin1',
+                        // and use 'SET NAMES' to change to the desired
+                        // charset after the connection is established.
+                        packet.writeByte((byte) 8);
+
+                        // Set of bytes reserved for future use.
+                        packet.writeBytesNoNull(new byte[23]);
+                    } else {
+                        packet.writeLong(this.clientParam);
+                        packet.writeLong(this.maxThreeBytes);
+                    }
+                } else {
+                    packet.writeInt((int) this.clientParam);
+                    packet.writeLongInt(this.maxThreeBytes);
+                }
+
+                // User/Password data
+                packet.writeString(user, CODE_PAGE_1252, this.connection);
+
+                if (this.protocolVersion > 9) {
+                    packet.writeString(Util.newCrypt(password, this.seed), CODE_PAGE_1252, this.connection);
+                } else {
+                    packet.writeString(Util.oldCrypt(password, this.seed), CODE_PAGE_1252, this.connection);
+                }
+
+                if (this.useConnectWithDb) {
+                    packet.writeString(database, CODE_PAGE_1252, this.connection);
+                }
+
+                send(packet, packet.getPosition());
+            }
+        } else {
+            negotiateSSLConnection(user, password, database, packLength);
+        }
+
+        // Check for errors, not for 4.1.1 or newer,
+        // as the new auth protocol doesn't work that way
+        // (see secureAuth411() for more details...)
+        if (!versionMeetsMinimum(4, 1, 1)) {
+            checkErrorPacket();
+        }
+
+        //
+        // Can't enable compression until after handshake
+        //
+        if (((this.serverCapabilities & CLIENT_COMPRESS) != 0) &&
+                this.connection.getUseCompression()) {
+            // The following matches with ZLIB's
+            // compress()
+            this.deflater = new Deflater();
+            this.useCompression = true;
+            this.mysqlInput = new CompressedInputStream(this.connection,
+                    this.mysqlInput);
+        }
+
+        if (!this.useConnectWithDb) {
+            changeDatabaseTo(database);
+        }
+        
+        try {
+        	this.mysqlConnection = this.socketFactory.afterHandshake();
+        } catch (IOException ioEx) {
+        	throw SQLError.createCommunicationsException(this.connection, this.lastPacketSentTimeMs, ioEx);
+        }
+    }
+
+	private void changeDatabaseTo(String database) throws SQLException {
+		if (database == null || database.length() == 0) {
+			return;
+		}
+
+		try {
+		    sendCommand(MysqlDefs.INIT_DB, database, null, false, null);
+		} catch (Exception ex) {
+			if (this.connection.getCreateDatabaseIfNotExist()) {
+				sendCommand(MysqlDefs.QUERY, "CREATE DATABASE IF NOT EXISTS " +
+					database,
+					null, false, null);
+				sendCommand(MysqlDefs.INIT_DB, database, null, false, null);
+			} else {
+				throw SQLError.createCommunicationsException(this.connection,
+						this.lastPacketSentTimeMs, ex);
+			}
+		}
+	}
+
+    /**
+    * Retrieve one row from the MySQL server. Note: this method is not
+    * thread-safe, but it is only called from methods that are guarded by
+    * synchronizing on this object.
+    *
+    * @param fields DOCUMENT ME!
+    * @param columnCount DOCUMENT ME!
+    * @param isBinaryEncoded DOCUMENT ME!
+    * @param resultSetConcurrency DOCUMENT ME!
+     * @param b
+    *
+    * @return DOCUMENT ME!
+    *
+    * @throws SQLException DOCUMENT ME!
+    */
+    public final ResultSetRow nextRow(Field[] fields, int columnCount,
+        boolean isBinaryEncoded, int resultSetConcurrency,
+        boolean useBufferRowIfPossible,
+        boolean useBufferRowExplicit,
+        boolean canReuseRowPacketForBufferRow, Buffer existingRowPacket)
+        throws SQLException {
+
+    	if (this.useDirectRowUnpack && existingRowPacket == null
+				&& !isBinaryEncoded && !useBufferRowIfPossible
+				&& !useBufferRowExplicit) {
+			return nextRowFast(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
+					useBufferRowIfPossible, useBufferRowExplicit, canReuseRowPacketForBufferRow);
+		}
+
+        Buffer rowPacket = null;
+
+        if (existingRowPacket == null) {
+        	rowPacket = checkErrorPacket();
+
+        	if (!useBufferRowExplicit && useBufferRowIfPossible) {
+        		if (rowPacket.getBufLength() > this.useBufferRowSizeThreshold) {
+        			useBufferRowExplicit = true;
+        		}
+        	}
+        } else {
+        	// We attempted to do nextRowFast(), but the packet was a
+        	// multipacket, so we couldn't unpack it directly
+        	rowPacket = existingRowPacket;
+        	checkErrorPacket(existingRowPacket);
+        }
+
+
+        if (!isBinaryEncoded) {
+            //
+            // Didn't read an error, so re-position to beginning
+            // of packet in order to read result set data
+            //
+            rowPacket.setPosition(rowPacket.getPosition() - 1);
+
+            if (!rowPacket.isLastDataPacket()) {
+            	if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
+            			|| (!useBufferRowIfPossible && !useBufferRowExplicit)) {
+
+            		byte[][] rowData = new byte[columnCount][];
+
+            		for (int i = 0; i < columnCount; i++) {
+            			rowData[i] = rowPacket.readLenByteArray(0);
+            		}
+
+            		return new ByteArrayRow(rowData);
+            	}
+
+            	if (!canReuseRowPacketForBufferRow) {
+            		this.reusablePacket = new Buffer(rowPacket.getBufLength());
+            	}
+
+            	return new BufferRow(rowPacket, fields, false);
+
+            }
+
+            readServerStatusForResultSets(rowPacket);
+
+            return null;
+        }
+
+        //
+        // Handle binary-encoded data for server-side
+        // PreparedStatements...
+        //
+        if (!rowPacket.isLastDataPacket()) {
+        	if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE
+        			|| (!useBufferRowIfPossible && !useBufferRowExplicit)) {
+        		return unpackBinaryResultSetRow(fields, rowPacket,
+        				resultSetConcurrency);
+        	}
+
+        	if (!canReuseRowPacketForBufferRow) {
+        		this.reusablePacket = new Buffer(rowPacket.getBufLength());
+        	}
+
+            return new BufferRow(rowPacket, fields, true);
+        }
+
+        rowPacket.setPosition(rowPacket.getPosition() - 1);
+        readServerStatusForResultSets(rowPacket);
+
+        return null;
+    }
+
+    final ResultSetRow nextRowFast(Field[] fields, int columnCount,
+            boolean isBinaryEncoded, int resultSetConcurrency,
+            boolean useBufferRowIfPossible,
+            boolean useBufferRowExplicit, boolean canReuseRowPacket)
+			throws SQLException {
+		try {
+			int lengthRead = readFully(this.mysqlInput, this.packetHeaderBuf,
+					0, 4);
+
+			if (lengthRead < 4) {
+				forceClose();
+				throw new RuntimeException(Messages.getString("MysqlIO.43")); //$NON-NLS-1$
+			}
+
+			int packetLength = (this.packetHeaderBuf[0] & 0xff)
+					+ ((this.packetHeaderBuf[1] & 0xff) << 8)
+					+ ((this.packetHeaderBuf[2] & 0xff) << 16);
+
+			// Have we stumbled upon a multi-packet?
+			if (packetLength == this.maxThreeBytes) {
+				reuseAndReadPacket(this.reusablePacket, packetLength);
+
+				// Go back to "old" way which uses packets
+				return nextRow(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
+						useBufferRowIfPossible, useBufferRowExplicit,
+						canReuseRowPacket, this.reusablePacket);
+			}
+
+			// Does this go over the threshold where we should use a BufferRow?
+
+			if (packetLength > this.useBufferRowSizeThreshold) {
+				reuseAndReadPacket(this.reusablePacket, packetLength);
+
+				// Go back to "old" way which uses packets
+				return nextRow(fields, columnCount, isBinaryEncoded, resultSetConcurrency,
+						true, true,
+						false, this.reusablePacket);
+			}
+
+			int remaining = packetLength;
+
+			boolean firstTime = true;
+
+			byte[][] rowData = null;
+
+			for (int i = 0; i < columnCount; i++) {
+
+				int sw = this.mysqlInput.read() & 0xff;
+				remaining--;
+
+				if (firstTime) {
+					if (sw == 255) {
+						// error packet - we assemble it whole for "fidelity"
+						// in case we ever need an entire packet in checkErrorPacket()
+						// but we could've gotten away with just writing the error code
+						// and message in it (for now).
+						Buffer errorPacket = new Buffer(packetLength + HEADER_LENGTH);
+						errorPacket.setPosition(0);
+						errorPacket.writeByte(this.packetHeaderBuf[0]);
+						errorPacket.writeByte(this.packetHeaderBuf[1]);
+						errorPacket.writeByte(this.packetHeaderBuf[2]);
+						errorPacket.writeByte((byte) 1);
+						errorPacket.writeByte((byte)sw);
+						readFully(this.mysqlInput, errorPacket.getByteBuffer(), 5, packetLength - 1);
+						errorPacket.setPosition(4);
+						checkErrorPacket(errorPacket);
+					}
+
+					if (sw == 254 && packetLength < 9) {
+						if (this.use41Extensions) {
+							this.warningCount = (this.mysqlInput.read() & 0xff)
+									| ((this.mysqlInput.read() & 0xff) << 8);
+							remaining -= 2;
+
+							if (this.warningCount > 0) {
+								this.hadWarnings = true; // this is a
+															// 'latch', it's
+															// reset by
+															// sendCommand()
+							}
+
+							this.serverStatus = (this.mysqlInput.read() & 0xff)
+									| ((this.mysqlInput.read() & 0xff) << 8);
+							remaining -= 2;
+
+							if (remaining > 0) {
+								skipFully(this.mysqlInput, remaining);
+							}
+						}
+
+						return null; // last data packet
+					}
+
+					rowData = new byte[columnCount][];
+
+					firstTime = false;
+				}
+
+				int len = 0;
+
+				switch (sw) {
+				case 251:
+					len = NULL_LENGTH;
+					break;
+
+				case 252:
+					len = (this.mysqlInput.read() & 0xff)
+							| ((this.mysqlInput.read() & 0xff) << 8);
+					remaining -= 2;
+					break;
+
+				case 253:
+					len = (this.mysqlInput.read() & 0xff)
+							| ((this.mysqlInput.read() & 0xff) << 8)
+							| ((this.mysqlInput.read() & 0xff) << 16);
+
+					remaining -= 3;
+					break;
+
+				case 254:
+					len = (int) ((this.mysqlInput.read() & 0xff)
+							| ((long) (this.mysqlInput.read() & 0xff) << 8)
+							| ((long) (this.mysqlInput.read() & 0xff) << 16)
+							| ((long) (this.mysqlInput.read() & 0xff) << 24)
+							| ((long) (this.mysqlInput.read() & 0xff) << 32)
+							| ((long) (this.mysqlInput.read() & 0xff) << 40)
+							| ((long) (this.mysqlInput.read() & 0xff) << 48)
+							| ((long) (this.mysqlInput.read() & 0xff) << 56));
+					remaining -= 8;
+					break;
+
+				default:
+					len = sw;
+				}
+
+				if (len == NULL_LENGTH) {
+					rowData[i] = null;
+				} else if (len == 0) {
+					rowData[i] = Constants.EMPTY_BYTE_ARRAY;
+				} else {
+					rowData[i] = new byte[len];
+
+					int bytesRead = readFully(this.mysqlInput, rowData[i], 0,
+							len);
+
+					if (bytesRead != len) {
+						throw SQLError.createCommunicationsException(this.connection,
+			    				this.lastPacketSentTimeMs,
+			    				new IOException(Messages.getString("MysqlIO.43")));
+					}
+
+					remaining -= bytesRead;
+				}
+			}
+
+			if (remaining > 0) {
+				skipFully(this.mysqlInput, remaining);
+			}
+
+			return new ByteArrayRow(rowData);
+		} catch (IOException ioEx) {
+			throw SQLError.createCommunicationsException(this.connection,
+    				this.lastPacketSentTimeMs, ioEx);
+		}
+	}
+
+    /**
+     * Log-off of the MySQL server and close the socket.
+     *
+     * @throws SQLException DOCUMENT ME!
+     */
+    public final void quit() throws SQLException {
+        Buffer packet = new Buffer(6);
+        this.packetSequence = -1;
+        packet.writeByte((byte) MysqlDefs.QUIT);
+        send(packet, packet.getPosition());
+        forceClose();
+    }
+
+    /**
+     * Returns the packet used for sending data (used by PreparedStatement)
+     * Guarded by external synchronization on a mutex.
+     *
+     * @return A packet to send data with
+     */
+    public Buffer getSharedSendPacket() {
+        if (this.sharedSendPacket == null) {
+        	this.sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
+        }
+
+        return this.sharedSendPacket;
+    }
+
+    public void closeStreamer(RowData streamer) throws SQLException {
+        if (this.streamingData == null) {
+            throw SQLError.createSQLException(Messages.getString("MysqlIO.17") //$NON-NLS-1$
+                 +streamer + Messages.getString("MysqlIO.18")); //$NON-NLS-1$
+        }
+
+        if (streamer != this.streamingData) {
+            throw SQLError.createSQLException(Messages.getString("MysqlIO.19") //$NON-NLS-1$
+                 +streamer + Messages.getString("MysqlIO.20") //$NON-NLS-1$
+                 +Messages.getString("MysqlIO.21") //$NON-NLS-1$
+                 +Messages.getString("MysqlIO.22")); //$NON-NLS-1$
+        }
+
+        this.streamingData = null;
+    }
+
+    public boolean tackOnMoreStreamingResults(ResultSetImpl addingTo) throws SQLException {
+    	if ((this.serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0) {
+    		
+			boolean moreRowSetsExist = true;
+			ResultSetImpl currentResultSet = addingTo;
+			boolean firstTime = true;
+			
+			while (moreRowSetsExist) {
+				if (!firstTime && currentResultSet.reallyResult()) {
+					break;
+				}
+				
+				firstTime = false;
+				
+				Buffer fieldPacket = checkErrorPacket();
+	            fieldPacket.setPosition(0);
+	            
+	            java.sql.Statement owningStatement = addingTo.getStatement();
+	            
+	            int maxRows = owningStatement.getMaxRows();
+	            
+	            // fixme for catalog, isBinary
+	            
+	            ResultSetImpl newResultSet = readResultsForQueryOrUpdate(
+	            		(StatementImpl)owningStatement,
+	                    maxRows, owningStatement.getResultSetType(), 
+	                    owningStatement.getResultSetConcurrency(),
+	                    true, owningStatement.getConnection().getCatalog(), fieldPacket, 
+	                    addingTo.isBinaryEncoded,
+	                    -1L, null);
+
+	            currentResultSet.setNextResultSet(newResultSet);
+
+	            currentResultSet = newResultSet;
+
+	            moreRowSetsExist = (this.serverStatus & MysqlIOprotocol.SERVER_MORE_RESULTS_EXISTS) != 0;
+	            
+	            if (!currentResultSet.reallyResult() && !moreRowSetsExist) {
+	            	// special case, we can stop "streaming"
+	            	return false;
+	            }
+			}
+			
+			return true;
+    	}
+
+    	return false;
+    }
+    
+    public ResultSetImpl readAllResults(StatementImpl callingStatement, int maxRows,
+        int resultSetType, int resultSetConcurrency, boolean streamResults,
+        String catalog, Buffer resultPacket, boolean isBinaryEncoded,
+        long preSentColumnCount, Field[] metadataFromCache)
+        throws SQLException {
+        resultPacket.setPosition(resultPacket.getPosition() - 1);
+
+        ResultSetImpl topLevelResultSet = readResultsForQueryOrUpdate(callingStatement,
+                maxRows, resultSetType, resultSetConcurrency, streamResults,
+                catalog, resultPacket, isBinaryEncoded, preSentColumnCount,
+                metadataFromCache);
+
+        ResultSetImpl currentResultSet = topLevelResultSet;
+
+        boolean checkForMoreResults = ((this.clientParam &
+            CLIENT_MULTI_RESULTS) != 0);
+
+        boolean serverHasMoreResults = (this.serverStatus &
+            SERVER_MORE_RESULTS_EXISTS) != 0;
+
+        //
+        // TODO: We need to support streaming of multiple result sets
+        //
+        if (serverHasMoreResults && streamResults) {
+            //clearInputStream();
+//
+            //throw SQLError.createSQLException(Messages.getString("MysqlIO.23"), //$NON-NLS-1$
+                //SQLError.SQL_STATE_DRIVER_NOT_CAPABLE);
+        	if (topLevelResultSet.getUpdateCount() != -1) {
+        		tackOnMoreStreamingResults(topLevelResultSet);
+        	}
+        	
+        	reclaimLargeReusablePacket();
+        	
+        	return topLevelResultSet;
+        }
+
+        boolean moreRowSetsExist = checkForMoreResults & serverHasMoreResults;
+
+        while (moreRowSetsExist) {
+        	Buffer fieldPacket = checkErrorPacket();
+            fieldPacket.setPosition(0);
+
+            ResultSetImpl newResultSet = readResultsForQueryOrUpdate(callingStatement,
+                    maxRows, resultSetType, resultSetConcurrency,
+                    streamResults, catalog, fieldPacket, isBinaryEncoded,
+                    preSentColumnCount, metadataFromCache);
+
+            currentResultSet.setNextResultSet(newResultSet);
+
+            currentResultSet = newResultSet;
+
+            moreRowSetsExist = (this.serverStatus & SERVER_MORE_RESULTS_EXISTS) != 0;
+        }
+
+        if (!streamResults) {
+            clearInputStream();
+        }
+
+        reclaimLargeReusablePacket();
+
+        return topLevelResultSet;
+    }
+
+    /**
+     * Sets the buffer size to max-buf
+     */
+    public void resetMaxBuf() {
+        this.maxAllowedPacket = this.connection.getMaxAllowedPacket();
+    }
+
+    /**
+     * Send a command to the MySQL server If data is to be sent with command,
+     * it should be put in extraData.
+     *
+     * Raw packets can be sent by setting queryPacket to something other
+     * than null.
+     *
+     * @param command the MySQL protocol 'command' from MysqlDefs
+     * @param extraData any 'string' data for the command
+     * @param queryPacket a packet pre-loaded with data for the protocol (i.e.
+     * from a client-side prepared statement).
+     * @param skipCheck do not call checkErrorPacket() if true
+     * @param extraDataCharEncoding the character encoding of the extraData
+     * parameter.
+     *
+     * @return the response packet from the server
+     *
+     * @throws SQLException if an I/O error or SQL error occurs
+     */
+
+    public final Buffer sendCommand(int command, String extraData, Buffer queryPacket,
+        boolean skipCheck, String extraDataCharEncoding)
+        throws SQLException {
+    	this.commandCount++;
+    	
+        //
+        // We cache these locally, per-command, as the checks
+        // for them are in very 'hot' sections of the I/O code
+        // and we save 10-15% in overall performance by doing this...
+        //
+        this.enablePacketDebug = this.connection.getEnablePacketDebug();
+        this.traceProtocol = this.connection.getTraceProtocol();
+        this.readPacketSequence = 0;
+
+        try {
+
+            checkForOutstandingStreamingData();
+
+            // Clear serverStatus...this value is guarded by an
+            // external mutex, as you can only ever be processing
+            // one command at a time
+            this.serverStatus = 0;
+            this.hadWarnings = false;
+            this.warningCount = 0;
+
+            this.queryNoIndexUsed = false;
+            this.queryBadIndexUsed = false;
+
+            //
+            // Compressed input stream needs cleared at beginning
+            // of each command execution...
+            //
+            if (this.useCompression) {
+                int bytesLeft = this.mysqlInput.available();
+
+                if (bytesLeft > 0) {
+                    this.mysqlInput.skip(bytesLeft);
+                }
+            }
+
+            try {
+                clearInputStream();
+
+                //
+                // PreparedStatements construct their own packets,
+                // for efficiency's sake.
+                //
+                // If this is a generic query, we need to re-use
+                // the sending packet.
+                //
+                if (queryPacket == null) {
+                    int packLength = HEADER_LENGTH + COMP_HEADER_LENGTH + 1 +
+                        ((extraData != null) ? extraData.length() : 0) + 2;
+
+                    if (this.sendPacket == null) {
+                        this.sendPacket = new Buffer(packLength);
+                    }
+
+                    this.packetSequence = -1;
+                    this.readPacketSequence = 0;
+                    this.checkPacketSequence = true;
+                    this.sendPacket.clear();
+
+                    this.sendPacket.writeByte((byte) command);
+
+                    if ((command == MysqlDefs.INIT_DB) ||
+                            (command == MysqlDefs.CREATE_DB) ||
+                            (command == MysqlDefs.DROP_DB) ||
+                            (command == MysqlDefs.QUERY) ||
+                            (command == MysqlDefs.COM_PREPARE)) {
+                        if (extraDataCharEncoding == null) {
+                            this.sendPacket.writeStringNoNull(extraData);
+                        } else {
+                            this.sendPacket.writeStringNoNull(extraData,
+                                extraDataCharEncoding,
+                                this.connection.getServerCharacterEncoding(),
+                                this.connection.parserKnowsUnicode(), this.connection);
+                        }
+                    } else if (command == MysqlDefs.PROCESS_KILL) {
+                        long id = Long.parseLong(extraData);
+                        this.sendPacket.writeLong(id);
+                    }
+
+                    send(this.sendPacket, this.sendPacket.getPosition());
+                } else {
+                    this.packetSequence = -1;
+                    send(queryPacket, queryPacket.getPosition()); // packet passed by PreparedStatement
+                }
+            } catch (SQLException sqlEx) {
+                // don't wrap SQLExceptions
+                throw sqlEx;
+            } catch (Exception ex) {
+                throw SQLError.createCommunicationsException(this.connection,
+                    this.lastPacketSentTimeMs, ex);
+            }
+
+            Buffer returnPacket = null;
+
+            if (!skipCheck) {
+                if ((command == MysqlDefs.COM_EXECUTE) ||
+                        (command == MysqlDefs.COM_RESET_STMT)) {
+                    this.readPacketSequence = 0;
+                    this.packetSequenceReset = true;
+                }
+
+                returnPacket = checkErrorPacket(command);
+            }
+
+            return returnPacket;
+        } catch (IOException ioEx) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs, ioEx);
+        }
+    }
+
+    private int statementExecutionDepth = 0;
+	private boolean useAutoSlowLog;
+
+    /**
+     * Send a query stored in a packet directly to the server.
+     *
+     * @param callingStatement DOCUMENT ME!
+     * @param resultSetConcurrency DOCUMENT ME!
+     * @param characterEncoding DOCUMENT ME!
+     * @param queryPacket DOCUMENT ME!
+     * @param maxRows DOCUMENT ME!
+     * @param conn DOCUMENT ME!
+     * @param resultSetType DOCUMENT ME!
+     * @param resultSetConcurrency DOCUMENT ME!
+     * @param streamResults DOCUMENT ME!
+     * @param catalog DOCUMENT ME!
+     * @param unpackFieldInfo should we read MYSQL_FIELD info (if available)?
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws Exception DOCUMENT ME!
+     */
+    public final ResultSetInternalMethods sqlQueryDirect(StatementImpl callingStatement, String query,
+    		String characterEncoding, Buffer queryPacket, int maxRows,
+    		int resultSetType, int resultSetConcurrency,
+    		boolean streamResults, String catalog, Field[] cachedMetadata)
+    throws Exception {
+    	this.statementExecutionDepth++;
+
+    	try {
+	    	if (this.statementInterceptors != null) {
+	    		ResultSetInternalMethods interceptedResults =
+	    			invokeStatementInterceptorsPre(query, callingStatement);
+
+	    		if (interceptedResults != null) {
+	    			return interceptedResults;
+	    		}
+	    	}
+
+	    	long queryStartTime = 0;
+	    	long queryEndTime = 0;
+
+	    	if (query != null) {
+
+	    		// We don't know exactly how many bytes we're going to get
+	    		// from the query. Since we're dealing with Unicode, the
+	    		// max is 2, so pad it (2 * query) + space for headers
+	    		int packLength = HEADER_LENGTH + 1 + (query.length() * 2) + 2;
+
+	    		String statementComment = this.connection.getStatementComment();
+
+	    		byte[] commentAsBytes = null;
+
+	    		if (statementComment != null) {
+	    			commentAsBytes = StringUtils.getBytes(statementComment, null,
+	    					characterEncoding, this.connection
+	    					.getServerCharacterEncoding(),
+	    					this.connection.parserKnowsUnicode());
+
+	    			packLength += commentAsBytes.length;
+	    			packLength += 6; // for /*[space] [space]*/
+	    		}
+
+	    		if (this.sendPacket == null) {
+	    			this.sendPacket = new Buffer(packLength);
+	    		} else {
+	    			this.sendPacket.clear();
+	    		}
+
+	    		this.sendPacket.writeByte((byte) MysqlDefs.QUERY);
+
+	    		if (commentAsBytes != null) {
+	    			this.sendPacket.writeBytesNoNull(Constants.SLASH_STAR_SPACE_AS_BYTES);
+	    			this.sendPacket.writeBytesNoNull(commentAsBytes);
+	    			this.sendPacket.writeBytesNoNull(Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
+	    		}
+
+	    		if (characterEncoding != null) {
+	    			if (this.platformDbCharsetMatches) {
+	    				this.sendPacket.writeStringNoNull(query, characterEncoding,
+	    						this.connection.getServerCharacterEncoding(),
+	    						this.connection.parserKnowsUnicode(),
+	    						this.connection);
+	    			} else {
+	    				if (StringUtils.startsWithIgnoreCaseAndWs(query, "LOAD DATA")) { //$NON-NLS-1$
+	    					this.sendPacket.writeBytesNoNull(query.getBytes());
+	    				} else {
+	    					this.sendPacket.writeStringNoNull(query,
+	    							characterEncoding,
+	    							this.connection.getServerCharacterEncoding(),
+	    							this.connection.parserKnowsUnicode(),
+	    							this.connection);
+	    				}
+	    			}
+	    		} else {
+	    			this.sendPacket.writeStringNoNull(query);
+	    		}
+
+	    		queryPacket = this.sendPacket;
+	    	}
+
+	    	byte[] queryBuf = null;
+	    	int oldPacketPosition = 0;
+
+	    	if (needToGrabQueryFromPacket) {
+	    		queryBuf = queryPacket.getByteBuffer();
+
+	    		// save the packet position
+	    		oldPacketPosition = queryPacket.getPosition();
+
+	    		queryStartTime = getCurrentTimeNanosOrMillis();
+	    	}
+
+	    	// Send query command and sql query string
+	    	Buffer resultPacket = sendCommand(MysqlDefs.QUERY, null, queryPacket,
+	    			false, null);
+
+	    	long fetchBeginTime = 0;
+	    	long fetchEndTime = 0;
+
+	    	String profileQueryToLog = null;
+
+	    	boolean queryWasSlow = false;
+
+	    	if (this.profileSql || this.logSlowQueries) {
+	    		queryEndTime = System.currentTimeMillis();
+
+	    		boolean shouldExtractQuery = false;
+
+	    		if (this.profileSql) {
+	    			shouldExtractQuery = true;
+	    		} else if (this.logSlowQueries) {
+	    			long queryTime = queryEndTime - queryStartTime;
+	    			
+	    			boolean logSlow = false;
+	    			
+	    			if (this.useAutoSlowLog) {
+	    				logSlow = queryTime > this.connection.getSlowQueryThresholdMillis();
+	    			} else {
+	    				logSlow = this.connection.isAbonormallyLongQuery(queryTime);
+	    				
+	    				this.connection.reportQueryTime(queryTime);
+	    			}
+	    			
+	    			if (logSlow) {
+	    				shouldExtractQuery = true;
+	    				queryWasSlow = true;
+	    			}
+	    		}
+
+	    		if (shouldExtractQuery) {
+	    			// Extract the actual query from the network packet
+	    			boolean truncated = false;
+
+	    			int extractPosition = oldPacketPosition;
+
+	    			if (oldPacketPosition > this.connection.getMaxQuerySizeToLog()) {
+	    				extractPosition = this.connection.getMaxQuerySizeToLog() + 5;
+	    				truncated = true;
+	    			}
+
+	    			profileQueryToLog = new String(queryBuf, 5,
+	    					(extractPosition - 5));
+
+	    			if (truncated) {
+	    				profileQueryToLog += Messages.getString("MysqlIO.25"); //$NON-NLS-1$
+	    			}
+	    		}
+
+	    		fetchBeginTime = queryEndTime;
+	    	}
+
+	    	if (this.autoGenerateTestcaseScript) {
+	    		String testcaseQuery = null;
+
+	    		if (query != null) {
+	    			testcaseQuery = query;
+	    		} else {
+	    			testcaseQuery = new String(queryBuf, 5,
+	    					(oldPacketPosition - 5));
+	    		}
+
+	    		StringBuffer debugBuf = new StringBuffer(testcaseQuery.length() + 32);
+	    		this.connection.generateConnectionCommentBlock(debugBuf);
+	    		debugBuf.append(testcaseQuery);
+	    		debugBuf.append(';');
+	    		this.connection.dumpTestcaseQuery(debugBuf.toString());
+	    	}
+
+	    	ResultSetInternalMethods rs = readAllResults(callingStatement, maxRows, resultSetType,
+	    			resultSetConcurrency, streamResults, catalog, resultPacket,
+	    			false, -1L, cachedMetadata);
+
+	    	if (queryWasSlow) {
+	    		StringBuffer mesgBuf = new StringBuffer(48 +
+	    				profileQueryToLog.length());
+
+	    		mesgBuf.append(Messages.getString("MysqlIO.SlowQuery",
+	    				new Object[] {new Long(this.slowQueryThreshold),
+	    				queryTimingUnits,
+	    				new Long(queryEndTime - queryStartTime)}));
+	    		mesgBuf.append(profileQueryToLog);
+
+	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
+
+	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_SLOW_QUERY,
+	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
+	    				(callingStatement != null) ? callingStatement.getId() : 999,
+	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
+	    						(int) (queryEndTime - queryStartTime), queryTimingUnits, null,
+	    						new Throwable(), mesgBuf.toString()));
+
+	    		if (this.connection.getExplainSlowQueries()) {
+	    			if (oldPacketPosition < MAX_QUERY_SIZE_TO_EXPLAIN) {
+	    				explainSlowQuery(queryPacket.getBytes(5,
+	    						(oldPacketPosition - 5)), profileQueryToLog);
+	    			} else {
+	    				this.connection.getLog().logWarn(Messages.getString(
+	    						"MysqlIO.28") //$NON-NLS-1$
+	    						+MAX_QUERY_SIZE_TO_EXPLAIN +
+	    						Messages.getString("MysqlIO.29")); //$NON-NLS-1$
+	    			}
+	    		}
+	    	}
+
+	    	if (this.logSlowQueries) {
+
+	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
+
+	    		if (this.queryBadIndexUsed) {
+	    			eventSink.consumeEvent(new ProfilerEvent(
+	    					ProfilerEvent.TYPE_SLOW_QUERY, "", catalog, //$NON-NLS-1$
+	    					this.connection.getId(),
+	    					(callingStatement != null) ? callingStatement.getId()
+	    							: 999, ((ResultSetImpl)rs).resultId,
+	    							System.currentTimeMillis(),
+	    							(queryEndTime - queryStartTime), this.queryTimingUnits,
+	    							null,
+	    							new Throwable(),
+	    							Messages.getString("MysqlIO.33") //$NON-NLS-1$
+	    							+profileQueryToLog));
+	    		}
+
+	    		if (this.queryNoIndexUsed) {
+	    			eventSink.consumeEvent(new ProfilerEvent(
+	    					ProfilerEvent.TYPE_SLOW_QUERY, "", catalog, //$NON-NLS-1$
+	    					this.connection.getId(),
+	    					(callingStatement != null) ? callingStatement.getId()
+	    							: 999, ((ResultSetImpl)rs).resultId,
+	    							System.currentTimeMillis(),
+	    							(queryEndTime - queryStartTime), this.queryTimingUnits,
+	    							null,
+	    							new Throwable(),
+	    							Messages.getString("MysqlIO.35") //$NON-NLS-1$
+	    							+profileQueryToLog));
+	    		}
+	    	}
+
+	    	if (this.profileSql) {
+	    		fetchEndTime = getCurrentTimeNanosOrMillis();
+
+	    		ProfilerEventHandler eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
+
+	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_QUERY,
+	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
+	    				(callingStatement != null) ? callingStatement.getId() : 999,
+	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
+	    						(queryEndTime - queryStartTime), this.queryTimingUnits,
+	    						null,
+	    						new Throwable(), profileQueryToLog));
+
+	    		eventSink.consumeEvent(new ProfilerEvent(ProfilerEvent.TYPE_FETCH,
+	    				"", catalog, this.connection.getId(), //$NON-NLS-1$
+	    				(callingStatement != null) ? callingStatement.getId() : 999,
+	    						((ResultSetImpl)rs).resultId, System.currentTimeMillis(),
+	    						(fetchEndTime - fetchBeginTime), this.queryTimingUnits,
+	    						null,
+	    						new Throwable(), null));
+	    	}
+
+	    	if (this.hadWarnings) {
+	    		scanForAndThrowDataTruncation();
+	    	}
+
+	    	if (this.statementInterceptors != null) {
+	    		ResultSetInternalMethods interceptedResults = invokeStatementInterceptorsPost(
+	    				query, callingStatement, rs);
+
+	    		if (interceptedResults != null) {
+	    			rs = interceptedResults;
+	    		}
+	    	}
+
+	    	return rs;
+    	} finally {
+    		this.statementExecutionDepth--;
+    	}
+    }
+
+    private ResultSetInternalMethods invokeStatementInterceptorsPre(String sql,
+			Statement interceptedStatement) throws SQLException {
+		ResultSetInternalMethods previousResultSet = null;
+
+		Iterator interceptors = this.statementInterceptors.iterator();
+
+		while (interceptors.hasNext()) {
+			StatementInterceptor interceptor = ((StatementInterceptor) interceptors
+					.next());
+
+			boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
+			boolean shouldExecute = (executeTopLevelOnly && this.statementExecutionDepth == 1)
+					|| (!executeTopLevelOnly);
+
+			if (shouldExecute) {
+				String sqlToInterceptor = sql;
+
+				if (interceptedStatement instanceof PreparedStatement) {
+					sqlToInterceptor = ((PreparedStatement) interceptedStatement)
+							.asSql();
+				}
+
+				ResultSetInternalMethods interceptedResultSet = interceptor
+						.preProcess(sqlToInterceptor, interceptedStatement,
+								this.connection);
+
+				if (interceptedResultSet != null) {
+					previousResultSet = interceptedResultSet;
+				}
+			}
+		}
+
+		return previousResultSet;
+	}
+
+	private ResultSetInternalMethods invokeStatementInterceptorsPost(
+			String sql, Statement interceptedStatement,
+			ResultSetInternalMethods originalResultSet) throws SQLException {
+		Iterator interceptors = this.statementInterceptors.iterator();
+
+		while (interceptors.hasNext()) {
+			StatementInterceptor interceptor = ((StatementInterceptor) interceptors
+					.next());
+
+			boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
+			boolean shouldExecute = (executeTopLevelOnly && this.statementExecutionDepth == 1)
+					|| (!executeTopLevelOnly);
+
+			if (shouldExecute) {
+				String sqlToInterceptor = sql;
+
+				if (interceptedStatement instanceof PreparedStatement) {
+					sqlToInterceptor = ((PreparedStatement) interceptedStatement)
+							.asSql();
+				}
+
+				ResultSetInternalMethods interceptedResultSet = interceptor
+						.postProcess(sqlToInterceptor, interceptedStatement,
+								originalResultSet, this.connection);
+
+				if (interceptedResultSet != null) {
+					originalResultSet = interceptedResultSet;
+				}
+			}
+		}
+
+		return originalResultSet;
+	}
+
+	private void calculateSlowQueryThreshold() {
+		this.slowQueryThreshold = this.connection.getSlowQueryThresholdMillis();
+
+		if (this.connection.getUseNanosForElapsedTime()) {
+			long nanosThreshold = this.connection.getSlowQueryThresholdNanos();
+
+			if (nanosThreshold != 0) {
+				this.slowQueryThreshold = nanosThreshold;
+			} else {
+				this.slowQueryThreshold *= 1000000; // 1 million millis in a nano
+			}
+		}
+	}
+
+	protected long getCurrentTimeNanosOrMillis() {
+		if (this.useNanosForElapsedTime) {
+			return Util.getCurrentTimeNanosOrMillis();
+		}
+
+		return System.currentTimeMillis();
+	}
+
+    /**
+     * Returns the host this IO is connected to
+     *
+     * @return DOCUMENT ME!
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Is the version of the MySQL server we are connected to the given
+     * version?
+     *
+     * @param major the major version
+     * @param minor the minor version
+     * @param subminor the subminor version
+     *
+     * @return true if the version of the MySQL server we are connected  is the
+     *         given version
+     */
+    boolean isVersion(int major, int minor, int subminor) {
+        return ((major == getServerMajorVersion()) &&
+        (minor == getServerMinorVersion()) &&
+        (subminor == getServerSubMinorVersion()));
+    }
+
+    /**
+     * Does the version of the MySQL server we are connected to meet the given
+     * minimums?
+     *
+     * @param major DOCUMENT ME!
+     * @param minor DOCUMENT ME!
+     * @param subminor DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     */
+    public boolean versionMeetsMinimum(int major, int minor, int subminor) {
+        if (getServerMajorVersion() >= major) {
+            if (getServerMajorVersion() == major) {
+                if (getServerMinorVersion() >= minor) {
+                    if (getServerMinorVersion() == minor) {
+                        return (getServerSubMinorVersion() >= subminor);
+                    }
+
+                    // newer than major.minor
+                    return true;
+                }
+
+                // older than major.minor
+                return false;
+            }
+
+            // newer than major
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the hex dump of the given packet, truncated to
+     * MAX_PACKET_DUMP_LENGTH if packetLength exceeds that value.
+     *
+     * @param packetToDump the packet to dump in hex
+     * @param packetLength the number of bytes to dump
+     *
+     * @return the hex dump of the given packet
+     */
+    private final static String getPacketDumpToLog(Buffer packetToDump,
+        int packetLength) {
+        if (packetLength < MAX_PACKET_DUMP_LENGTH) {
+            return packetToDump.dump(packetLength);
+        }
+
+        StringBuffer packetDumpBuf = new StringBuffer(MAX_PACKET_DUMP_LENGTH * 4);
+        packetDumpBuf.append(packetToDump.dump(MAX_PACKET_DUMP_LENGTH));
+        packetDumpBuf.append(Messages.getString("MysqlIO.36")); //$NON-NLS-1$
+        packetDumpBuf.append(MAX_PACKET_DUMP_LENGTH);
+        packetDumpBuf.append(Messages.getString("MysqlIO.37")); //$NON-NLS-1$
+
+        return packetDumpBuf.toString();
+    }
+
+    private final int readFully(InputStream in, byte[] b, int off, int len)
+        throws IOException {
+        if (len < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        int n = 0;
+
+        while (n < len) {
+            int count = in.read(b, off + n, len - n);
+
+            if (count < 0) {
+                throw new EOFException(Messages.getString("MysqlIO.EOF",
+                		new Object[] {new Integer(len), new Integer(n)}));
+            }
+
+            n += count;
+        }
+
+        return n;
+    }
+
+    private final long skipFully(InputStream in, long len) throws IOException {
+    	if (len < 0) {
+    		throw new IOException("Negative skip length not allowed");
+    	}
+
+    	long n = 0;
+
+    	while (n < len) {
+    		long count = in.skip(len - n);
+
+    		if (count < 0) {
+    			throw new EOFException(Messages.getString("MysqlIO.EOF",
+                		new Object[] {new Long(len), new Long(n)}));
+    		}
+
+    		n += count;
+    	}
+
+    	return n;
+    }
+
+    /**
+     * Reads one result set off of the wire, if the result is actually an
+     * update count, creates an update-count only result set.
+     *
+     * @param callingStatement DOCUMENT ME!
+     * @param maxRows the maximum rows to return in the result set.
+     * @param resultSetType scrollability
+     * @param resultSetConcurrency updatability
+     * @param streamResults should the driver leave the results on the wire,
+     *        and read them only when needed?
+     * @param catalog the catalog in use
+     * @param resultPacket the first packet of information in the result set
+     * @param isBinaryEncoded is this result set from a prepared statement?
+     * @param preSentColumnCount do we already know the number of columns?
+     * @param unpackFieldInfo should we unpack the field information?
+     *
+     * @return a result set that either represents the rows, or an update count
+     *
+     * @throws SQLException if an error occurs while reading the rows
+     */
+    protected final ResultSetImpl readResultsForQueryOrUpdate(
+        StatementImpl callingStatement, int maxRows, int resultSetType,
+        int resultSetConcurrency, boolean streamResults, String catalog,
+        Buffer resultPacket, boolean isBinaryEncoded, long preSentColumnCount,
+        Field[] metadataFromCache) throws SQLException {
+        long columnCount = resultPacket.readFieldLength();
+
+        if (columnCount == 0) {
+            return buildResultSetWithUpdates(callingStatement, resultPacket);
+        } else if (columnCount == Buffer.NULL_LENGTH) {
+            String charEncoding = null;
+
+            if (this.connection.getUseUnicode()) {
+                charEncoding = this.connection.getEncoding();
+            }
+
+            String fileName = null;
+
+            if (this.platformDbCharsetMatches) {
+                fileName = ((charEncoding != null)
+                    ? resultPacket.readString(charEncoding)
+                    : resultPacket.readString());
+            } else {
+                fileName = resultPacket.readString();
+            }
+
+            return sendFileToServer(callingStatement, fileName);
+        } else {
+            com.mysql.jdbc.ResultSetImpl results = getResultSet(callingStatement,
+                    columnCount, maxRows, resultSetType, resultSetConcurrency,
+                    streamResults, catalog, isBinaryEncoded,
+                    metadataFromCache);
+
+            return results;
+        }
+    }
+
+    private int alignPacketSize(int a, int l) {
+        return ((((a) + (l)) - 1) & ~((l) - 1));
+    }
+
+    private com.mysql.jdbc.ResultSetImpl buildResultSetWithRows(
+        StatementImpl callingStatement, String catalog,
+        com.mysql.jdbc.Field[] fields, RowData rows, int resultSetType,
+        int resultSetConcurrency, boolean isBinaryEncoded)
+        throws SQLException {
+        ResultSetImpl rs = null;
+
+        switch (resultSetConcurrency) {
+        case java.sql.ResultSet.CONCUR_READ_ONLY:
+            rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
+                    this.connection, callingStatement, false);
+
+            if (isBinaryEncoded) {
+                rs.setBinaryEncoded();
+            }
+
+            break;
+
+        case java.sql.ResultSet.CONCUR_UPDATABLE:
+            rs = com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
+                    this.connection, callingStatement, true);
+
+            break;
+
+        default:
+            return com.mysql.jdbc.ResultSetImpl.getInstance(catalog, fields, rows,
+                this.connection, callingStatement, false);
+        }
+
+        rs.setResultSetType(resultSetType);
+        rs.setResultSetConcurrency(resultSetConcurrency);
+
+        return rs;
+    }
+
+    private com.mysql.jdbc.ResultSetImpl buildResultSetWithUpdates(
+        StatementImpl callingStatement, Buffer resultPacket)
+        throws SQLException {
+        long updateCount = -1;
+        long updateID = -1;
+        String info = null;
+
+        try {
+            if (this.useNewUpdateCounts) {
+                updateCount = resultPacket.newReadLength();
+                updateID = resultPacket.newReadLength();
+            } else {
+                updateCount = resultPacket.readLength();
+                updateID = resultPacket.readLength();
+            }
+
+            if (this.use41Extensions) {
+                this.serverStatus = resultPacket.readInt();
+
+                this.warningCount = resultPacket.readInt();
+
+                if (this.warningCount > 0) {
+                    this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
+                }
+
+                resultPacket.readByte(); // advance pointer
+
+                if (this.profileSql) {
+                    this.queryNoIndexUsed = (this.serverStatus &
+                        SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
+                    this.queryBadIndexUsed = (this.serverStatus &
+                        SERVER_QUERY_NO_INDEX_USED) != 0;
+                }
+            }
+
+            if (this.connection.isReadInfoMsgEnabled()) {
+                info = resultPacket.readString();
+            }
+        } catch (Exception ex) {
+            SQLException sqlEx = SQLError.createSQLException(SQLError.get(
+                    SQLError.SQL_STATE_GENERAL_ERROR), SQLError.SQL_STATE_GENERAL_ERROR, -1);
+            sqlEx.initCause(ex);
+            
+            throw sqlEx;
+        }
+
+        ResultSetInternalMethods updateRs = com.mysql.jdbc.ResultSetImpl.getInstance(updateCount,
+                updateID, this.connection, callingStatement);
+
+        if (info != null) {
+            ((com.mysql.jdbc.ResultSetImpl)updateRs).setServerInfo(info);
+        }
+
+        return (com.mysql.jdbc.ResultSetImpl)updateRs;
+    }
+
+    private void checkForOutstandingStreamingData() throws SQLException {
+        if (this.streamingData != null) {
+        	boolean shouldClobber = this.connection.getClobberStreamingResults();
+
+            if (!shouldClobber) {
+                throw SQLError.createSQLException(Messages.getString("MysqlIO.39") //$NON-NLS-1$
+                     +this.streamingData +
+                    Messages.getString("MysqlIO.40") //$NON-NLS-1$
+                     +Messages.getString("MysqlIO.41") //$NON-NLS-1$
+                     +Messages.getString("MysqlIO.42")); //$NON-NLS-1$
+            }
+
+            // Close the result set
+            this.streamingData.getOwner().realClose(false);
+
+            // clear any pending data....
+            clearInputStream();
+        }
+    }
+
+    private Buffer compressPacket(Buffer packet, int offset, int packetLen,
+        int headerLength) throws SQLException {
+        packet.writeLongInt(packetLen - headerLength);
+        packet.writeByte((byte) 0); // wrapped packet has 0 packet seq.
+
+        int lengthToWrite = 0;
+        int compressedLength = 0;
+        byte[] bytesToCompress = packet.getByteBuffer();
+        byte[] compressedBytes = null;
+        int offsetWrite = 0;
+
+        if (packetLen < MIN_COMPRESS_LEN) {
+            lengthToWrite = packetLen;
+            compressedBytes = packet.getByteBuffer();
+            compressedLength = 0;
+            offsetWrite = offset;
+        } else {
+            compressedBytes = new byte[bytesToCompress.length * 2];
+
+            this.deflater.reset();
+            this.deflater.setInput(bytesToCompress, offset, packetLen);
+            this.deflater.finish();
+
+            int compLen = this.deflater.deflate(compressedBytes);
+
+            if (compLen > packetLen) {
+                lengthToWrite = packetLen;
+                compressedBytes = packet.getByteBuffer();
+                compressedLength = 0;
+                offsetWrite = offset;
+            } else {
+                lengthToWrite = compLen;
+                headerLength += COMP_HEADER_LENGTH;
+                compressedLength = packetLen;
+            }
+        }
+
+        Buffer compressedPacket = new Buffer(packetLen + headerLength);
+
+        compressedPacket.setPosition(0);
+        compressedPacket.writeLongInt(lengthToWrite);
+        compressedPacket.writeByte(this.packetSequence);
+        compressedPacket.writeLongInt(compressedLength);
+        compressedPacket.writeBytesNoNull(compressedBytes, offsetWrite,
+            lengthToWrite);
+
+        return compressedPacket;
+    }
+
+    private final void readServerStatusForResultSets(Buffer rowPacket)
+        throws SQLException {
+        if (this.use41Extensions) {
+            rowPacket.readByte(); // skips the 'last packet' flag
+
+            this.warningCount = rowPacket.readInt();
+
+            if (this.warningCount > 0) {
+                this.hadWarnings = true; // this is a 'latch', it's reset by sendCommand()
+            }
+
+            this.serverStatus = rowPacket.readInt();
+
+            if (this.profileSql) {
+                this.queryNoIndexUsed = (this.serverStatus &
+                    SERVER_QUERY_NO_GOOD_INDEX_USED) != 0;
+                this.queryBadIndexUsed = (this.serverStatus &
+                    SERVER_QUERY_NO_INDEX_USED) != 0;
+            }
+        }
+    }
+
+    //TODO: use Util.getInstance
+    private SocketFactory createSocketFactory() throws SQLException {
+        try {
+            if (this.socketFactoryClassName == null) {
+                throw SQLError.createSQLException(Messages.getString("MysqlIO.75"), //$NON-NLS-1$
+                    SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
+            }
+
+            return (SocketFactory) (Class.forName(this.socketFactoryClassName)
+                                         .newInstance());
+        } catch (Exception ex) {
+            SQLException sqlEx = SQLError.createSQLException(Messages.getString("MysqlIO.76") //$NON-NLS-1$
+                 +this.socketFactoryClassName +
+                Messages.getString("MysqlIO.77"),
+                SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
+            
+            sqlEx.initCause(ex);
+            
+            throw sqlEx;
+        }
+    }
+
+    private void enqueuePacketForDebugging(boolean isPacketBeingSent,
+        boolean isPacketReused, int sendLength, byte[] header, Buffer packet)
+        throws SQLException {
+        if ((this.packetDebugRingBuffer.size() + 1) > this.connection.getPacketDebugBufferSize()) {
+            this.packetDebugRingBuffer.removeFirst();
+        }
+
+        StringBuffer packetDump = null;
+
+        if (!isPacketBeingSent) {
+            int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH,
+                    packet.getBufLength());
+
+            Buffer packetToDump = new Buffer(4 + bytesToDump);
+
+            packetToDump.setPosition(0);
+            packetToDump.writeBytesNoNull(header);
+            packetToDump.writeBytesNoNull(packet.getBytes(0, bytesToDump));
+
+            String packetPayload = packetToDump.dump(bytesToDump);
+
+            packetDump = new StringBuffer(96 + packetPayload.length());
+
+            packetDump.append("Server ");
+
+            if (isPacketReused) {
+                packetDump.append("(re-used)");
+            } else {
+                packetDump.append("(new)");
+            }
+
+            packetDump.append(" ");
+            packetDump.append(packet.toSuperString());
+            packetDump.append(" --------------------> Client\n");
+            packetDump.append("\nPacket payload:\n\n");
+            packetDump.append(packetPayload);
+
+            if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
+                packetDump.append("\nNote: Packet of " + packet.getBufLength() +
+                    " bytes truncated to " + MAX_PACKET_DUMP_LENGTH +
+                    " bytes.\n");
+            }
+        } else {
+            int bytesToDump = Math.min(MAX_PACKET_DUMP_LENGTH, sendLength);
+
+            String packetPayload = packet.dump(bytesToDump);
+
+            packetDump = new StringBuffer(64 + 4 + packetPayload.length());
+
+            packetDump.append("Client ");
+            packetDump.append(packet.toSuperString());
+            packetDump.append("--------------------> Server\n");
+            packetDump.append("\nPacket payload:\n\n");
+            packetDump.append(packetPayload);
+
+            if (bytesToDump == MAX_PACKET_DUMP_LENGTH) {
+                packetDump.append("\nNote: Packet of " + sendLength +
+                    " bytes truncated to " + MAX_PACKET_DUMP_LENGTH +
+                    " bytes.\n");
+            }
+        }
+
+        this.packetDebugRingBuffer.addLast(packetDump);
+    }
+
+    private RowData readSingleRowSet(long columnCount, int maxRows,
+        int resultSetConcurrency, boolean isBinaryEncoded, Field[] fields)
+        throws SQLException {
+        RowData rowData;
+        ArrayList rows = new ArrayList();
+
+        boolean useBufferRowExplicit = useBufferRowExplicit(fields);
+
+        // Now read the data
+        ResultSetRow row = nextRow(fields, (int) columnCount, isBinaryEncoded,
+                resultSetConcurrency, false, useBufferRowExplicit, false, null);
+
+        int rowCount = 0;
+
+        if (row != null) {
+            rows.add(row);
+            rowCount = 1;
+        }
+
+        while (row != null) {
+        	row = nextRow(fields, (int) columnCount, isBinaryEncoded,
+                    resultSetConcurrency, false, useBufferRowExplicit, false, null);
+
+            if (row != null) {
+            	if ((maxRows == -1) || (rowCount < maxRows)) {
+            		rows.add(row);
+            		rowCount++;
+            	}
+            }
+        }
+
+        rowData = new RowDataStatic(rows);
+
+        return rowData;
+    }
+
+    /*
+     * TODO: find a beter place where this static function should live; Field
+     * perhaps?
+     */
+    public static boolean useBufferRowExplicit(Field[] fields) {
+    	if (fields == null) {
+    		return false;
+    	}
+
+		for (int i = 0; i < fields.length; i++) {
+			switch (fields[i].getSQLType()) {
+			case Types.BLOB:
+			case Types.CLOB:
+			case Types.LONGVARBINARY:
+			case Types.LONGVARCHAR:
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+     * Don't hold on to overly-large packets
+     */
+    private void reclaimLargeReusablePacket() {
+        if ((this.reusablePacket != null) &&
+                (this.reusablePacket.getCapacity() > 1048576)) {
+            this.reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
+        }
+    }
+
+    /**
+     * Re-use a packet to read from the MySQL server
+     *
+     * @param reuse DOCUMENT ME!
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws SQLException DOCUMENT ME!
+     * @throws SQLException DOCUMENT ME!
+     */
+    private final Buffer reuseAndReadPacket(Buffer reuse) throws SQLException {
+    	return reuseAndReadPacket(reuse, -1);
+    }
+
+    private final Buffer reuseAndReadPacket(Buffer reuse, int existingPacketLength)
+        throws SQLException {
+
+    	try {
+    		reuse.setWasMultiPacket(false);
+    		int packetLength = 0;
+
+    		if (existingPacketLength == -1) {
+	    		int lengthRead = readFully(this.mysqlInput,
+	    				this.packetHeaderBuf, 0, 4);
+
+	    		if (lengthRead < 4) {
+	    			forceClose();
+	    			throw new IOException(Messages.getString("MysqlIO.43")); //$NON-NLS-1$
+	    		}
+
+	    		packetLength = (this.packetHeaderBuf[0] & 0xff) +
+	    		((this.packetHeaderBuf[1] & 0xff) << 8) +
+	    		((this.packetHeaderBuf[2] & 0xff) << 16);
+    		} else {
+    			packetLength = existingPacketLength;
+    		}
+
+    		if (this.traceProtocol) {
+    			StringBuffer traceMessageBuf = new StringBuffer();
+
+    			traceMessageBuf.append(Messages.getString("MysqlIO.44")); //$NON-NLS-1$
+    			traceMessageBuf.append(packetLength);
+    			traceMessageBuf.append(Messages.getString("MysqlIO.45")); //$NON-NLS-1$
+    			traceMessageBuf.append(StringUtils.dumpAsHex(
+    					this.packetHeaderBuf, 4));
+
+    			this.connection.getLog().logTrace(traceMessageBuf.toString());
+    		}
+
+    		byte multiPacketSeq = this.packetHeaderBuf[3];
+
+    		if (!this.packetSequenceReset) {
+    			if (this.enablePacketDebug && this.checkPacketSequence) {
+    				checkPacketSequencing(multiPacketSeq);
+    			}
+    		} else {
+    			this.packetSequenceReset = false;
+    		}
+
+    		this.readPacketSequence = multiPacketSeq;
+
+    		// Set the Buffer to it's original state
+    		reuse.setPosition(0);
+
+    		// Do we need to re-alloc the byte buffer?
+    		//
+    		// Note: We actually check the length of the buffer,
+    		// rather than getBufLength(), because getBufLength() is not
+    		// necesarily the actual length of the byte array
+    		// used as the buffer
+    		if (reuse.getByteBuffer().length <= packetLength) {
+    			reuse.setByteBuffer(new byte[packetLength + 1]);
+    		}
+
+    		// Set the new length
+    		reuse.setBufLength(packetLength);
+
+    		// Read the data from the server
+    		int numBytesRead = readFully(this.mysqlInput,
+    				reuse.getByteBuffer(), 0, packetLength);
+
+    		if (numBytesRead != packetLength) {
+    			throw new IOException("Short read, expected " +
+    					packetLength + " bytes, only read " + numBytesRead);
+    		}
+
+    		if (this.traceProtocol) {
+    			StringBuffer traceMessageBuf = new StringBuffer();
+
+    			traceMessageBuf.append(Messages.getString("MysqlIO.46")); //$NON-NLS-1$
+    			traceMessageBuf.append(getPacketDumpToLog(reuse,
+    					packetLength));
+
+    			this.connection.getLog().logTrace(traceMessageBuf.toString());
+    		}
+
+    		if (this.enablePacketDebug) {
+    			enqueuePacketForDebugging(false, true, 0,
+    					this.packetHeaderBuf, reuse);
+    		}
+
+    		boolean isMultiPacket = false;
+
+    		if (packetLength == this.maxThreeBytes) {
+    			reuse.setPosition(this.maxThreeBytes);
+
+    			int packetEndPoint = packetLength;
+
+    			// it's multi-packet
+    			isMultiPacket = true;
+
+    			packetLength = readRemainingMultiPackets(reuse, multiPacketSeq,
+						packetEndPoint);
+    		}
+
+    		if (!isMultiPacket) {
+    			reuse.getByteBuffer()[packetLength] = 0; // Null-termination
+    		}
+
+    		return reuse;
+    	} catch (IOException ioEx) {
+    		throw SQLError.createCommunicationsException(this.connection,
+    				this.lastPacketSentTimeMs, ioEx);
+    	} catch (OutOfMemoryError oom) {
+    		try {
+    			// _Try_ this
+    			clearInputStream();
+    		} finally {
+    			try {
+    				this.connection.realClose(false, false, true, oom);
+    			} finally {
+    				throw oom;
+    			}
+    		}
+    	}
+
+    }
+
+	private int readRemainingMultiPackets(Buffer reuse, byte multiPacketSeq,
+			int packetEndPoint) throws IOException, SQLException {
+		int lengthRead;
+		int packetLength;
+		lengthRead = readFully(this.mysqlInput,
+				this.packetHeaderBuf, 0, 4);
+
+		if (lengthRead < 4) {
+			forceClose();
+			throw new IOException(Messages.getString("MysqlIO.47")); //$NON-NLS-1$
+		}
+
+		packetLength = (this.packetHeaderBuf[0] & 0xff) +
+			((this.packetHeaderBuf[1] & 0xff) << 8) +
+			((this.packetHeaderBuf[2] & 0xff) << 16);
+
+		Buffer multiPacket = new Buffer(packetLength);
+		boolean firstMultiPkt = true;
+
+		while (true) {
+			if (!firstMultiPkt) {
+				lengthRead = readFully(this.mysqlInput,
+						this.packetHeaderBuf, 0, 4);
+
+				if (lengthRead < 4) {
+					forceClose();
+					throw new IOException(Messages.getString(
+					"MysqlIO.48")); //$NON-NLS-1$
+				}
+
+				packetLength = (this.packetHeaderBuf[0] & 0xff) +
+				((this.packetHeaderBuf[1] & 0xff) << 8) +
+				((this.packetHeaderBuf[2] & 0xff) << 16);
+			} else {
+				firstMultiPkt = false;
+			}
+
+			if (!this.useNewLargePackets && (packetLength == 1)) {
+				clearInputStream();
+
+				break;
+			} else if (packetLength < this.maxThreeBytes) {
+				byte newPacketSeq = this.packetHeaderBuf[3];
+
+				if (newPacketSeq != (multiPacketSeq + 1)) {
+					throw new IOException(Messages.getString(
+					"MysqlIO.49")); //$NON-NLS-1$
+				}
+
+				multiPacketSeq = newPacketSeq;
+
+				// Set the Buffer to it's original state
+				multiPacket.setPosition(0);
+
+				// Set the new length
+				multiPacket.setBufLength(packetLength);
+
+				// Read the data from the server
+				byte[] byteBuf = multiPacket.getByteBuffer();
+				int lengthToWrite = packetLength;
+
+				int bytesRead = readFully(this.mysqlInput, byteBuf,
+						0, packetLength);
+
+				if (bytesRead != lengthToWrite) {
+					throw SQLError.createCommunicationsException(this.connection,
+							this.lastPacketSentTimeMs,
+							SQLError.createSQLException(Messages.getString(
+							"MysqlIO.50") //$NON-NLS-1$
+							+lengthToWrite +
+							Messages.getString("MysqlIO.51") +
+							bytesRead //$NON-NLS-1$
+							+".")); //$NON-NLS-1$
+				}
+
+				reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
+
+				packetEndPoint += lengthToWrite;
+
+				break; // end of multipacket sequence
+			}
+
+			byte newPacketSeq = this.packetHeaderBuf[3];
+
+			if (newPacketSeq != (multiPacketSeq + 1)) {
+				throw new IOException(Messages.getString(
+				"MysqlIO.53")); //$NON-NLS-1$
+			}
+
+			multiPacketSeq = newPacketSeq;
+
+			// Set the Buffer to it's original state
+			multiPacket.setPosition(0);
+
+			// Set the new length
+			multiPacket.setBufLength(packetLength);
+
+			// Read the data from the server
+			byte[] byteBuf = multiPacket.getByteBuffer();
+			int lengthToWrite = packetLength;
+
+			int bytesRead = readFully(this.mysqlInput, byteBuf, 0,
+					packetLength);
+
+			if (bytesRead != lengthToWrite) {
+				throw SQLError.createCommunicationsException(this.connection,
+						this.lastPacketSentTimeMs,
+						SQLError.createSQLException(Messages.getString(
+						"MysqlIO.54") //$NON-NLS-1$
+						+lengthToWrite +
+						Messages.getString("MysqlIO.55") //$NON-NLS-1$
+						+bytesRead + ".")); //$NON-NLS-1$
+			}
+
+			reuse.writeBytesNoNull(byteBuf, 0, lengthToWrite);
+
+			packetEndPoint += lengthToWrite;
+		}
+
+		reuse.setPosition(0);
+		reuse.setWasMultiPacket(true);
+		return packetLength;
+	}
+
+    /**
+         * @param multiPacketSeq
+         * @throws CommunicationsException
+         */
+    private void checkPacketSequencing(byte multiPacketSeq)
+        throws SQLException {
+        if ((multiPacketSeq == -128) && (this.readPacketSequence != 127)) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs,
+                new IOException("Packets out of order, expected packet # -128, but received packet # " +
+                    multiPacketSeq));
+        }
+
+        if ((this.readPacketSequence == -1) && (multiPacketSeq != 0)) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs,
+                new IOException("Packets out of order, expected packet # -1, but received packet # " +
+                    multiPacketSeq));
+        }
+
+        if ((multiPacketSeq != -128) && (this.readPacketSequence != -1) &&
+                (multiPacketSeq != (this.readPacketSequence + 1))) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs,
+                new IOException("Packets out of order, expected packet # " +
+                    (this.readPacketSequence + 1) + ", but received packet # " +
+                    multiPacketSeq));
+        }
+    }
+
+    public void enableMultiQueries() throws SQLException {
+    	Buffer buf = getSharedSendPacket();
+
+    	buf.clear();
+    	buf.writeByte((byte)MysqlDefs.COM_SET_OPTION);
+    	buf.writeInt(0);
+    	sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
+    }
+
+    public void disableMultiQueries() throws SQLException {
+    	Buffer buf = getSharedSendPacket();
+
+    	buf.clear();
+    	buf.writeByte((byte)MysqlDefs.COM_SET_OPTION);
+    	buf.writeInt(1);
+    	sendCommand(MysqlDefs.COM_SET_OPTION, null, buf, false, null);
+    }
+
+    private final void send(Buffer packet, int packetLen)
+        throws SQLException {
+        try {
+            if (packetLen > this.maxAllowedPacket) {
+                throw new PacketTooBigException(packetLen, this.maxAllowedPacket);
+            }
+
+			if (this.connection.getMaintainTimeStats()) {
+				this.lastPacketSentTimeMs = System.currentTimeMillis();
+			}
+
+            if ((this.serverMajorVersion >= 4) &&
+                    (packetLen >= this.maxThreeBytes)) {
+                sendSplitPackets(packet);
+            } else {
+                this.packetSequence++;
+
+                Buffer packetToSend = packet;
+
+                packetToSend.setPosition(0);
+
+                if (this.useCompression) {
+                    int originalPacketLen = packetLen;
+
+                    packetToSend = compressPacket(packet, 0, packetLen,
+                            HEADER_LENGTH);
+                    packetLen = packetToSend.getPosition();
+
+                    if (this.traceProtocol) {
+                        StringBuffer traceMessageBuf = new StringBuffer();
+
+                        traceMessageBuf.append(Messages.getString("MysqlIO.57")); //$NON-NLS-1$
+                        traceMessageBuf.append(getPacketDumpToLog(
+                                packetToSend, packetLen));
+                        traceMessageBuf.append(Messages.getString("MysqlIO.58")); //$NON-NLS-1$
+                        traceMessageBuf.append(getPacketDumpToLog(packet,
+                                originalPacketLen));
+
+                        this.connection.getLog().logTrace(traceMessageBuf.toString());
+                    }
+                } else {
+                    packetToSend.writeLongInt(packetLen - HEADER_LENGTH);
+                    packetToSend.writeByte(this.packetSequence);
+
+                    if (this.traceProtocol) {
+                        StringBuffer traceMessageBuf = new StringBuffer();
+
+                        traceMessageBuf.append(Messages.getString("MysqlIO.59")); //$NON-NLS-1$
+                        traceMessageBuf.append(packetToSend.dump(packetLen));
+
+                        this.connection.getLog().logTrace(traceMessageBuf.toString());
+                    }
+                }
+
+
+                this.mysqlOutput.write(packetToSend.getByteBuffer(), 0,
+                		packetLen);
+                this.mysqlOutput.flush();
+            }
+
+            if (this.enablePacketDebug) {
+                enqueuePacketForDebugging(true, false, packetLen + 5,
+                    this.packetHeaderBuf, packet);
+            }
+
+            //
+            // Don't hold on to large packets
+            //
+            if (packet == this.sharedSendPacket) {
+                reclaimLargeSharedSendPacket();
+            }
+        } catch (IOException ioEx) {
+            throw SQLError.createCommunicationsException(this.connection,
+                this.lastPacketSentTimeMs, ioEx);
+        }
+    }
+
+    /**
+     * Reads and sends a file to the server for LOAD DATA LOCAL INFILE
+     *
+     * @param callingStatement DOCUMENT ME!
+     * @param fileName the file name to send.
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws SQLException DOCUMENT ME!
+     */
+    private final ResultSetImpl sendFileToServer(StatementImpl callingStatement,
+        String fileName) throws SQLException {
+
+        Buffer filePacket = (this.loadFileBufRef == null) ? null
+                                                          : (Buffer) (this.loadFileBufRef.get());
+
+        int bigPacketLength = Math.min(this.connection.getMaxAllowedPacket() -
+                (HEADER_LENGTH * 3),
+                alignPacketSize(this.connection.getMaxAllowedPacket() - 16, 4096) -
+                (HEADER_LENGTH * 3));
+
+        int oneMeg = 1024 * 1024;
+
+        int smallerPacketSizeAligned = Math.min(oneMeg - (HEADER_LENGTH * 3),
+        		alignPacketSize(oneMeg - 16, 4096) - (HEADER_LENGTH * 3));
+
+        int packetLength = Math.min(smallerPacketSizeAligned, bigPacketLength);
+
+        if (filePacket == null) {
+        	try {
+        		filePacket = new Buffer((packetLength + HEADER_LENGTH));
+        		this.loadFileBufRef = new SoftReference(filePacket);
+        	} catch (OutOfMemoryError oom) {
+        		throw SQLError.createSQLException("Could not allocate packet of " + packetLength
+        				+ " bytes required for LOAD DATA LOCAL INFILE operation."
+						+ " Try increasing max heap allocation for JVM or decreasing server variable "
+						+ "'max_allowed_packet'", SQLError.SQL_STATE_MEMORY_ALLOCATION_FAILURE);
+
+        	}
+        }
+
+        filePacket.clear();
+        send(filePacket, 0);
+
+        byte[] fileBuf = new byte[packetLength];
+
+        BufferedInputStream fileIn = null;
+
+        try {
+        	if (!this.connection.getAllowLoadLocalInfile()) {
+        		throw SQLError.createSQLException(
+        				Messages.getString("MysqlIO.LoadDataLocalNotAllowed"),
+        				SQLError.SQL_STATE_GENERAL_ERROR);
+        	}
+
+        	InputStream hookedStream = null;
+
+        	if (callingStatement != null) {
+        	    hookedStream = callingStatement.getLocalInfileInputStream();
+        	}
+
+        	if (hookedStream != null) {
+        	    fileIn = new BufferedInputStream(hookedStream);
+        	} else if (!this.connection.getAllowUrlInLocalInfile()) {
+                fileIn = new BufferedInputStream(new FileInputStream(fileName));
+            } else {
+                // First look for ':'
+                if (fileName.indexOf(':') != -1) {
+                    try {
+                        URL urlFromFileName = new URL(fileName);
+                        fileIn = new BufferedInputStream(urlFromFileName.openStream());
+                    } catch (MalformedURLException badUrlEx) {
+                        // we fall back to trying this as a file input stream
+                        fileIn = new BufferedInputStream(new FileInputStream(
+                                    fileName));
+                    }
+                } else {
+                    fileIn = new BufferedInputStream(new FileInputStream(
+                                fileName));
+                }
+            }
+
+            int bytesRead = 0;
+
+            while ((bytesRead = fileIn.read(fileBuf)) != -1) {
+                filePacket.clear();
+                filePacket.writeBytesNoNull(fileBuf, 0, bytesRead);
+                send(filePacket, filePacket.getPosition());
+            }
+        } catch (IOException ioEx) {
+            StringBuffer messageBuf = new StringBuffer(Messages.getString(
+                        "MysqlIO.60")); //$NON-NLS-1$
+
+            if (!this.connection.getParanoid()) {
+                messageBuf.append("'"); //$NON-NLS-1$
+
+                if (fileName != null) {
+                    messageBuf.append(fileName);
+                }
+
+                messageBuf.append("'"); //$NON-NLS-1$
+            }
+
+            messageBuf.append(Messages.getString("MysqlIO.63")); //$NON-NLS-1$
+
+            if (!this.connection.getParanoid()) {
+                messageBuf.append(Messages.getString("MysqlIO.64")); //$NON-NLS-1$
+                messageBuf.append(Util.stackTraceToString(ioEx));
+            }
+
+            throw SQLError.createSQLException(messageBuf.toString(),
+                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+        } finally {
+            if (fileIn != null) {
+                try {
+                    fileIn.close();
+                } catch (Exception ex) {
+                    SQLException sqlEx = SQLError.createSQLException(Messages.getString("MysqlIO.65"), //$NON-NLS-1$
+                        SQLError.SQL_STATE_GENERAL_ERROR);
+                    sqlEx.initCause(ex);
+                    
+                    throw sqlEx;
+                }
+
+                fileIn = null;
+            } else {
+                // file open failed, but server needs one packet
+                filePacket.clear();
+                send(filePacket, filePacket.getPosition());
+                checkErrorPacket(); // to clear response off of queue
+            }
+        }
+
+        // send empty packet to mark EOF
+        filePacket.clear();
+        send(filePacket, filePacket.getPosition());
+
+        Buffer resultPacket = checkErrorPacket();
+
+        return buildResultSetWithUpdates(callingStatement, resultPacket);
+    }
+
+    /**
+     * Checks for errors in the reply packet, and if none, returns the reply
+     * packet, ready for reading
+     *
+     * @param command the command being issued (if used)
+     *
+     * @return DOCUMENT ME!
+     *
+     * @throws SQLException if an error packet was received
+     * @throws CommunicationsException DOCUMENT ME!
+     */
+    private Buffer checkErrorPacket(int command) throws SQLException {
+        int statusCode = 0;
+        Buffer resultPacket = null;
+        this.serverStatus = 0;
+
+        try {
+            // Check return value, if we get a java.io.EOFException,
+            // the server has gone away. We'll pass it on up the
+            // exception chain and let someone higher up decide
+            // what to do (barf, reconnect, etc).
+            resultPacket = reuseAndReadPacket(this.reusablePacket);
+        } catch (SQLException sqlEx) {
+            // Don't wrap SQL Exceptions
+            throw sqlEx;