| Method from com.mysql.jdbc.MysqlIO Detail: |
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);
}
}
}
Re-authenticates as the given user and password |
protected Buffer checkErrorPacket() throws SQLException {
return checkErrorPacket(-1);
}
Checks for errors in the reply packet, and if none, returns the reply
packet, ready for reading |
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());
}
}
}
Determines if the database charset is the same as the platform charset |
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, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
}
}
|
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"), getExceptionInterceptor()); //$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"), getExceptionInterceptor()); //$NON-NLS-1$
}
this.streamingData = 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, 0);
}
|
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("ASCII", getExceptionInterceptor());
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, getExceptionInterceptor());
}
this.serverVersion = buf.readString("ASCII", getExceptionInterceptor());
// 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("ASCII", getExceptionInterceptor());
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();
checkTransactionState(0);
buf.setPosition(position + 16);
String seedPart2 = buf.readString("ASCII", getExceptionInterceptor());
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, getExceptionInterceptor());
}
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
if (!this.connection.getUseAffectedRows()) {
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, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
}
}
Initialize communications with the MySQL server. Handles logging on, and
handling initial connection errors. |
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());
}
}
|
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, 0);
}
|
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 {
}
}
Runs an 'EXPLAIN' on the given query and dumps the results to the log |
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, 0);
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 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;
}
}
Forcibly closes the underlying socket to MySQL. |
protected int getCommandCount() {
return this.commandCount;
}
|
protected long getCurrentTimeNanosOrMillis() {
if (this.useNanosForElapsedTime) {
return Util.getCurrentTimeNanosOrMillis();
}
return System.currentTimeMillis();
}
|
protected ExceptionInterceptor getExceptionInterceptor() {
return this.exceptionInterceptor;
}
|
String getHost() {
return this.host;
}
Returns the host this IO is connected to |
protected long getLastPacketReceivedTimeMs() {
return this.lastPacketReceivedTimeMs;
}
|
protected long getLastPacketSentTimeMs() {
return this.lastPacketSentTimeMs;
}
|
static int getMaxBuf() {
return maxBufferSize;
}
|
protected String getQueryTimingUnits() {
return this.queryTimingUnits;
}
|
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;
}
Build a result set. Delegates to buildResultSetWithRows() to build a
JDBC-version-specific ResultSet, given rows as byte data, and field
information. |
final int getServerMajorVersion() {
return this.serverMajorVersion;
}
Get the major version of the MySQL server we are talking to. |
final int getServerMinorVersion() {
return this.serverMinorVersion;
}
Get the minor version of the MySQL server we are talking to. |
protected int getServerStatus() {
return this.serverStatus;
}
|
final int getServerSubMinorVersion() {
return this.serverSubMinorVersion;
}
Get the sub-minor version of the MySQL server we are talking to. |
String getServerVersion() {
return this.serverVersion;
}
Get the version string of the server we are talking to |
Buffer getSharedSendPacket() {
if (this.sharedSendPacket == null) {
this.sharedSendPacket = new Buffer(INITIAL_PACKET_SIZE);
}
return this.sharedSendPacket;
}
Returns the packet used for sending data (used by PreparedStatement)
Guarded by external synchronization on a mutex. |
protected long getSlowQueryThreshold() {
return this.slowQueryThreshold;
}
|
protected long getThreadId() {
return this.threadId;
}
|
boolean hadWarnings() {
return this.hadWarnings;
}
|
public boolean hasLongColumnInfo() {
return this.hasLongColumnInfo;
}
Does the server send back extra column info? |
protected boolean inTransactionOnServer() {
return (this.serverStatus & SERVER_STATUS_IN_TRANS) != 0;
}
|
ResultSetInternalMethods invokeStatementInterceptorsPost(String sql,
Statement interceptedStatement,
ResultSetInternalMethods originalResultSet,
boolean forceExecute,
SQLException statementException) throws SQLException {
Iterator interceptors = this.statementInterceptors.iterator();
while (interceptors.hasNext()) {
StatementInterceptorV2 interceptor = ((StatementInterceptorV2) interceptors
.next());
boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
boolean shouldExecute = (executeTopLevelOnly && (this.statementExecutionDepth == 1 || forceExecute))
|| (!executeTopLevelOnly);
if (shouldExecute) {
String sqlToInterceptor = sql;
ResultSetInternalMethods interceptedResultSet = interceptor
.postProcess(sqlToInterceptor, interceptedStatement,
originalResultSet, this.connection, this.warningCount,
this.queryNoIndexUsed, this.queryBadIndexUsed, statementException);
if (interceptedResultSet != null) {
originalResultSet = interceptedResultSet;
}
}
}
return originalResultSet;
}
|
ResultSetInternalMethods invokeStatementInterceptorsPre(String sql,
Statement interceptedStatement,
boolean forceExecute) throws SQLException {
ResultSetInternalMethods previousResultSet = null;
Iterator interceptors = this.statementInterceptors.iterator();
while (interceptors.hasNext()) {
StatementInterceptorV2 interceptor = ((StatementInterceptorV2) interceptors
.next());
boolean executeTopLevelOnly = interceptor.executeTopLevelOnly();
boolean shouldExecute = (executeTopLevelOnly && (this.statementExecutionDepth == 1 || forceExecute))
|| (!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;
}
|
protected boolean isDataAvailable() throws SQLException {
try {
return this.mysqlInput.available() > 0;
} catch (IOException ioEx) {
throw SQLError.createCommunicationsException(this.connection,
this.lastPacketSentTimeMs, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
}
}
|
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;
}
|
boolean isVersion(int major,
int minor,
int subminor) {
return ((major == getServerMajorVersion()) &&
(minor == getServerMinorVersion()) &&
(subminor == getServerSubMinorVersion()));
}
Is the version of the MySQL server we are connected to the given
version? |
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, getExceptionInterceptor());
}
if (!canReuseRowPacketForBufferRow) {
this.reusablePacket = new Buffer(rowPacket.getBufLength());
}
return new BufferRow(rowPacket, fields, false, getExceptionInterceptor());
}
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, getExceptionInterceptor());
}
rowPacket.setPosition(rowPacket.getPosition() - 1);
readServerStatusForResultSets(rowPacket);
return null;
}
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. |
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.oldServerStatus = this.serverStatus;
this.serverStatus = (this.mysqlInput.read() & 0xff)
| ((this.mysqlInput.read() & 0xff) < < 8);
checkTransactionState(oldServerStatus);
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, this.lastPacketReceivedTimeMs,
new IOException(Messages.getString("MysqlIO.43")), getExceptionInterceptor());
}
remaining -= bytesRead;
}
}
if (remaining > 0) {
skipFully(this.mysqlInput, remaining);
}
return new ByteArrayRow(rowData, getExceptionInterceptor());
} catch (IOException ioEx) {
throw SQLError.createCommunicationsException(this.connection,
this.lastPacketSentTimeMs, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
}
}
|
final void quit() throws SQLException {
Buffer packet = new Buffer(6);
this.packetSequence = -1;
packet.writeByte((byte) MysqlDefs.QUIT);
send(packet, packet.getPosition());
forceClose();
}
Log-off of the MySQL server and close the socket. |
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;
}
|
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);
}
if (this.connection.getMaintainTimeStats()) {
this.lastPacketReceivedTimeMs = System.currentTimeMillis();
}
return packet;
} catch (IOException ioEx) {
throw SQLError.createCommunicationsException(this.connection,
this.lastPacketSentTimeMs, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
} catch (OutOfMemoryError oom) {
try {
this.connection.realClose(false, false, true, oom);
} finally {
throw oom;
}
}
}
Read one packet from the MySQL server |
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, getExceptionInterceptor())
: 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;
}
}
Reads one result set off of the wire, if the result is actually an
update count, creates an update-count only result set. |
void resetMaxBuf() {
this.maxAllowedPacket = this.connection.getMaxAllowedPacket();
}
Sets the buffer size to max-buf |
protected void resetReadPacketSequence() {
this.readPacketSequence = 0;
}
|
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);
}
}
|
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, this.connection));
} 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, getExceptionInterceptor());
} catch (UnsupportedEncodingException e) {
throw SQLError.createSQLException(Messages.getString("MysqlIO.95") //$NON-NLS-1$
+Messages.getString("MysqlIO.96"), //$NON-NLS-1$
SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
}
} 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();
}
}
Secure authentication for 4.1.1 and newer servers. |
final Buffer sendCommand(int command,
String extraData,
Buffer queryPacket,
boolean skipCheck,
String extraDataCharEncoding,
int timeoutMillis) 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.readPacketSequence = 0;
int oldTimeout = 0;
if (timeoutMillis != 0) {
try {
oldTimeout = this.mysqlConnection.getSoTimeout();
this.mysqlConnection.setSoTimeout(timeoutMillis);
} catch (SocketException e) {
throw SQLError.createCommunicationsException(this.connection, lastPacketSentTimeMs,
lastPacketReceivedTimeMs, e, getExceptionInterceptor());
}
}
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.oldServerStatus = this.serverStatus;
this.serverStatus = 0;
this.hadWarnings = false;
this.warningCount = 0;
this.queryNoIndexUsed = false;
this.queryBadIndexUsed = false;
this.serverQueryWasSlow = 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, this.lastPacketReceivedTimeMs, ex, getExceptionInterceptor());
}
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, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
} finally {
if (timeoutMillis != 0) {
try {
this.mysqlConnection.setSoTimeout(oldTimeout);
} catch (SocketException e) {
throw SQLError.createCommunicationsException(this.connection, lastPacketSentTimeMs,
lastPacketReceivedTimeMs, e, getExceptionInterceptor());
}
}
}
}
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. |
protected void setStatementInterceptors(List statementInterceptors) {
this.statementInterceptors = statementInterceptors;
}
|
protected boolean shouldIntercept() {
return this.statementInterceptors != null;
}
|
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, this.lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
} catch (OutOfMemoryError oom) {
try {
this.connection.realClose(false, false, true, oom);
} finally {
throw oom;
}
}
}
Reads and discards a single MySQL packet from the input stream. |
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, false);
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(), getExceptionInterceptor());
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();
}
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());
}
// Send query command and sql query string
Buffer resultPacket = sendCommand(MysqlDefs.QUERY, null, queryPacket,
false, null, 0);
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;
}
ResultSetInternalMethods rs = readAllResults(callingStatement, maxRows, resultSetType,
resultSetConcurrency, streamResults, catalog, resultPacket,
false, -1L, cachedMetadata);
if (queryWasSlow && !this.serverQueryWasSlow /* don't log slow queries twice */) {
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.serverQueryWasSlow) {
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.ServerSlowQuery") //$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, false, null);
if (interceptedResults != null) {
rs = interceptedResults;
}
}
return rs;
} catch (SQLException sqlEx) {
if (this.statementInterceptors != null) {
invokeStatementInterceptorsPost(
query, callingStatement, null, false, sqlEx); // we don't do anything with the result set in this case
}
if (callingStatement != null) {
synchronized (callingStatement.cancelTimeoutMutex) {
if (callingStatement.wasCancelled) {
SQLException cause = null;
if (callingStatement.wasCancelledByTimeout) {
cause = new MySQLTimeoutException();
} else {
cause = new MySQLStatementCancelledException();
}
callingStatement.resetCancelledState();
throw cause;
}
}
}
throw sqlEx;
} finally {
this.statementExecutionDepth--;
}
}
Send a query stored in a packet directly to the server. |
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;
}
|
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;
}
Unpacks the Field information from the given packet. Understands pre 4.1
and post 4.1 server version field packet structures. |
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;
}
|
protected boolean useNanosForElapsedTime() {
return this.useNanosForElapsedTime;
}
|
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;
}
Does the version of the MySQL server we are connected to meet the given
minimums? |