?? mysqlio.java
字號:
/*
Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.Properties;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
/**
* This class is used by Connection for communicating with the MySQL server.
*
* @author Mark Matthews
* @version $Id: MysqlIO.java,v 1.32.2.46 2004/02/06 00:54:42 mmatthew Exp $
*
* @see java.sql.Connection
*/
public class MysqlIO {
static final int NULL_LENGTH = ~0;
static final int COMP_HEADER_LENGTH = 3;
static final int MIN_COMPRESS_LEN = 50;
static final int HEADER_LENGTH = 4;
private static int maxBufferSize = 65535;
private static final int CLIENT_COMPRESS = 32; /* Can use compression
protcol */
private static final int CLIENT_CONNECT_WITH_DB = 8;
private static final int CLIENT_FOUND_ROWS = 2;
private static final int CLIENT_IGNORE_SPACE = 256; /* Ignore spaces
before '(' */
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;
private static final int CLIENT_SSL = 2048;
private static final int CLIENT_RESERVED = 16384; // for 4.1.0 only
private static final int CLIENT_SECURE_CONNECTION = 32768;
private static final String FALSE_SCRAMBLE = "xxxxxxxx";
/**
* We store the platform 'encoding' here, only used to avoid munging
* filenames for LOAD DATA LOCAL INFILE...
*/
private static String jvmPlatformCharset = null;
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 {
outWriter.close();
} catch (IOException ioEx) {
// ignore
}
}
}
//
// 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 */
//private DataOutputStream _Mysql_Output = null;
private BufferedOutputStream mysqlOutput = null;
private com.mysql.jdbc.Connection connection;
private Deflater deflater = null;
private Inflater inflater = null;
/** Buffered data from the server */
//private BufferedInputStream _Mysql_Buf_Input = null;
/** Buffered data to the server */
//private BufferedOutputStream _Mysql_Buf_Output = null;
/** Data from the server */
//private DataInputStream _Mysql_Input = null;
private InputStream mysqlInput = null;
private RowData streamingData = null;
//
// For SQL Warnings
//
private SQLWarning warningChain = null;
/** The connection to the server */
private 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;
private String host = null;
private String seed;
private String serverVersion = null;
private String socketFactoryClassName = null;
private byte[] packetHeaderBuf = new byte[4];
private boolean clearStreamBeforeEachQuery = false;
private boolean colDecimalNeedsBump = false; // do we need to increment the colDecimal flag?
private boolean has41NewNewProt = false;
/** Does the server support long column info? */
private boolean hasLongColumnInfo = false;
private boolean isInteractiveClient = false;
/**
* Does the character set of this connection match the character set of the
* platform
*/
private boolean platformDbCharsetMatches = true;
private boolean profileSql = 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 protocolVersion = 0;
private int clientParam = 0;
// changed once we've connected.
private int maxAllowedPacket = 1024 * 1024;
private int maxThreeBytes = 255 * 255 * 255;
private int port = 3306;
private int serverMajorVersion = 0;
private int serverMinorVersion = 0;
private int serverSubMinorVersion = 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 socketFactoryClassName the socket factory to use
* @param props the Properties from DriverManager.getConnection()
* @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 java.sql.SQLException if a database access error occurs.
*/
protected MysqlIO(String host, int port, String socketFactoryClassName,
Properties props, com.mysql.jdbc.Connection conn, int socketTimeout)
throws IOException, java.sql.SQLException {
this.connection = conn;
this.reusablePacket = new Buffer(this.connection.getNetBufferLength());
this.port = port;
this.host = host;
this.socketFactoryClassName = socketFactoryClassName;
this.socketFactory = createSocketFactory();
this.mysqlConnection = socketFactory.connect(this.host, props);
this.clearStreamBeforeEachQuery = this.connection.alwaysClearStream();
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.isUsingUnbufferedInput()) {
this.mysqlInput = new BufferedInputStream(this.mysqlConnection
.getInputStream(), 16384);
} else {
this.mysqlInput = this.mysqlConnection.getInputStream();
}
this.mysqlOutput = new BufferedOutputStream(this.mysqlConnection
.getOutputStream(), 16384);
this.isInteractiveClient = this.connection.isInteractiveClient();
}
/**
* Should the driver generate SQL statement profiles?
*
* @param flag should the driver enable profiling?
*/
protected void setProfileSql(boolean flag) {
this.profileSql = flag;
}
/**
* Build a result set. Delegates to buildResultSetWithRows() to build a
* JDBC-version-specific ResultSet, given rows as byte data, and field
* information.
*
* @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 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
*
* @return a result set
*
* @throws Exception if a database access error occurs
*/
protected ResultSet getResultSet(long columnCount, int maxRows,
int resultSetType, boolean streamResults, String catalog)
throws Exception {
Buffer packet; // The packet from the server
Field[] fields = new Field[(int) columnCount];
// Read in the column information
for (int i = 0; i < columnCount; i++) {
packet = readPacket();
fields[i] = unpackField(packet, false);
}
packet = reuseAndReadPacket(this.reusablePacket);
RowData rowData = null;
if (!streamResults) {
ArrayList rows = new ArrayList();
// Now read the data
byte[][] rowBytes = nextRow((int) columnCount);
int rowCount = 0;
if (rowBytes != null) {
rows.add(rowBytes);
rowCount = 1;
}
while ((rowBytes != null) && (rowCount < maxRows)) {
rowBytes = nextRow((int) columnCount);
if (rowBytes != null) {
rows.add(rowBytes);
rowCount++;
} else {
if (Driver.TRACE) {
Debug.msg(this, "* NULL Row *");
}
}
}
//
// Clear any outstanding data left on the wire
// when we've artifically limited the number of
// rows we retrieve (fix for BUG#1695)
//
if (rowCount <= maxRows) {
clearInputStream();
}
if (Driver.TRACE) {
Debug.msg(this,
"* Fetched " + rows.size() + " rows from server *");
}
rowData = new RowDataStatic(rows);
reclaimLargeReusablePacket();
} else {
rowData = new RowDataDynamic(this, (int) columnCount);
this.streamingData = rowData;
}
return buildResultSetWithRows(catalog, fields, rowData, resultSetType);
}
/**
* 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;
}
}
/**
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -