?? preparedstatement.java
字號:
/* Copyright (C) 2002-2007 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. There are special exceptions to the terms and conditions of the GPL as it is applied to this software. View the full text of the exception in file EXCEPTIONS-CONNECTOR-J in the directory of this software distribution. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package com.mysql.jdbc;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.ObjectOutputStream;import java.io.Reader;import java.io.StringReader;import java.io.UnsupportedEncodingException;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.math.BigDecimal;import java.math.BigInteger;import java.net.URL;import java.sql.Array;import java.sql.BatchUpdateException;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.text.ParsePosition;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Calendar;import java.util.List;import java.util.Locale;import java.util.Properties;import java.util.TimeZone;import com.mysql.jdbc.StatementImpl.CancelTask;import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;import com.mysql.jdbc.exceptions.NotYetImplementedException;import com.mysql.jdbc.exceptions.MySQLTimeoutException;import com.mysql.jdbc.profiler.ProfilerEvent;/** * A SQL Statement is pre-compiled and stored in a PreparedStatement object. * This object can then be used to efficiently execute this statement multiple * times. * * <p> * <B>Note:</B> The setXXX methods for setting IN parameter values must specify * types that are compatible with the defined SQL type of the input parameter. * For instance, if the IN parameter has SQL type Integer, then setInt should be * used. * </p> * * <p> * If arbitrary parameter type conversions are required, then the setObject * method should be used with a target SQL type. * </p> * * @author Mark Matthews * @version $Id: PreparedStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews * Exp $ * * @see java.sql.ResultSet * @see java.sql.PreparedStatement */public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements java.sql.PreparedStatement { private static final Constructor JDBC_4_PSTMT_2_ARG_CTOR; private static final Constructor JDBC_4_PSTMT_3_ARG_CTOR; private static final Constructor JDBC_4_PSTMT_4_ARG_CTOR; static { if (Util.isJdbc4()) { try { JDBC_4_PSTMT_2_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4PreparedStatement") .getConstructor( new Class[] { ConnectionImpl.class, String.class }); JDBC_4_PSTMT_3_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4PreparedStatement") .getConstructor( new Class[] { ConnectionImpl.class, String.class, String.class }); JDBC_4_PSTMT_4_ARG_CTOR = Class.forName( "com.mysql.jdbc.JDBC4PreparedStatement") .getConstructor( new Class[] { ConnectionImpl.class, String.class, String.class, ParseInfo.class }); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } else { JDBC_4_PSTMT_2_ARG_CTOR = null; JDBC_4_PSTMT_3_ARG_CTOR = null; JDBC_4_PSTMT_4_ARG_CTOR = null; } } class BatchParams { boolean[] isNull = null; boolean[] isStream = null; InputStream[] parameterStreams = null; byte[][] parameterStrings = null; int[] streamLengths = null; BatchParams(byte[][] strings, InputStream[] streams, boolean[] isStreamFlags, int[] lengths, boolean[] isNullFlags) { // // Make copies // this.parameterStrings = new byte[strings.length][]; this.parameterStreams = new InputStream[streams.length]; this.isStream = new boolean[isStreamFlags.length]; this.streamLengths = new int[lengths.length]; this.isNull = new boolean[isNullFlags.length]; System.arraycopy(strings, 0, this.parameterStrings, 0, strings.length); System.arraycopy(streams, 0, this.parameterStreams, 0, streams.length); System.arraycopy(isStreamFlags, 0, this.isStream, 0, isStreamFlags.length); System.arraycopy(lengths, 0, this.streamLengths, 0, lengths.length); System .arraycopy(isNullFlags, 0, this.isNull, 0, isNullFlags.length); } } class EndPoint { int begin; int end; EndPoint(int b, int e) { this.begin = b; this.end = e; } } class ParseInfo { char firstStmtChar = 0; boolean foundLimitClause = false; boolean foundLoadData = false; long lastUsed = 0; int statementLength = 0; int statementStartPos = 0; byte[][] staticSql = null; /** * Represents the "parsed" state of a client-side * prepared statement, with the statement broken up into * it's static and dynamic (where parameters are bound) * parts. */ public ParseInfo(String sql, ConnectionImpl conn, java.sql.DatabaseMetaData dbmd, String encoding, SingleByteCharsetConverter converter) throws SQLException { try { if (sql == null) { throw SQLError.createSQLException(Messages .getString("PreparedStatement.61"), //$NON-NLS-1$ SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } this.lastUsed = System.currentTimeMillis(); String quotedIdentifierString = dbmd.getIdentifierQuoteString(); char quotedIdentifierChar = 0; if ((quotedIdentifierString != null) && !quotedIdentifierString.equals(" ") //$NON-NLS-1$ && (quotedIdentifierString.length() > 0)) { quotedIdentifierChar = quotedIdentifierString.charAt(0); } this.statementLength = sql.length(); ArrayList endpointList = new ArrayList(); boolean inQuotes = false; char quoteChar = 0; boolean inQuotedId = false; int lastParmEnd = 0; int i; int stopLookingForLimitClause = this.statementLength - 5; this.foundLimitClause = false; boolean noBackslashEscapes = connection.isNoBackslashEscapesSet(); // we're not trying to be real pedantic here, but we'd like to // skip comments at the beginning of statements, as frameworks // such as Hibernate use them to aid in debugging statementStartPos = findStartOfStatement(sql); for (i = statementStartPos; i < this.statementLength; ++i) { char c = sql.charAt(i); if ((this.firstStmtChar == 0) && Character.isLetter(c)) { // Determine what kind of statement we're doing (_S_elect, // _I_nsert, etc.) this.firstStmtChar = Character.toUpperCase(c); } if (!noBackslashEscapes && c == '\\' && i < (this.statementLength - 1)) { i++; continue; // next character is escaped } // are we in a quoted identifier? // (only valid when the id is not inside a 'string') if (!inQuotes && (quotedIdentifierChar != 0) && (c == quotedIdentifierChar)) { inQuotedId = !inQuotedId; } else if (!inQuotedId) { // only respect quotes when not in a quoted identifier if (inQuotes) { if (((c == '\'') || (c == '"')) && c == quoteChar) { if (i < (this.statementLength - 1) && sql.charAt(i + 1) == quoteChar) { i++; continue; // inline quote escape } inQuotes = !inQuotes; quoteChar = 0; } else if (((c == '\'') || (c == '"')) && c == quoteChar) { inQuotes = !inQuotes; quoteChar = 0; } } else { if (c == '#' || (c == '-' && (i + 1) < this.statementLength && sql .charAt(i + 1) == '-')) { // run out to end of statement, or newline, // whichever comes first int endOfStmt = this.statementLength - 1; for (; i < endOfStmt; i++) { c = sql.charAt(i); if (c == '\r' || c == '\n') { break; } } continue; } else if (c == '/' && (i + 1) < this.statementLength) { // Comment? char cNext = sql.charAt(i + 1); if (cNext == '*') { i+= 2; for (int j = i; j < this.statementLength; j++) { i++; cNext = sql.charAt(j); if (cNext == '*' && (j + 1) < this.statementLength) { if (sql.charAt(j + 1) == '/') { i++; if (i < this.statementLength) { c = sql.charAt(i); } break; // comment done } } } } } else if ((c == '\'') || (c == '"')) { inQuotes = true; quoteChar = c; } } } if ((c == '?') && !inQuotes && !inQuotedId) { endpointList.add(new int[] { lastParmEnd, i }); lastParmEnd = i + 1; } if (!inQuotes && (i < stopLookingForLimitClause)) { if ((c == 'L') || (c == 'l')) { char posI1 = sql.charAt(i + 1); if ((posI1 == 'I') || (posI1 == 'i')) { char posM = sql.charAt(i + 2); if ((posM == 'M') || (posM == 'm')) { char posI2 = sql.charAt(i + 3); if ((posI2 == 'I') || (posI2 == 'i')) { char posT = sql.charAt(i + 4); if ((posT == 'T') || (posT == 't')) { foundLimitClause = true; } } } } } } } if (this.firstStmtChar == 'L') { if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) { //$NON-NLS-1$ this.foundLoadData = true; } else { this.foundLoadData = false; } } else { this.foundLoadData = false; } endpointList.add(new int[] { lastParmEnd, this.statementLength }); this.staticSql = new byte[endpointList.size()][]; char[] asCharArray = sql.toCharArray(); for (i = 0; i < this.staticSql.length; i++) { int[] ep = (int[]) endpointList.get(i); int end = ep[1]; int begin = ep[0]; int len = end - begin; if (this.foundLoadData) { String temp = new String(asCharArray, begin, len); this.staticSql[i] = temp.getBytes(); } else if (encoding == null) { byte[] buf = new byte[len]; for (int j = 0; j < len; j++) { buf[j] = (byte) sql.charAt(begin + j); } this.staticSql[i] = buf; } else { if (converter != null) { this.staticSql[i] = StringUtils.getBytes(sql, converter, encoding, connection .getServerCharacterEncoding(), begin, len, connection.parserKnowsUnicode()); } else { String temp = new String(asCharArray, begin, len); this.staticSql[i] = StringUtils.getBytes(temp, encoding, connection .getServerCharacterEncoding(), connection.parserKnowsUnicode(), conn); } } } } catch (StringIndexOutOfBoundsException oobEx) { SQLException sqlEx = new SQLException("Parse error for " + sql); sqlEx.initCause(oobEx); throw sqlEx; } } } private final static byte[] HEX_DIGITS = new byte[] { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F' }; /** * Reads length bytes from reader into buf. Blocks until enough input is * available * * @param reader * DOCUMENT ME! * @param buf * DOCUMENT ME! * @param length * DOCUMENT ME! * * @return DOCUMENT ME! * * @throws IOException * DOCUMENT ME! */ protected static int readFully(Reader reader, char[] buf, int length) throws IOException { int numCharsRead = 0; while (numCharsRead < length) { int count = reader.read(buf, numCharsRead, length - numCharsRead); if (count < 0) { break; } numCharsRead += count; } return numCharsRead; } /** * Does the batch (if any) contain "plain" statements added by * Statement.addBatch(String)? * * If so, we can't re-write it to use multi-value or multi-queries. */ protected boolean batchHasPlainStatements = false; private java.sql.DatabaseMetaData dbmd = null; /** * What is the first character of the prepared statement (used to check for * SELECT vs. INSERT/UPDATE/DELETE) */ protected char firstCharOfStmt = 0; /** Does the SQL for this statement contain a 'limit' clause? */ protected boolean hasLimitClause = false; /** Is this query a LOAD DATA query? */ protected boolean isLoadDataQuery = false; private boolean[] isNull = null; private boolean[] isStream = null;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -