?? serverpreparedstatement.java
字號:
/* Copyright (C) 2002-2004 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 com.mysql.jdbc.PreparedStatement.BatchParams;import com.mysql.jdbc.Statement.CancelTask;import com.mysql.jdbc.exceptions.MySQLTimeoutException;import com.mysql.jdbc.profiler.ProfileEventSink;import com.mysql.jdbc.profiler.ProfilerEvent;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.Reader;import java.io.UnsupportedEncodingException;import java.math.BigDecimal;import java.net.URL;import java.sql.Array;import java.sql.Blob;import java.sql.Clob;import java.sql.Date;import java.sql.ParameterMetaData;import java.sql.Ref;import java.sql.SQLException;import java.sql.Time;import java.sql.Timestamp;import java.sql.Types;import java.util.ArrayList;import java.util.BitSet;import java.util.Calendar;import java.util.Locale;import java.util.TimeZone;/** * JDBC Interface for MySQL-4.1 and newer server-side PreparedStatements. * * @author Mark Matthews * @version $Id: ServerPreparedStatement.java,v 1.1.2.2 2005/05/17 14:58:56 * mmatthews Exp $ */public class ServerPreparedStatement extends PreparedStatement { protected static final int BLOB_STREAM_READ_BUF_SIZE = 8192; static class BatchedBindValues { BindValue[] batchedParameterValues; BatchedBindValues(BindValue[] paramVals) { int numParams = paramVals.length; this.batchedParameterValues = new BindValue[numParams]; for (int i = 0; i < numParams; i++) { this.batchedParameterValues[i] = new BindValue(paramVals[i]); } } } static class BindValue { long boundBeforeExecutionNum = 0; long bindLength; /* Default length of data */ int bufferType; /* buffer type */ byte byteBinding; double doubleBinding; float floatBinding; int intBinding; boolean isLongData; /* long data indicator */ boolean isNull; /* NULL indicator */ boolean isSet = false; /* has this parameter been set? */ long longBinding; short shortBinding; Object value; /* The value to store */ BindValue() { } BindValue(BindValue copyMe) { this.value = copyMe.value; this.isSet = copyMe.isSet; this.isLongData = copyMe.isLongData; this.isNull = copyMe.isNull; this.bufferType = copyMe.bufferType; this.bindLength = copyMe.bindLength; this.byteBinding = copyMe.byteBinding; this.shortBinding = copyMe.shortBinding; this.intBinding = copyMe.intBinding; this.longBinding = copyMe.longBinding; this.floatBinding = copyMe.floatBinding; this.doubleBinding = copyMe.doubleBinding; } void reset() { this.isSet = false; this.value = null; this.isLongData = false; this.byteBinding = 0; this.shortBinding = 0; this.intBinding = 0; this.longBinding = 0L; this.floatBinding = 0; this.doubleBinding = 0D; } public String toString() { return toString(false); } public String toString(boolean quoteIfNeeded) { if (this.isLongData) { return "' STREAM DATA '"; } switch (this.bufferType) { case MysqlDefs.FIELD_TYPE_TINY: return String.valueOf(byteBinding); case MysqlDefs.FIELD_TYPE_SHORT: return String.valueOf(shortBinding); case MysqlDefs.FIELD_TYPE_LONG: return String.valueOf(intBinding); case MysqlDefs.FIELD_TYPE_LONGLONG: return String.valueOf(longBinding); case MysqlDefs.FIELD_TYPE_FLOAT: return String.valueOf(floatBinding); case MysqlDefs.FIELD_TYPE_DOUBLE: return String.valueOf(doubleBinding); case MysqlDefs.FIELD_TYPE_TIME: case MysqlDefs.FIELD_TYPE_DATE: case MysqlDefs.FIELD_TYPE_DATETIME: case MysqlDefs.FIELD_TYPE_TIMESTAMP: case MysqlDefs.FIELD_TYPE_VAR_STRING: case MysqlDefs.FIELD_TYPE_STRING: case MysqlDefs.FIELD_TYPE_VARCHAR: if (quoteIfNeeded) { return "'" + String.valueOf(value) + "'"; } else { return String.valueOf(value); } default: if (value instanceof byte[]) { return "byte data"; } else { if (quoteIfNeeded) { return "'" + String.valueOf(value) + "'"; } else { return String.valueOf(value); } } } } long getBoundLength() { if (isNull) { return 0; } if (isLongData) { return bindLength; } switch (bufferType) { case MysqlDefs.FIELD_TYPE_TINY: return 1; case MysqlDefs.FIELD_TYPE_SHORT: return 2; case MysqlDefs.FIELD_TYPE_LONG: return 4; case MysqlDefs.FIELD_TYPE_LONGLONG: return 8; case MysqlDefs.FIELD_TYPE_FLOAT: return 4; case MysqlDefs.FIELD_TYPE_DOUBLE: return 8; case MysqlDefs.FIELD_TYPE_TIME: return 9; case MysqlDefs.FIELD_TYPE_DATE: return 7; case MysqlDefs.FIELD_TYPE_DATETIME: case MysqlDefs.FIELD_TYPE_TIMESTAMP: return 11; 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: if (value instanceof byte[]) { return ((byte[]) value).length; } else { return ((String) value).length(); } default: return 0; } } } /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */ private static final byte MAX_DATE_REP_LENGTH = (byte) 5; /* * 1 (length) + 2 (year) + 1 (month) + 1 (day) + 1 (hour) + 1 (minute) + 1 * (second) + 4 (microseconds) */ private static final byte MAX_DATETIME_REP_LENGTH = 12; /* * 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) + 1 (minute) + 1 * (seconds) + 4 (microseconds) */ private static final byte MAX_TIME_REP_LENGTH = 13; private void storeTime(Buffer intoBuf, Time tm) throws SQLException { intoBuf.ensureCapacity(9); intoBuf.writeByte((byte) 8); // length intoBuf.writeByte((byte) 0); // neg flag intoBuf.writeLong(0); // tm->day, not used Calendar sessionCalendar = getCalendarInstanceForSessionOrNew(); synchronized (sessionCalendar) { java.util.Date oldTime = sessionCalendar.getTime(); try { sessionCalendar.setTime(tm); intoBuf.writeByte((byte) sessionCalendar.get(Calendar.HOUR_OF_DAY)); intoBuf.writeByte((byte) sessionCalendar.get(Calendar.MINUTE)); intoBuf.writeByte((byte) sessionCalendar.get(Calendar.SECOND)); // intoBuf.writeLongInt(0); // tm-second_part } finally { sessionCalendar.setTime(oldTime); } } } /** * Flag indicating whether or not the long parameters have been 'switched' * back to normal parameters. We can not execute() if clearParameters() * hasn't been called in this case. */ private boolean detectedLongParameterSwitch = false; /** * The number of fields in the result set (if any) for this * PreparedStatement. */ private int fieldCount; /** Has this prepared statement been marked invalid? */ private boolean invalid = false; /** If this statement has been marked invalid, what was the reason? */ private SQLException invalidationException; /** Does this query modify data? */ private boolean isSelectQuery; private Buffer outByteBuffer; /** Bind values for individual fields */ private BindValue[] parameterBindings; /** Field-level metadata for parameters */ private Field[] parameterFields; /** Field-level metadata for result sets. */ private Field[] resultFields; /** Do we need to send/resend types to the server? */ private boolean sendTypesToServer = false; /** The ID that the server uses to identify this PreparedStatement */ private long serverStatementId; /** The type used for string bindings, changes from version-to-version */ private int stringTypeCode = MysqlDefs.FIELD_TYPE_STRING; private boolean serverNeedsResetBeforeEachExecution; /** * Creates a new ServerPreparedStatement object. * * @param conn * the connection creating us. * @param sql * the SQL containing the statement to prepare. * @param catalog * the catalog in use when we were created. * * @throws SQLException * If an error occurs */ public ServerPreparedStatement(Connection conn, String sql, String catalog, int resultSetType, int resultSetConcurrency) throws SQLException { super(conn, catalog); checkNullOrEmptyQuery(sql); this.isSelectQuery = StringUtils.startsWithIgnoreCaseAndWs(sql, "SELECT"); //$NON-NLS-1$ if (this.connection.versionMeetsMinimum(5, 0, 0)) { this.serverNeedsResetBeforeEachExecution = !this.connection.versionMeetsMinimum(5, 0, 3); } else { this.serverNeedsResetBeforeEachExecution = !this.connection.versionMeetsMinimum(4, 1, 10); } this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23); this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$ this.firstCharOfStmt = StringUtils.firstNonWsCharUc(sql); this.originalSql = sql; if (this.connection.versionMeetsMinimum(4, 1, 2)) { this.stringTypeCode = MysqlDefs.FIELD_TYPE_VAR_STRING; } else { this.stringTypeCode = MysqlDefs.FIELD_TYPE_STRING; } try { serverPrepare(sql); } catch (SQLException sqlEx) { realClose(false, true); // don't wrap SQLExceptions throw sqlEx; } catch (Exception ex) { realClose(false, true); throw SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } setResultSetType(resultSetType); setResultSetConcurrency(resultSetConcurrency); } /** * JDBC 2.0 Add a set of parameters to the batch. * * @exception SQLException * if a database-access error occurs. * * @see Statement#addBatch */ public synchronized void addBatch() throws SQLException { checkClosed(); if (this.batchedArgs == null) { this.batchedArgs = new ArrayList(); } this.batchedArgs.add(new BatchedBindValues(this.parameterBindings)); } protected String asSql(boolean quoteStreamsAndUnknowns) throws SQLException { if (this.isClosed) { return "statement has been closed, no further internal information available"; } PreparedStatement pStmtForSub = null; try { pStmtForSub = new PreparedStatement(this.connection, this.originalSql, this.currentCatalog); int numParameters = pStmtForSub.parameterCount; int ourNumParameters = this.parameterCount; for (int i = 0; (i < numParameters) && (i < ourNumParameters); i++) { if (this.parameterBindings[i] != null) { if (this.parameterBindings[i].isNull) { pStmtForSub.setNull(i + 1, Types.NULL); } else { BindValue bindValue = this.parameterBindings[i]; // // Handle primitives first // switch (bindValue.bufferType) { case MysqlDefs.FIELD_TYPE_TINY: pStmtForSub.setByte(i + 1, bindValue.byteBinding); break; case MysqlDefs.FIELD_TYPE_SHORT: pStmtForSub.setShort(i + 1, bindValue.shortBinding); break; case MysqlDefs.FIELD_TYPE_LONG: pStmtForSub.setInt(i + 1, bindValue.intBinding); break; case MysqlDefs.FIELD_TYPE_LONGLONG: pStmtForSub.setLong(i + 1, bindValue.longBinding); break; case MysqlDefs.FIELD_TYPE_FLOAT: pStmtForSub.setFloat(i + 1, bindValue.floatBinding); break; case MysqlDefs.FIELD_TYPE_DOUBLE: pStmtForSub.setDouble(i + 1, bindValue.doubleBinding); break; default: pStmtForSub.setObject(i + 1, this.parameterBindings[i].value); break; } } } } return pStmtForSub.asSql(quoteStreamsAndUnknowns); } finally { if (pStmtForSub != null) { try { pStmtForSub.close(); } catch (SQLException sqlEx) { ; // ignore } } } } /* * (non-Javadoc) * * @see com.mysql.jdbc.Statement#checkClosed() */ protected void checkClosed() throws SQLException { if (this.invalid) { throw this.invalidationException; } super.checkClosed(); } /** * @see java.sql.PreparedStatement#clearParameters() */ public void clearParameters() throws SQLException {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -