📄 serverpreparedstatement.java
字号:
/* Copyright 2002-2007 MySQL AB, 2008 Sun Microsystems 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.IOException;import java.io.InputStream;import java.io.Reader;import java.io.UnsupportedEncodingException;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;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.ResultSet;import java.sql.SQLException;import java.sql.Time;import java.sql.Timestamp;import java.sql.Types;import java.util.ArrayList;import java.util.Calendar;import java.util.GregorianCalendar;import java.util.TimeZone;import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;import com.mysql.jdbc.exceptions.MySQLTimeoutException;import com.mysql.jdbc.profiler.ProfilerEvent;import com.mysql.jdbc.profiler.ProfilerEventHandlerFactory;/** * 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 { private static final Constructor JDBC_4_SPS_CTOR; static { if (Util.isJdbc4()) { try { JDBC_4_SPS_CTOR = Class.forName("com.mysql.jdbc.JDBC4ServerPreparedStatement") .getConstructor( new Class[] { ConnectionImpl.class, String.class, String.class, Integer.TYPE, Integer.TYPE}); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } else { JDBC_4_SPS_CTOR = null; } } 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]); } } } public static class BindValue { long boundBeforeExecutionNum = 0; public long bindLength; /* Default length of data */ int bufferType; /* buffer type */ byte byteBinding; double doubleBinding; float floatBinding; int intBinding; public boolean isLongData; /* long data indicator */ public boolean isNull; /* NULL indicator */ boolean isSet = false; /* has this parameter been set? */ long longBinding; short shortBinding; public 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 boolean hasOnDuplicateKeyUpdate = false; 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 prepared statement instance -- We need to provide factory-style * methods so we can support both JDBC3 (and older) and JDBC4 runtimes, * otherwise the class verifier complains when it tries to load JDBC4-only * interface classes that are present in JDBC4 method signatures. */ protected static ServerPreparedStatement getInstance(ConnectionImpl conn, String sql, String catalog, int resultSetType, int resultSetConcurrency) throws SQLException { if (!Util.isJdbc4()) { return new ServerPreparedStatement(conn, sql, catalog, resultSetType, resultSetConcurrency); } try { return (ServerPreparedStatement) JDBC_4_SPS_CTOR.newInstance(new Object[] { conn, sql, catalog, Constants.integerValueOf(resultSetType), Constants.integerValueOf(resultSetConcurrency) }); } catch (IllegalArgumentException e) { throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } catch (InstantiationException e) { throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } catch (IllegalAccessException e) { throw new SQLException(e.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } catch (InvocationTargetException e) { Throwable target = e.getTargetException(); if (target instanceof SQLException) { throw (SQLException)target; } throw new SQLException(target.toString(), SQLError.SQL_STATE_GENERAL_ERROR); } } /** * 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 */ protected ServerPreparedStatement(ConnectionImpl conn, String sql, String catalog, int resultSetType, int resultSetConcurrency) throws SQLException { super(conn, catalog); checkNullOrEmptyQuery(sql); this.hasOnDuplicateKeyUpdate = containsOnDuplicateKeyInString(sql); int startOfStatement = findStartOfStatement(sql); this.firstCharOfStmt = StringUtils.firstAlphaCharUc(sql, startOfStatement); this.isSelectQuery = 'S' == this.firstCharOfStmt; 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.useAutoSlowLog = this.connection.getAutoSlowLog(); this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23); this.hasLimitClause = (StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1); //$NON-NLS-1$ String statementComment = this.connection.getStatementComment(); this.originalSql = (statementComment == null) ? sql : "/* " + statementComment + " */ " + 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); SQLException sqlEx = SQLError.createSQLException(ex.toString(), SQLError.SQL_STATE_GENERAL_ERROR); sqlEx.initCause(ex); throw sqlEx; } setResultSetType(resultSetType); setResultSetConcurrency(resultSetConcurrency); this.parameterTypes = new int[this.parameterCount]; } /** * JDBC 2.0 Add a set of parameters to the batch. * * @exception SQLException * if a database-access error occurs. * * @see StatementImpl#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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -