0001: /*
0002: Copyright (C) 2002-2007 MySQL AB
0003:
0004: This program is free software; you can redistribute it and/or modify
0005: it under the terms of version 2 of the GNU General Public License as
0006: published by the Free Software Foundation.
0007:
0008: There are special exceptions to the terms and conditions of the GPL
0009: as it is applied to this software. View the full text of the
0010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
0011: software distribution.
0012:
0013: This program is distributed in the hope that it will be useful,
0014: but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: GNU General Public License for more details.
0017:
0018: You should have received a copy of the GNU General Public License
0019: along with this program; if not, write to the Free Software
0020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0021:
0022:
0023:
0024: */
0025: package com.mysql.jdbc;
0026:
0027: import java.io.ByteArrayInputStream;
0028: import java.io.ByteArrayOutputStream;
0029: import java.io.IOException;
0030: import java.io.InputStream;
0031: import java.io.ObjectOutputStream;
0032: import java.io.Reader;
0033: import java.io.StringReader;
0034: import java.io.UnsupportedEncodingException;
0035: import java.lang.reflect.Constructor;
0036: import java.lang.reflect.InvocationTargetException;
0037: import java.math.BigDecimal;
0038: import java.math.BigInteger;
0039: import java.net.URL;
0040: import java.sql.Array;
0041: import java.sql.BatchUpdateException;
0042: import java.sql.Clob;
0043: import java.sql.Date;
0044: import java.sql.ParameterMetaData;
0045: import java.sql.Ref;
0046: import java.sql.ResultSet;
0047: import java.sql.SQLException;
0048: import java.sql.Time;
0049: import java.sql.Timestamp;
0050: import java.sql.Types;
0051: import java.text.ParsePosition;
0052: import java.text.SimpleDateFormat;
0053: import java.util.ArrayList;
0054: import java.util.Calendar;
0055: import java.util.List;
0056: import java.util.Locale;
0057: import java.util.Properties;
0058: import java.util.TimeZone;
0059:
0060: import com.mysql.jdbc.StatementImpl.CancelTask;
0061: import com.mysql.jdbc.exceptions.MySQLStatementCancelledException;
0062: import com.mysql.jdbc.exceptions.NotYetImplementedException;
0063: import com.mysql.jdbc.exceptions.MySQLTimeoutException;
0064: import com.mysql.jdbc.profiler.ProfilerEvent;
0065:
0066: /**
0067: * A SQL Statement is pre-compiled and stored in a PreparedStatement object.
0068: * This object can then be used to efficiently execute this statement multiple
0069: * times.
0070: *
0071: * <p>
0072: * <B>Note:</B> The setXXX methods for setting IN parameter values must specify
0073: * types that are compatible with the defined SQL type of the input parameter.
0074: * For instance, if the IN parameter has SQL type Integer, then setInt should be
0075: * used.
0076: * </p>
0077: *
0078: * <p>
0079: * If arbitrary parameter type conversions are required, then the setObject
0080: * method should be used with a target SQL type.
0081: * </p>
0082: *
0083: * @author Mark Matthews
0084: * @version $Id: PreparedStatement.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
0085: * Exp $
0086: *
0087: * @see java.sql.ResultSet
0088: * @see java.sql.PreparedStatement
0089: */
0090: public class PreparedStatement extends com.mysql.jdbc.StatementImpl
0091: implements java.sql.PreparedStatement {
0092: private static final Constructor JDBC_4_PSTMT_2_ARG_CTOR;
0093: private static final Constructor JDBC_4_PSTMT_3_ARG_CTOR;
0094: private static final Constructor JDBC_4_PSTMT_4_ARG_CTOR;
0095:
0096: static {
0097: if (Util.isJdbc4()) {
0098: try {
0099: JDBC_4_PSTMT_2_ARG_CTOR = Class.forName(
0100: "com.mysql.jdbc.JDBC4PreparedStatement")
0101: .getConstructor(
0102: new Class[] { ConnectionImpl.class,
0103: String.class });
0104: JDBC_4_PSTMT_3_ARG_CTOR = Class.forName(
0105: "com.mysql.jdbc.JDBC4PreparedStatement")
0106: .getConstructor(
0107: new Class[] { ConnectionImpl.class,
0108: String.class, String.class });
0109: JDBC_4_PSTMT_4_ARG_CTOR = Class.forName(
0110: "com.mysql.jdbc.JDBC4PreparedStatement")
0111: .getConstructor(
0112: new Class[] { ConnectionImpl.class,
0113: String.class, String.class,
0114: ParseInfo.class });
0115: } catch (SecurityException e) {
0116: throw new RuntimeException(e);
0117: } catch (NoSuchMethodException e) {
0118: throw new RuntimeException(e);
0119: } catch (ClassNotFoundException e) {
0120: throw new RuntimeException(e);
0121: }
0122: } else {
0123: JDBC_4_PSTMT_2_ARG_CTOR = null;
0124: JDBC_4_PSTMT_3_ARG_CTOR = null;
0125: JDBC_4_PSTMT_4_ARG_CTOR = null;
0126: }
0127: }
0128:
0129: class BatchParams {
0130: boolean[] isNull = null;
0131:
0132: boolean[] isStream = null;
0133:
0134: InputStream[] parameterStreams = null;
0135:
0136: byte[][] parameterStrings = null;
0137:
0138: int[] streamLengths = null;
0139:
0140: BatchParams(byte[][] strings, InputStream[] streams,
0141: boolean[] isStreamFlags, int[] lengths,
0142: boolean[] isNullFlags) {
0143: //
0144: // Make copies
0145: //
0146: this .parameterStrings = new byte[strings.length][];
0147: this .parameterStreams = new InputStream[streams.length];
0148: this .isStream = new boolean[isStreamFlags.length];
0149: this .streamLengths = new int[lengths.length];
0150: this .isNull = new boolean[isNullFlags.length];
0151: System.arraycopy(strings, 0, this .parameterStrings, 0,
0152: strings.length);
0153: System.arraycopy(streams, 0, this .parameterStreams, 0,
0154: streams.length);
0155: System.arraycopy(isStreamFlags, 0, this .isStream, 0,
0156: isStreamFlags.length);
0157: System.arraycopy(lengths, 0, this .streamLengths, 0,
0158: lengths.length);
0159: System.arraycopy(isNullFlags, 0, this .isNull, 0,
0160: isNullFlags.length);
0161: }
0162: }
0163:
0164: class EndPoint {
0165: int begin;
0166:
0167: int end;
0168:
0169: EndPoint(int b, int e) {
0170: this .begin = b;
0171: this .end = e;
0172: }
0173: }
0174:
0175: class ParseInfo {
0176: char firstStmtChar = 0;
0177:
0178: boolean foundLimitClause = false;
0179:
0180: boolean foundLoadData = false;
0181:
0182: long lastUsed = 0;
0183:
0184: int statementLength = 0;
0185:
0186: int statementStartPos = 0;
0187:
0188: byte[][] staticSql = null;
0189:
0190: /**
0191: * Represents the "parsed" state of a client-side
0192: * prepared statement, with the statement broken up into
0193: * it's static and dynamic (where parameters are bound)
0194: * parts.
0195: */
0196: public ParseInfo(String sql, ConnectionImpl conn,
0197: java.sql.DatabaseMetaData dbmd, String encoding,
0198: SingleByteCharsetConverter converter)
0199: throws SQLException {
0200: try {
0201: if (sql == null) {
0202: throw SQLError.createSQLException(Messages
0203: .getString("PreparedStatement.61"), //$NON-NLS-1$
0204: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
0205: }
0206:
0207: this .lastUsed = System.currentTimeMillis();
0208:
0209: String quotedIdentifierString = dbmd
0210: .getIdentifierQuoteString();
0211:
0212: char quotedIdentifierChar = 0;
0213:
0214: if ((quotedIdentifierString != null)
0215: && !quotedIdentifierString.equals(" ") //$NON-NLS-1$
0216: && (quotedIdentifierString.length() > 0)) {
0217: quotedIdentifierChar = quotedIdentifierString
0218: .charAt(0);
0219: }
0220:
0221: this .statementLength = sql.length();
0222:
0223: ArrayList endpointList = new ArrayList();
0224: boolean inQuotes = false;
0225: char quoteChar = 0;
0226: boolean inQuotedId = false;
0227: int lastParmEnd = 0;
0228: int i;
0229:
0230: int stopLookingForLimitClause = this .statementLength - 5;
0231:
0232: this .foundLimitClause = false;
0233:
0234: boolean noBackslashEscapes = connection
0235: .isNoBackslashEscapesSet();
0236:
0237: // we're not trying to be real pedantic here, but we'd like to
0238: // skip comments at the beginning of statements, as frameworks
0239: // such as Hibernate use them to aid in debugging
0240:
0241: statementStartPos = findStartOfStatement(sql);
0242:
0243: for (i = statementStartPos; i < this .statementLength; ++i) {
0244: char c = sql.charAt(i);
0245:
0246: if ((this .firstStmtChar == 0)
0247: && !Character.isWhitespace(c)) {
0248: // Determine what kind of statement we're doing (_S_elect,
0249: // _I_nsert, etc.)
0250: this .firstStmtChar = Character.toUpperCase(c);
0251: }
0252:
0253: if (!noBackslashEscapes && c == '\\'
0254: && i < (this .statementLength - 1)) {
0255: i++;
0256: continue; // next character is escaped
0257: }
0258:
0259: // are we in a quoted identifier?
0260: // (only valid when the id is not inside a 'string')
0261: if (!inQuotes && (quotedIdentifierChar != 0)
0262: && (c == quotedIdentifierChar)) {
0263: inQuotedId = !inQuotedId;
0264: } else if (!inQuotedId) {
0265: // only respect quotes when not in a quoted identifier
0266:
0267: if (inQuotes) {
0268: if (((c == '\'') || (c == '"'))
0269: && c == quoteChar) {
0270: if (i < (this .statementLength - 1)
0271: && sql.charAt(i + 1) == quoteChar) {
0272: i++;
0273: continue; // inline quote escape
0274: }
0275:
0276: inQuotes = !inQuotes;
0277: quoteChar = 0;
0278: } else if (((c == '\'') || (c == '"'))
0279: && c == quoteChar) {
0280: inQuotes = !inQuotes;
0281: quoteChar = 0;
0282: }
0283: } else {
0284: if (c == '#'
0285: || (c == '-'
0286: && (i + 1) < this .statementLength && sql
0287: .charAt(i + 1) == '-')) {
0288: // run out to end of statement, or newline,
0289: // whichever comes first
0290: int endOfStmt = this .statementLength - 1;
0291:
0292: for (; i < endOfStmt; i++) {
0293: c = sql.charAt(i);
0294:
0295: if (c == '\r' || c == '\n') {
0296: break;
0297: }
0298: }
0299:
0300: continue;
0301: } else if (c == '/'
0302: && (i + 1) < this .statementLength) {
0303: // Comment?
0304: char cNext = sql.charAt(i + 1);
0305:
0306: if (cNext == '*') {
0307: i += 2;
0308:
0309: for (int j = i; j < this .statementLength; j++) {
0310: i++;
0311: cNext = sql.charAt(j);
0312:
0313: if (cNext == '*'
0314: && (j + 1) < this .statementLength) {
0315: if (sql.charAt(j + 1) == '/') {
0316: i++;
0317:
0318: if (i < this .statementLength) {
0319: c = sql.charAt(i);
0320: }
0321:
0322: break; // comment done
0323: }
0324: }
0325: }
0326: }
0327: } else if ((c == '\'') || (c == '"')) {
0328: inQuotes = true;
0329: quoteChar = c;
0330: }
0331: }
0332: }
0333:
0334: if ((c == '?') && !inQuotes && !inQuotedId) {
0335: endpointList.add(new int[] { lastParmEnd, i });
0336: lastParmEnd = i + 1;
0337: }
0338:
0339: if (!inQuotes && (i < stopLookingForLimitClause)) {
0340: if ((c == 'L') || (c == 'l')) {
0341: char posI1 = sql.charAt(i + 1);
0342:
0343: if ((posI1 == 'I') || (posI1 == 'i')) {
0344: char posM = sql.charAt(i + 2);
0345:
0346: if ((posM == 'M') || (posM == 'm')) {
0347: char posI2 = sql.charAt(i + 3);
0348:
0349: if ((posI2 == 'I')
0350: || (posI2 == 'i')) {
0351: char posT = sql.charAt(i + 4);
0352:
0353: if ((posT == 'T')
0354: || (posT == 't')) {
0355: foundLimitClause = true;
0356: }
0357: }
0358: }
0359: }
0360: }
0361: }
0362: }
0363:
0364: if (this .firstStmtChar == 'L') {
0365: if (StringUtils.startsWithIgnoreCaseAndWs(sql,
0366: "LOAD DATA")) { //$NON-NLS-1$
0367: this .foundLoadData = true;
0368: } else {
0369: this .foundLoadData = false;
0370: }
0371: } else {
0372: this .foundLoadData = false;
0373: }
0374:
0375: endpointList.add(new int[] { lastParmEnd,
0376: this .statementLength });
0377: this .staticSql = new byte[endpointList.size()][];
0378: char[] asCharArray = sql.toCharArray();
0379:
0380: for (i = 0; i < this .staticSql.length; i++) {
0381: int[] ep = (int[]) endpointList.get(i);
0382: int end = ep[1];
0383: int begin = ep[0];
0384: int len = end - begin;
0385:
0386: if (this .foundLoadData) {
0387: String temp = new String(asCharArray, begin,
0388: len);
0389: this .staticSql[i] = temp.getBytes();
0390: } else if (encoding == null) {
0391: byte[] buf = new byte[len];
0392:
0393: for (int j = 0; j < len; j++) {
0394: buf[j] = (byte) sql.charAt(begin + j);
0395: }
0396:
0397: this .staticSql[i] = buf;
0398: } else {
0399: if (converter != null) {
0400: this .staticSql[i] = StringUtils
0401: .getBytes(
0402: sql,
0403: converter,
0404: encoding,
0405: connection
0406: .getServerCharacterEncoding(),
0407: begin,
0408: len,
0409: connection
0410: .parserKnowsUnicode());
0411: } else {
0412: String temp = new String(asCharArray,
0413: begin, len);
0414:
0415: this .staticSql[i] = StringUtils
0416: .getBytes(
0417: temp,
0418: encoding,
0419: connection
0420: .getServerCharacterEncoding(),
0421: connection
0422: .parserKnowsUnicode(),
0423: conn);
0424: }
0425: }
0426: }
0427: } catch (StringIndexOutOfBoundsException oobEx) {
0428: SQLException sqlEx = new SQLException(
0429: "Parse error for " + sql);
0430: sqlEx.initCause(oobEx);
0431:
0432: throw sqlEx;
0433: }
0434: }
0435: }
0436:
0437: private final static byte[] HEX_DIGITS = new byte[] { (byte) '0',
0438: (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
0439: (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A',
0440: (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F' };
0441:
0442: /**
0443: * Reads length bytes from reader into buf. Blocks until enough input is
0444: * available
0445: *
0446: * @param reader
0447: * DOCUMENT ME!
0448: * @param buf
0449: * DOCUMENT ME!
0450: * @param length
0451: * DOCUMENT ME!
0452: *
0453: * @return DOCUMENT ME!
0454: *
0455: * @throws IOException
0456: * DOCUMENT ME!
0457: */
0458: protected static int readFully(Reader reader, char[] buf, int length)
0459: throws IOException {
0460: int numCharsRead = 0;
0461:
0462: while (numCharsRead < length) {
0463: int count = reader.read(buf, numCharsRead, length
0464: - numCharsRead);
0465:
0466: if (count < 0) {
0467: break;
0468: }
0469:
0470: numCharsRead += count;
0471: }
0472:
0473: return numCharsRead;
0474: }
0475:
0476: /**
0477: * Does the batch (if any) contain "plain" statements added by
0478: * Statement.addBatch(String)?
0479: *
0480: * If so, we can't re-write it to use multi-value or multi-queries.
0481: */
0482: protected boolean batchHasPlainStatements = false;
0483:
0484: private java.sql.DatabaseMetaData dbmd = null;
0485:
0486: /**
0487: * What is the first character of the prepared statement (used to check for
0488: * SELECT vs. INSERT/UPDATE/DELETE)
0489: */
0490: protected char firstCharOfStmt = 0;
0491:
0492: /** Does the SQL for this statement contain a 'limit' clause? */
0493: protected boolean hasLimitClause = false;
0494:
0495: /** Is this query a LOAD DATA query? */
0496: protected boolean isLoadDataQuery = false;
0497:
0498: private boolean[] isNull = null;
0499:
0500: private boolean[] isStream = null;
0501:
0502: protected int numberOfExecutions = 0;
0503:
0504: /** The SQL that was passed in to 'prepare' */
0505: protected String originalSql = null;
0506:
0507: /** The number of parameters in this PreparedStatement */
0508: protected int parameterCount;
0509:
0510: protected MysqlParameterMetadata parameterMetaData;
0511:
0512: private InputStream[] parameterStreams = null;
0513:
0514: private byte[][] parameterValues = null;
0515:
0516: /**
0517: * Only used by statement interceptors at the moment to
0518: * provide introspection of bound values
0519: */
0520: protected int[] parameterTypes = null;
0521:
0522: private ParseInfo parseInfo;
0523:
0524: private java.sql.ResultSetMetaData pstmtResultMetaData;
0525:
0526: private byte[][] staticSqlStrings = null;
0527:
0528: private byte[] streamConvertBuf = new byte[4096];
0529:
0530: private int[] streamLengths = null;
0531:
0532: private SimpleDateFormat tsdf = null;
0533:
0534: /**
0535: * Are we using a version of MySQL where we can use 'true' boolean values?
0536: */
0537: protected boolean useTrueBoolean = false;
0538:
0539: protected boolean usingAnsiMode;
0540:
0541: protected String batchedValuesClause;
0542:
0543: /** Where does the statement text actually start? */
0544:
0545: private int statementAfterCommentsPos;
0546:
0547: /**
0548: * have we checked whether we can rewrite this statement as a multi-value
0549: * insert?
0550: */
0551:
0552: private boolean hasCheckedForRewrite = false;
0553:
0554: /** Can we actually rewrite this statement as a multi-value insert? */
0555:
0556: private boolean canRewrite = false;
0557:
0558: private boolean doPingInstead;
0559:
0560: /**
0561: * Creates a prepared statement instance -- We need to provide factory-style
0562: * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,
0563: * otherwise the class verifier complains when it tries to load JDBC4-only
0564: * interface classes that are present in JDBC4 method signatures.
0565: */
0566:
0567: protected static PreparedStatement getInstance(ConnectionImpl conn,
0568: String catalog) throws SQLException {
0569: if (!Util.isJdbc4()) {
0570: return new PreparedStatement(conn, catalog);
0571: }
0572:
0573: return (PreparedStatement) Util
0574: .handleNewInstance(JDBC_4_PSTMT_2_ARG_CTOR,
0575: new Object[] { conn, catalog });
0576: }
0577:
0578: /**
0579: * Creates a prepared statement instance -- We need to provide factory-style
0580: * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,
0581: * otherwise the class verifier complains when it tries to load JDBC4-only
0582: * interface classes that are present in JDBC4 method signatures.
0583: */
0584:
0585: protected static PreparedStatement getInstance(ConnectionImpl conn,
0586: String sql, String catalog) throws SQLException {
0587: if (!Util.isJdbc4()) {
0588: return new PreparedStatement(conn, sql, catalog);
0589: }
0590:
0591: return (PreparedStatement) Util.handleNewInstance(
0592: JDBC_4_PSTMT_3_ARG_CTOR, new Object[] { conn, sql,
0593: catalog });
0594: }
0595:
0596: /**
0597: * Creates a prepared statement instance -- We need to provide factory-style
0598: * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,
0599: * otherwise the class verifier complains when it tries to load JDBC4-only
0600: * interface classes that are present in JDBC4 method signatures.
0601: */
0602:
0603: protected static PreparedStatement getInstance(ConnectionImpl conn,
0604: String sql, String catalog, ParseInfo cachedParseInfo)
0605: throws SQLException {
0606: if (!Util.isJdbc4()) {
0607: return new PreparedStatement(conn, sql, catalog,
0608: cachedParseInfo);
0609: }
0610:
0611: return (PreparedStatement) Util.handleNewInstance(
0612: JDBC_4_PSTMT_4_ARG_CTOR, new Object[] { conn, sql,
0613: catalog, cachedParseInfo });
0614: }
0615:
0616: /**
0617: * Constructor used by server-side prepared statements
0618: *
0619: * @param conn
0620: * the connection that created us
0621: * @param catalog
0622: * the catalog in use when we were created
0623: *
0624: * @throws SQLException
0625: * if an error occurs
0626: */
0627: public PreparedStatement(ConnectionImpl conn, String catalog)
0628: throws SQLException {
0629: super (conn, catalog);
0630: }
0631:
0632: /**
0633: * Constructor for the PreparedStatement class.
0634: *
0635: * @param conn
0636: * the connection creating this statement
0637: * @param sql
0638: * the SQL for this statement
0639: * @param catalog
0640: * the catalog/database this statement should be issued against
0641: *
0642: * @throws SQLException
0643: * if a database error occurs.
0644: */
0645: public PreparedStatement(ConnectionImpl conn, String sql,
0646: String catalog) throws SQLException {
0647: super (conn, catalog);
0648:
0649: if (sql == null) {
0650: throw SQLError.createSQLException(Messages
0651: .getString("PreparedStatement.0"), //$NON-NLS-1$
0652: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
0653: }
0654:
0655: this .originalSql = sql;
0656:
0657: if (this .originalSql.startsWith(PING_MARKER)) {
0658: this .doPingInstead = true;
0659: } else {
0660: this .doPingInstead = false;
0661: }
0662:
0663: this .dbmd = this .connection.getMetaData();
0664:
0665: this .useTrueBoolean = this .connection.versionMeetsMinimum(3,
0666: 21, 23);
0667:
0668: this .parseInfo = new ParseInfo(sql, this .connection, this .dbmd,
0669: this .charEncoding, this .charConverter);
0670:
0671: initializeFromParseInfo();
0672: }
0673:
0674: /**
0675: * Creates a new PreparedStatement object.
0676: *
0677: * @param conn
0678: * the connection creating this statement
0679: * @param sql
0680: * the SQL for this statement
0681: * @param catalog
0682: * the catalog/database this statement should be issued against
0683: * @param cachedParseInfo
0684: * already created parseInfo.
0685: *
0686: * @throws SQLException
0687: * DOCUMENT ME!
0688: */
0689: public PreparedStatement(ConnectionImpl conn, String sql,
0690: String catalog, ParseInfo cachedParseInfo)
0691: throws SQLException {
0692: super (conn, catalog);
0693:
0694: if (sql == null) {
0695: throw SQLError.createSQLException(Messages
0696: .getString("PreparedStatement.1"), //$NON-NLS-1$
0697: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
0698: }
0699:
0700: this .originalSql = sql;
0701:
0702: this .dbmd = this .connection.getMetaData();
0703:
0704: this .useTrueBoolean = this .connection.versionMeetsMinimum(3,
0705: 21, 23);
0706:
0707: this .parseInfo = cachedParseInfo;
0708:
0709: this .usingAnsiMode = !this .connection
0710: .useAnsiQuotedIdentifiers();
0711:
0712: initializeFromParseInfo();
0713: }
0714:
0715: /**
0716: * JDBC 2.0 Add a set of parameters to the batch.
0717: *
0718: * @exception SQLException
0719: * if a database-access error occurs.
0720: *
0721: * @see StatementImpl#addBatch
0722: */
0723: public void addBatch() throws SQLException {
0724: if (this .batchedArgs == null) {
0725: this .batchedArgs = new ArrayList();
0726: }
0727:
0728: this .batchedArgs.add(new BatchParams(this .parameterValues,
0729: this .parameterStreams, this .isStream,
0730: this .streamLengths, this .isNull));
0731: }
0732:
0733: public synchronized void addBatch(String sql) throws SQLException {
0734: this .batchHasPlainStatements = true;
0735:
0736: super .addBatch(sql);
0737: }
0738:
0739: protected String asSql() throws SQLException {
0740: return asSql(false);
0741: }
0742:
0743: protected String asSql(boolean quoteStreamsAndUnknowns)
0744: throws SQLException {
0745: if (this .isClosed) {
0746: return "statement has been closed, no further internal information available";
0747: }
0748:
0749: StringBuffer buf = new StringBuffer();
0750:
0751: try {
0752: for (int i = 0; i < this .parameterCount; ++i) {
0753: if (this .charEncoding != null) {
0754: buf.append(new String(this .staticSqlStrings[i],
0755: this .charEncoding));
0756: } else {
0757: buf.append(new String(this .staticSqlStrings[i]));
0758: }
0759:
0760: if ((this .parameterValues[i] == null)
0761: && !this .isStream[i]) {
0762: if (quoteStreamsAndUnknowns) {
0763: buf.append("'");
0764: }
0765:
0766: buf.append("** NOT SPECIFIED **"); //$NON-NLS-1$
0767:
0768: if (quoteStreamsAndUnknowns) {
0769: buf.append("'");
0770: }
0771: } else if (this .isStream[i]) {
0772: if (quoteStreamsAndUnknowns) {
0773: buf.append("'");
0774: }
0775:
0776: buf.append("** STREAM DATA **"); //$NON-NLS-1$
0777:
0778: if (quoteStreamsAndUnknowns) {
0779: buf.append("'");
0780: }
0781: } else {
0782: if (this .charConverter != null) {
0783: buf.append(this .charConverter
0784: .toString(this .parameterValues[i]));
0785: } else {
0786: if (this .charEncoding != null) {
0787: buf.append(new String(
0788: this .parameterValues[i],
0789: this .charEncoding));
0790: } else {
0791: buf
0792: .append(StringUtils
0793: .toAsciiString(this .parameterValues[i]));
0794: }
0795: }
0796: }
0797: }
0798:
0799: if (this .charEncoding != null) {
0800: buf.append(new String(
0801: this .staticSqlStrings[this .parameterCount],
0802: this .charEncoding));
0803: } else {
0804: buf
0805: .append(StringUtils
0806: .toAsciiString(this .staticSqlStrings[this .parameterCount]));
0807: }
0808: } catch (UnsupportedEncodingException uue) {
0809: throw new RuntimeException(Messages
0810: .getString("PreparedStatement.32") //$NON-NLS-1$
0811: + this .charEncoding
0812: + Messages.getString("PreparedStatement.33")); //$NON-NLS-1$
0813: }
0814:
0815: return buf.toString();
0816: }
0817:
0818: public synchronized void clearBatch() throws SQLException {
0819: this .batchHasPlainStatements = false;
0820:
0821: super .clearBatch();
0822: }
0823:
0824: /**
0825: * In general, parameter values remain in force for repeated used of a
0826: * Statement. Setting a parameter value automatically clears its previous
0827: * value. However, in some cases, it is useful to immediately release the
0828: * resources used by the current parameter values; this can be done by
0829: * calling clearParameters
0830: *
0831: * @exception SQLException
0832: * if a database access error occurs
0833: */
0834: public synchronized void clearParameters() throws SQLException {
0835: checkClosed();
0836:
0837: for (int i = 0; i < this .parameterValues.length; i++) {
0838: this .parameterValues[i] = null;
0839: this .parameterStreams[i] = null;
0840: this .isStream[i] = false;
0841: this .isNull[i] = false;
0842: this .parameterTypes[i] = Types.NULL;
0843: }
0844: }
0845:
0846: /**
0847: * Closes this prepared statement and releases all resources.
0848: *
0849: * @throws SQLException
0850: * if database error occurs.
0851: */
0852: public synchronized void close() throws SQLException {
0853: realClose(true, true);
0854: }
0855:
0856: private final void escapeblockFast(byte[] buf, Buffer packet,
0857: int size) throws SQLException {
0858: int lastwritten = 0;
0859:
0860: for (int i = 0; i < size; i++) {
0861: byte b = buf[i];
0862:
0863: if (b == '\0') {
0864: // write stuff not yet written
0865: if (i > lastwritten) {
0866: packet.writeBytesNoNull(buf, lastwritten, i
0867: - lastwritten);
0868: }
0869:
0870: // write escape
0871: packet.writeByte((byte) '\\');
0872: packet.writeByte((byte) '0');
0873: lastwritten = i + 1;
0874: } else {
0875: if ((b == '\\') || (b == '\'')
0876: || (!this .usingAnsiMode && b == '"')) {
0877: // write stuff not yet written
0878: if (i > lastwritten) {
0879: packet.writeBytesNoNull(buf, lastwritten, i
0880: - lastwritten);
0881: }
0882:
0883: // write escape
0884: packet.writeByte((byte) '\\');
0885: lastwritten = i; // not i+1 as b wasn't written.
0886: }
0887: }
0888: }
0889:
0890: // write out remaining stuff from buffer
0891: if (lastwritten < size) {
0892: packet.writeBytesNoNull(buf, lastwritten, size
0893: - lastwritten);
0894: }
0895: }
0896:
0897: private final void escapeblockFast(byte[] buf,
0898: ByteArrayOutputStream bytesOut, int size) {
0899: int lastwritten = 0;
0900:
0901: for (int i = 0; i < size; i++) {
0902: byte b = buf[i];
0903:
0904: if (b == '\0') {
0905: // write stuff not yet written
0906: if (i > lastwritten) {
0907: bytesOut.write(buf, lastwritten, i - lastwritten);
0908: }
0909:
0910: // write escape
0911: bytesOut.write('\\');
0912: bytesOut.write('0');
0913: lastwritten = i + 1;
0914: } else {
0915: if ((b == '\\') || (b == '\'')
0916: || (!this .usingAnsiMode && b == '"')) {
0917: // write stuff not yet written
0918: if (i > lastwritten) {
0919: bytesOut.write(buf, lastwritten, i
0920: - lastwritten);
0921: }
0922:
0923: // write escape
0924: bytesOut.write('\\');
0925: lastwritten = i; // not i+1 as b wasn't written.
0926: }
0927: }
0928: }
0929:
0930: // write out remaining stuff from buffer
0931: if (lastwritten < size) {
0932: bytesOut.write(buf, lastwritten, size - lastwritten);
0933: }
0934: }
0935:
0936: /**
0937: * Some prepared statements return multiple results; the execute method
0938: * handles these complex statements as well as the simpler form of
0939: * statements handled by executeQuery and executeUpdate
0940: *
0941: * @return true if the next result is a ResultSet; false if it is an update
0942: * count or there are no more results
0943: *
0944: * @exception SQLException
0945: * if a database access error occurs
0946: */
0947: public boolean execute() throws SQLException {
0948: checkClosed();
0949:
0950: ConnectionImpl locallyScopedConn = this .connection;
0951:
0952: if (locallyScopedConn.isReadOnly()
0953: && (this .firstCharOfStmt != 'S')) {
0954: throw SQLError.createSQLException(Messages
0955: .getString("PreparedStatement.20") //$NON-NLS-1$
0956: + Messages.getString("PreparedStatement.21"), //$NON-NLS-1$
0957: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
0958: }
0959:
0960: ResultSetInternalMethods rs = null;
0961:
0962: CachedResultSetMetaData cachedMetadata = null;
0963:
0964: synchronized (locallyScopedConn.getMutex()) {
0965: boolean doStreaming = createStreamingResultSet();
0966:
0967: clearWarnings();
0968:
0969: // Adjust net_write_timeout to a higher value if we're
0970: // streaming result sets. More often than not, someone runs into
0971: // an issue where they blow net_write_timeout when using this
0972: // feature, and if they're willing to hold a result set open
0973: // for 30 seconds or more, one more round-trip isn't going to hurt
0974: //
0975: // This is reset by RowDataDynamic.close().
0976:
0977: if (doStreaming
0978: && this .connection
0979: .getNetTimeoutForStreamingResults() > 0) {
0980: executeSimpleNonQuery(
0981: locallyScopedConn,
0982: "SET net_write_timeout="
0983: + this .connection
0984: .getNetTimeoutForStreamingResults());
0985: }
0986:
0987: this .batchedGeneratedKeys = null;
0988:
0989: Buffer sendPacket = fillSendPacket();
0990:
0991: String oldCatalog = null;
0992:
0993: if (!locallyScopedConn.getCatalog().equals(
0994: this .currentCatalog)) {
0995: oldCatalog = locallyScopedConn.getCatalog();
0996: locallyScopedConn.setCatalog(this .currentCatalog);
0997: }
0998:
0999: //
1000: // Check if we have cached metadata for this query...
1001: //
1002: if (locallyScopedConn.getCacheResultSetMetadata()) {
1003: cachedMetadata = locallyScopedConn
1004: .getCachedMetaData(this .originalSql);
1005: }
1006:
1007: Field[] metadataFromCache = null;
1008:
1009: if (cachedMetadata != null) {
1010: metadataFromCache = cachedMetadata.fields;
1011: }
1012:
1013: boolean oldInfoMsgState = false;
1014:
1015: if (this .retrieveGeneratedKeys) {
1016: oldInfoMsgState = locallyScopedConn
1017: .isReadInfoMsgEnabled();
1018: locallyScopedConn.setReadInfoMsgEnabled(true);
1019: }
1020:
1021: // If there isn't a limit clause in the SQL
1022: // then limit the number of rows to return in
1023: // an efficient manner. Only do this if
1024: // setMaxRows() hasn't been used on any Statements
1025: // generated from the current Connection (saves
1026: // a query, and network traffic).
1027: //
1028: // Only apply max_rows to selects
1029: //
1030: if (locallyScopedConn.useMaxRows()) {
1031: int rowLimit = -1;
1032:
1033: if (this .firstCharOfStmt == 'S') {
1034: if (this .hasLimitClause) {
1035: rowLimit = this .maxRows;
1036: } else {
1037: if (this .maxRows <= 0) {
1038: executeSimpleNonQuery(locallyScopedConn,
1039: "SET OPTION SQL_SELECT_LIMIT=DEFAULT");
1040: } else {
1041: executeSimpleNonQuery(locallyScopedConn,
1042: "SET OPTION SQL_SELECT_LIMIT="
1043: + this .maxRows);
1044: }
1045: }
1046: } else {
1047: executeSimpleNonQuery(locallyScopedConn,
1048: "SET OPTION SQL_SELECT_LIMIT=DEFAULT");
1049: }
1050:
1051: // Finally, execute the query
1052: rs = executeInternal(rowLimit, sendPacket, doStreaming,
1053: (this .firstCharOfStmt == 'S'),
1054: metadataFromCache, false);
1055: } else {
1056: rs = executeInternal(-1, sendPacket, doStreaming,
1057: (this .firstCharOfStmt == 'S'),
1058: metadataFromCache, false);
1059: }
1060:
1061: if (cachedMetadata != null) {
1062: locallyScopedConn.initializeResultsMetadataFromCache(
1063: this .originalSql, cachedMetadata, this .results);
1064: } else {
1065: if (rs.reallyResult()
1066: && locallyScopedConn
1067: .getCacheResultSetMetadata()) {
1068: locallyScopedConn
1069: .initializeResultsMetadataFromCache(
1070: this .originalSql,
1071: null /* will be created */,
1072: this .results);
1073: }
1074: }
1075:
1076: if (this .retrieveGeneratedKeys) {
1077: locallyScopedConn
1078: .setReadInfoMsgEnabled(oldInfoMsgState);
1079: rs.setFirstCharOfQuery(this .firstCharOfStmt);
1080: }
1081:
1082: if (oldCatalog != null) {
1083: locallyScopedConn.setCatalog(oldCatalog);
1084: }
1085:
1086: if (rs != null) {
1087: this .lastInsertId = rs.getUpdateID();
1088:
1089: this .results = rs;
1090: }
1091: }
1092:
1093: return ((rs != null) && rs.reallyResult());
1094: }
1095:
1096: /**
1097: * JDBC 2.0 Submit a batch of commands to the database for execution. This
1098: * method is optional.
1099: *
1100: * @return an array of update counts containing one element for each command
1101: * in the batch. The array is ordered according to the order in
1102: * which commands were inserted into the batch
1103: *
1104: * @exception SQLException
1105: * if a database-access error occurs, or the driver does not
1106: * support batch statements
1107: * @throws java.sql.BatchUpdateException
1108: * DOCUMENT ME!
1109: */
1110: public int[] executeBatch() throws SQLException {
1111: checkClosed();
1112:
1113: if (this .connection.isReadOnly()) {
1114: throw new SQLException(Messages
1115: .getString("PreparedStatement.25") //$NON-NLS-1$
1116: + Messages.getString("PreparedStatement.26"), //$NON-NLS-1$
1117: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1118: }
1119:
1120: synchronized (this .connection.getMutex()) {
1121: if (this .batchedArgs == null
1122: || this .batchedArgs.size() == 0) {
1123: return new int[0];
1124: }
1125:
1126: // we timeout the entire batch, not individual statements
1127: int batchTimeout = this .timeoutInMillis;
1128: this .timeoutInMillis = 0;
1129:
1130: resetCancelledState();
1131:
1132: try {
1133: clearWarnings();
1134:
1135: if (!this .batchHasPlainStatements
1136: && this .connection
1137: .getRewriteBatchedStatements()) {
1138:
1139: if (canRewriteAsMultivalueInsertStatement()) {
1140: return executeBatchedInserts(batchTimeout);
1141: }
1142:
1143: if (this .connection.versionMeetsMinimum(4, 1, 0)
1144: && !this .batchHasPlainStatements
1145: && this .batchedArgs != null
1146: && this .batchedArgs.size() > 3 /* cost of option setting rt-wise */) {
1147: return executePreparedBatchAsMultiStatement(batchTimeout);
1148: }
1149: }
1150:
1151: return executeBatchSerially(batchTimeout);
1152: } finally {
1153: clearBatch();
1154: }
1155: }
1156: }
1157:
1158: public synchronized boolean canRewriteAsMultivalueInsertStatement() {
1159: if (!this .hasCheckedForRewrite) {
1160: // Needs to be INSERT, can't have INSERT ... SELECT or
1161: // INSERT ... ON DUPLICATE KEY UPDATE
1162: //
1163: // We're not smart enough to re-write to
1164: //
1165: // INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
1166: // ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
1167: //
1168: // (yet)
1169:
1170: this .canRewrite = StringUtils.startsWithIgnoreCaseAndWs(
1171: this .originalSql, "INSERT",
1172: this .statementAfterCommentsPos)
1173: && StringUtils.indexOfIgnoreCaseRespectMarker(
1174: this .statementAfterCommentsPos,
1175: this .originalSql, "SELECT", "\"'`", "\"'`",
1176: false) == -1
1177: && StringUtils.indexOfIgnoreCaseRespectMarker(
1178: this .statementAfterCommentsPos,
1179: this .originalSql, "UPDATE", "\"'`", "\"'`",
1180: false) == -1;
1181:
1182: this .hasCheckedForRewrite = true;
1183: }
1184:
1185: return this .canRewrite;
1186: }
1187:
1188: /**
1189: * Rewrites the already prepared statement into a multi-statement
1190: * query of 'statementsPerBatch' values and executes the entire batch
1191: * using this new statement.
1192: *
1193: * @return update counts in the same fashion as executeBatch()
1194: *
1195: * @throws SQLException
1196: */
1197:
1198: protected int[] executePreparedBatchAsMultiStatement(
1199: int batchTimeout) throws SQLException {
1200: synchronized (this .connection.getMutex()) {
1201: // This is kind of an abuse, but it gets the job done
1202: if (this .batchedValuesClause == null) {
1203: this .batchedValuesClause = this .originalSql + ";";
1204: }
1205:
1206: ConnectionImpl locallyScopedConn = this .connection;
1207:
1208: boolean multiQueriesEnabled = locallyScopedConn
1209: .getAllowMultiQueries();
1210: CancelTask timeoutTask = null;
1211:
1212: try {
1213: clearWarnings();
1214:
1215: int numBatchedArgs = this .batchedArgs.size();
1216:
1217: if (this .retrieveGeneratedKeys) {
1218: this .batchedGeneratedKeys = new ArrayList(
1219: numBatchedArgs);
1220: }
1221:
1222: int numValuesPerBatch = computeBatchSize(numBatchedArgs);
1223:
1224: if (numBatchedArgs < numValuesPerBatch) {
1225: numValuesPerBatch = numBatchedArgs;
1226: }
1227:
1228: java.sql.PreparedStatement batchedStatement = null;
1229:
1230: int batchedParamIndex = 1;
1231: int numberToExecuteAsMultiValue = 0;
1232: int batchCounter = 0;
1233: int updateCountCounter = 0;
1234: int[] updateCounts = new int[numBatchedArgs];
1235: SQLException sqlEx = null;
1236:
1237: try {
1238: if (!multiQueriesEnabled) {
1239: locallyScopedConn.getIO().enableMultiQueries();
1240: }
1241:
1242: if (this .retrieveGeneratedKeys) {
1243: batchedStatement = locallyScopedConn
1244: .prepareStatement(
1245: generateMultiStatementForBatch(numValuesPerBatch),
1246: RETURN_GENERATED_KEYS);
1247: } else {
1248: batchedStatement = locallyScopedConn
1249: .prepareStatement(generateMultiStatementForBatch(numValuesPerBatch));
1250: }
1251:
1252: if (locallyScopedConn.getEnableQueryTimeouts()
1253: && batchTimeout != 0
1254: && locallyScopedConn.versionMeetsMinimum(5,
1255: 0, 0)) {
1256: timeoutTask = new CancelTask(
1257: (StatementImpl) batchedStatement);
1258: ConnectionImpl.getCancelTimer().schedule(
1259: timeoutTask, batchTimeout);
1260: }
1261:
1262: if (numBatchedArgs < numValuesPerBatch) {
1263: numberToExecuteAsMultiValue = numBatchedArgs;
1264: } else {
1265: numberToExecuteAsMultiValue = numBatchedArgs
1266: / numValuesPerBatch;
1267: }
1268:
1269: int numberArgsToExecute = numberToExecuteAsMultiValue
1270: * numValuesPerBatch;
1271:
1272: for (int i = 0; i < numberArgsToExecute; i++) {
1273: if (i != 0 && i % numValuesPerBatch == 0) {
1274: try {
1275: batchedStatement.execute();
1276: } catch (SQLException ex) {
1277: sqlEx = handleExceptionForBatch(
1278: batchCounter,
1279: numValuesPerBatch,
1280: updateCounts, ex);
1281: }
1282:
1283: updateCountCounter = processMultiCountsAndKeys(
1284: (StatementImpl) batchedStatement,
1285: updateCountCounter, updateCounts);
1286:
1287: batchedStatement.clearParameters();
1288: batchedParamIndex = 1;
1289: }
1290:
1291: batchedParamIndex = setOneBatchedParameterSet(
1292: batchedStatement, batchedParamIndex,
1293: this .batchedArgs.get(batchCounter++));
1294: }
1295:
1296: try {
1297: batchedStatement.execute();
1298: } catch (SQLException ex) {
1299: sqlEx = handleExceptionForBatch(
1300: batchCounter - 1, numValuesPerBatch,
1301: updateCounts, ex);
1302: }
1303:
1304: updateCountCounter = processMultiCountsAndKeys(
1305: (StatementImpl) batchedStatement,
1306: updateCountCounter, updateCounts);
1307:
1308: batchedStatement.clearParameters();
1309:
1310: numValuesPerBatch = numBatchedArgs - batchCounter;
1311: } finally {
1312: if (batchedStatement != null) {
1313: batchedStatement.close();
1314: }
1315: }
1316:
1317: try {
1318: if (numValuesPerBatch > 0) {
1319:
1320: if (this .retrieveGeneratedKeys) {
1321: batchedStatement = locallyScopedConn
1322: .prepareStatement(
1323: generateMultiStatementForBatch(numValuesPerBatch),
1324: RETURN_GENERATED_KEYS);
1325: } else {
1326: batchedStatement = locallyScopedConn
1327: .prepareStatement(generateMultiStatementForBatch(numValuesPerBatch));
1328: }
1329:
1330: if (timeoutTask != null) {
1331: timeoutTask.toCancel = (StatementImpl) batchedStatement;
1332: }
1333:
1334: batchedParamIndex = 1;
1335:
1336: while (batchCounter < numBatchedArgs) {
1337: batchedParamIndex = setOneBatchedParameterSet(
1338: batchedStatement,
1339: batchedParamIndex, this .batchedArgs
1340: .get(batchCounter++));
1341: }
1342:
1343: try {
1344: batchedStatement.execute();
1345: } catch (SQLException ex) {
1346: sqlEx = handleExceptionForBatch(
1347: batchCounter - 1,
1348: numValuesPerBatch, updateCounts, ex);
1349: }
1350:
1351: updateCountCounter = processMultiCountsAndKeys(
1352: (StatementImpl) batchedStatement,
1353: updateCountCounter, updateCounts);
1354:
1355: batchedStatement.clearParameters();
1356: }
1357:
1358: if (timeoutTask != null) {
1359: if (timeoutTask.caughtWhileCancelling != null) {
1360: throw timeoutTask.caughtWhileCancelling;
1361: }
1362:
1363: timeoutTask.cancel();
1364: timeoutTask = null;
1365: }
1366:
1367: if (sqlEx != null) {
1368: throw new java.sql.BatchUpdateException(sqlEx
1369: .getMessage(), sqlEx.getSQLState(),
1370: sqlEx.getErrorCode(), updateCounts);
1371: }
1372:
1373: return updateCounts;
1374: } finally {
1375: if (batchedStatement != null) {
1376: batchedStatement.close();
1377: }
1378: }
1379: } finally {
1380: if (timeoutTask != null) {
1381: timeoutTask.cancel();
1382: }
1383:
1384: resetCancelledState();
1385:
1386: if (!multiQueriesEnabled) {
1387: locallyScopedConn.getIO().disableMultiQueries();
1388: }
1389:
1390: clearBatch();
1391: }
1392: }
1393: }
1394:
1395: private String generateMultiStatementForBatch(int numBatches) {
1396: StringBuffer newStatementSql = new StringBuffer(
1397: (this .originalSql.length() + 1) * numBatches);
1398:
1399: newStatementSql.append(this .originalSql);
1400:
1401: for (int i = 0; i < numBatches - 1; i++) {
1402: newStatementSql.append(';');
1403: newStatementSql.append(this .originalSql);
1404: }
1405:
1406: return newStatementSql.toString();
1407: }
1408:
1409: /**
1410: * Rewrites the already prepared statement into a multi-value insert
1411: * statement of 'statementsPerBatch' values and executes the entire batch
1412: * using this new statement.
1413: *
1414: * @return update counts in the same fashion as executeBatch()
1415: *
1416: * @throws SQLException
1417: */
1418: protected int[] executeBatchedInserts(int batchTimeout)
1419: throws SQLException {
1420: String valuesClause = extractValuesClause();
1421:
1422: Connection locallyScopedConn = this .connection;
1423:
1424: if (valuesClause == null) {
1425: return executeBatchSerially(batchTimeout);
1426: }
1427:
1428: int numBatchedArgs = this .batchedArgs.size();
1429:
1430: if (this .retrieveGeneratedKeys) {
1431: this .batchedGeneratedKeys = new ArrayList(numBatchedArgs);
1432: }
1433:
1434: int numValuesPerBatch = computeBatchSize(numBatchedArgs);
1435:
1436: if (numBatchedArgs < numValuesPerBatch) {
1437: numValuesPerBatch = numBatchedArgs;
1438: }
1439:
1440: java.sql.PreparedStatement batchedStatement = null;
1441:
1442: int batchedParamIndex = 1;
1443: int updateCountRunningTotal = 0;
1444: int numberToExecuteAsMultiValue = 0;
1445: int batchCounter = 0;
1446: CancelTask timeoutTask = null;
1447: SQLException sqlEx = null;
1448:
1449: int[] updateCounts = new int[numBatchedArgs];
1450:
1451: for (int i = 0; i < this .batchedArgs.size(); i++) {
1452: updateCounts[i] = 1;
1453: }
1454:
1455: try {
1456: try {
1457: if (this .retrieveGeneratedKeys) {
1458: batchedStatement = locallyScopedConn
1459: .prepareStatement(generateBatchedInsertSQL(
1460: valuesClause, numValuesPerBatch),
1461: RETURN_GENERATED_KEYS);
1462: } else {
1463: batchedStatement = locallyScopedConn
1464: .prepareStatement(generateBatchedInsertSQL(
1465: valuesClause, numValuesPerBatch));
1466: }
1467:
1468: if (this .connection.getEnableQueryTimeouts()
1469: && batchTimeout != 0
1470: && this .connection.versionMeetsMinimum(5, 0, 0)) {
1471: timeoutTask = new CancelTask(
1472: (StatementImpl) batchedStatement);
1473: ConnectionImpl.getCancelTimer().schedule(
1474: timeoutTask, batchTimeout);
1475: }
1476:
1477: if (numBatchedArgs < numValuesPerBatch) {
1478: numberToExecuteAsMultiValue = numBatchedArgs;
1479: } else {
1480: numberToExecuteAsMultiValue = numBatchedArgs
1481: / numValuesPerBatch;
1482: }
1483:
1484: int numberArgsToExecute = numberToExecuteAsMultiValue
1485: * numValuesPerBatch;
1486:
1487: for (int i = 0; i < numberArgsToExecute; i++) {
1488: if (i != 0 && i % numValuesPerBatch == 0) {
1489: try {
1490: updateCountRunningTotal += batchedStatement
1491: .executeUpdate();
1492: } catch (SQLException ex) {
1493: sqlEx = handleExceptionForBatch(
1494: batchCounter - 1,
1495: numValuesPerBatch, updateCounts, ex);
1496: }
1497:
1498: getBatchedGeneratedKeys(batchedStatement);
1499: batchedStatement.clearParameters();
1500: batchedParamIndex = 1;
1501:
1502: }
1503:
1504: batchedParamIndex = setOneBatchedParameterSet(
1505: batchedStatement, batchedParamIndex,
1506: this .batchedArgs.get(batchCounter++));
1507: }
1508:
1509: try {
1510: updateCountRunningTotal += batchedStatement
1511: .executeUpdate();
1512: } catch (SQLException ex) {
1513: sqlEx = handleExceptionForBatch(batchCounter - 1,
1514: numValuesPerBatch, updateCounts, ex);
1515: }
1516:
1517: getBatchedGeneratedKeys(batchedStatement);
1518:
1519: numValuesPerBatch = numBatchedArgs - batchCounter;
1520: } finally {
1521: if (batchedStatement != null) {
1522: batchedStatement.close();
1523: }
1524: }
1525:
1526: try {
1527: if (numValuesPerBatch > 0) {
1528:
1529: if (this .retrieveGeneratedKeys) {
1530: batchedStatement = locallyScopedConn
1531: .prepareStatement(
1532: generateBatchedInsertSQL(
1533: valuesClause,
1534: numValuesPerBatch),
1535: RETURN_GENERATED_KEYS);
1536: } else {
1537: batchedStatement = locallyScopedConn
1538: .prepareStatement(generateBatchedInsertSQL(
1539: valuesClause, numValuesPerBatch));
1540: }
1541:
1542: if (timeoutTask != null) {
1543: timeoutTask.toCancel = (StatementImpl) batchedStatement;
1544: }
1545:
1546: batchedParamIndex = 1;
1547:
1548: while (batchCounter < numBatchedArgs) {
1549: batchedParamIndex = setOneBatchedParameterSet(
1550: batchedStatement, batchedParamIndex,
1551: this .batchedArgs.get(batchCounter++));
1552: }
1553:
1554: try {
1555: updateCountRunningTotal += batchedStatement
1556: .executeUpdate();
1557: } catch (SQLException ex) {
1558: sqlEx = handleExceptionForBatch(
1559: batchCounter - 1, numValuesPerBatch,
1560: updateCounts, ex);
1561: }
1562:
1563: getBatchedGeneratedKeys(batchedStatement);
1564: }
1565:
1566: if (sqlEx != null) {
1567: throw new java.sql.BatchUpdateException(sqlEx
1568: .getMessage(), sqlEx.getSQLState(), sqlEx
1569: .getErrorCode(), updateCounts);
1570: }
1571:
1572: return updateCounts;
1573: } finally {
1574: if (batchedStatement != null) {
1575: batchedStatement.close();
1576: }
1577: }
1578: } finally {
1579: if (timeoutTask != null) {
1580: timeoutTask.cancel();
1581: }
1582:
1583: resetCancelledState();
1584: }
1585: }
1586:
1587: /**
1588: * Computes the optimum number of batched parameter lists to send
1589: * without overflowing max_allowed_packet.
1590: *
1591: * @param numBatchedArgs
1592: * @return
1593: */
1594: protected int computeBatchSize(int numBatchedArgs) {
1595: long[] combinedValues = computeMaxParameterSetSizeAndBatchSize(numBatchedArgs);
1596:
1597: long maxSizeOfParameterSet = combinedValues[0];
1598: long sizeOfEntireBatch = combinedValues[1];
1599:
1600: int maxAllowedPacket = this .connection.getMaxAllowedPacket();
1601:
1602: if (sizeOfEntireBatch < maxAllowedPacket
1603: - this .originalSql.length()) {
1604: return numBatchedArgs;
1605: }
1606:
1607: return (int) Math.max(1, (maxAllowedPacket - this .originalSql
1608: .length())
1609: / maxSizeOfParameterSet);
1610: }
1611:
1612: /**
1613: * Computes the maximum parameter set size, and entire batch size given
1614: * the number of arguments in the batch.
1615: */
1616: protected long[] computeMaxParameterSetSizeAndBatchSize(
1617: int numBatchedArgs) {
1618: long sizeOfEntireBatch = 0;
1619: long maxSizeOfParameterSet = 0;
1620:
1621: for (int i = 0; i < numBatchedArgs; i++) {
1622: BatchParams paramArg = (BatchParams) this .batchedArgs
1623: .get(i);
1624:
1625: boolean[] isNullBatch = paramArg.isNull;
1626: boolean[] isStreamBatch = paramArg.isStream;
1627:
1628: long sizeOfParameterSet = 0;
1629:
1630: for (int j = 0; j < isNullBatch.length; j++) {
1631: if (!isNullBatch[j]) {
1632:
1633: if (isStreamBatch[j]) {
1634: int streamLength = paramArg.streamLengths[j];
1635:
1636: if (streamLength != -1) {
1637: sizeOfParameterSet += streamLength * 2; // for safety in escaping
1638: } else {
1639: int paramLength = paramArg.parameterStrings[j].length;
1640: sizeOfParameterSet += paramLength;
1641: }
1642: } else {
1643: sizeOfParameterSet += paramArg.parameterStrings[j].length;
1644: }
1645: } else {
1646: sizeOfParameterSet += 4; // for NULL literal in SQL
1647: }
1648: }
1649:
1650: //
1651: // Account for static part of values clause
1652: // This is a little naiive, because the ?s will be replaced
1653: // but it gives us some padding, and is less housekeeping
1654: // to ignore them. We're looking for a "fuzzy" value here
1655: // anyway
1656: //
1657:
1658: if (this .batchedValuesClause != null) {
1659: sizeOfParameterSet += this .batchedValuesClause.length() + 1;
1660: }
1661:
1662: sizeOfEntireBatch += sizeOfParameterSet;
1663:
1664: if (sizeOfParameterSet > maxSizeOfParameterSet) {
1665: maxSizeOfParameterSet = sizeOfParameterSet;
1666: }
1667: }
1668:
1669: return new long[] { maxSizeOfParameterSet, sizeOfEntireBatch };
1670: }
1671:
1672: /**
1673: * Executes the current batch of statements by executing them one-by-one.
1674: *
1675: * @return a list of update counts
1676: * @throws SQLException
1677: * if an error occurs
1678: */
1679: protected int[] executeBatchSerially(int batchTimeout)
1680: throws SQLException {
1681:
1682: Connection locallyScopedConn = this .connection;
1683:
1684: if (locallyScopedConn == null) {
1685: checkClosed();
1686: }
1687:
1688: int[] updateCounts = null;
1689:
1690: if (this .batchedArgs != null) {
1691: int nbrCommands = this .batchedArgs.size();
1692: updateCounts = new int[nbrCommands];
1693:
1694: for (int i = 0; i < nbrCommands; i++) {
1695: updateCounts[i] = -3;
1696: }
1697:
1698: SQLException sqlEx = null;
1699:
1700: int commandIndex = 0;
1701:
1702: CancelTask timeoutTask = null;
1703:
1704: try {
1705: if (this .connection.getEnableQueryTimeouts()
1706: && batchTimeout != 0
1707: && this .connection.versionMeetsMinimum(5, 0, 0)) {
1708: timeoutTask = new CancelTask(this );
1709: ConnectionImpl.getCancelTimer().schedule(
1710: timeoutTask, batchTimeout);
1711: }
1712:
1713: if (this .retrieveGeneratedKeys) {
1714: this .batchedGeneratedKeys = new ArrayList(
1715: nbrCommands);
1716: }
1717:
1718: for (commandIndex = 0; commandIndex < nbrCommands; commandIndex++) {
1719: Object arg = this .batchedArgs.get(commandIndex);
1720:
1721: if (arg instanceof String) {
1722: updateCounts[commandIndex] = executeUpdate((String) arg);
1723: } else {
1724: BatchParams paramArg = (BatchParams) arg;
1725:
1726: try {
1727: updateCounts[commandIndex] = executeUpdate(
1728: paramArg.parameterStrings,
1729: paramArg.parameterStreams,
1730: paramArg.isStream,
1731: paramArg.streamLengths,
1732: paramArg.isNull, true);
1733:
1734: if (this .retrieveGeneratedKeys) {
1735: java.sql.ResultSet rs = null;
1736:
1737: try {
1738: rs = getGeneratedKeysInternal();
1739:
1740: while (rs.next()) {
1741: this .batchedGeneratedKeys
1742: .add(new ByteArrayRow(
1743: new byte[][] { rs
1744: .getBytes(1) }));
1745: }
1746: } finally {
1747: if (rs != null) {
1748: rs.close();
1749: }
1750: }
1751: }
1752: } catch (SQLException ex) {
1753: updateCounts[commandIndex] = EXECUTE_FAILED;
1754:
1755: if (this .continueBatchOnError
1756: && !(ex instanceof MySQLTimeoutException)
1757: && !(ex instanceof MySQLStatementCancelledException)) {
1758: sqlEx = ex;
1759: } else {
1760: int[] newUpdateCounts = new int[commandIndex];
1761: System.arraycopy(updateCounts, 0,
1762: newUpdateCounts, 0,
1763: commandIndex);
1764:
1765: throw new java.sql.BatchUpdateException(
1766: ex.getMessage(), ex
1767: .getSQLState(), ex
1768: .getErrorCode(),
1769: newUpdateCounts);
1770: }
1771: }
1772: }
1773: }
1774:
1775: if (sqlEx != null) {
1776: throw new java.sql.BatchUpdateException(sqlEx
1777: .getMessage(), sqlEx.getSQLState(), sqlEx
1778: .getErrorCode(), updateCounts);
1779: }
1780: } finally {
1781: if (timeoutTask != null) {
1782: timeoutTask.cancel();
1783: }
1784:
1785: resetCancelledState();
1786: }
1787: }
1788:
1789: return (updateCounts != null) ? updateCounts : new int[0];
1790:
1791: }
1792:
1793: /**
1794: * Actually execute the prepared statement. This is here so server-side
1795: * PreparedStatements can re-use most of the code from this class.
1796: *
1797: * @param maxRowsToRetrieve
1798: * the max number of rows to return
1799: * @param sendPacket
1800: * the packet to send
1801: * @param createStreamingResultSet
1802: * should a 'streaming' result set be created?
1803: * @param queryIsSelectOnly
1804: * is this query doing a SELECT?
1805: * @param unpackFields
1806: * DOCUMENT ME!
1807: *
1808: * @return the results as a ResultSet
1809: *
1810: * @throws SQLException
1811: * if an error occurs.
1812: */
1813: protected ResultSetInternalMethods executeInternal(
1814: int maxRowsToRetrieve, Buffer sendPacket,
1815: boolean createStreamingResultSet,
1816: boolean queryIsSelectOnly, Field[] metadataFromCache,
1817: boolean isBatch) throws SQLException {
1818: try {
1819:
1820: resetCancelledState();
1821:
1822: ConnectionImpl locallyScopedConnection = this .connection;
1823:
1824: this .numberOfExecutions++;
1825:
1826: if (this .doPingInstead) {
1827: doPingInstead();
1828:
1829: return this .results;
1830: }
1831:
1832: ResultSetInternalMethods rs;
1833:
1834: CancelTask timeoutTask = null;
1835:
1836: try {
1837: if (locallyScopedConnection.getEnableQueryTimeouts()
1838: && this .timeoutInMillis != 0
1839: && locallyScopedConnection.versionMeetsMinimum(
1840: 5, 0, 0)) {
1841: timeoutTask = new CancelTask(this );
1842: ConnectionImpl.getCancelTimer().schedule(
1843: timeoutTask, this .timeoutInMillis);
1844: }
1845:
1846: rs = locallyScopedConnection.execSQL(this , null,
1847: maxRowsToRetrieve, sendPacket,
1848: this .resultSetType, this .resultSetConcurrency,
1849: createStreamingResultSet, this .currentCatalog,
1850: metadataFromCache, isBatch);
1851:
1852: if (timeoutTask != null) {
1853: timeoutTask.cancel();
1854:
1855: if (timeoutTask.caughtWhileCancelling != null) {
1856: throw timeoutTask.caughtWhileCancelling;
1857: }
1858:
1859: timeoutTask = null;
1860: }
1861:
1862: synchronized (this .cancelTimeoutMutex) {
1863: if (this .wasCancelled) {
1864: SQLException cause = null;
1865:
1866: if (this .wasCancelledByTimeout) {
1867: cause = new MySQLTimeoutException();
1868: } else {
1869: cause = new MySQLStatementCancelledException();
1870: }
1871:
1872: resetCancelledState();
1873:
1874: throw cause;
1875: }
1876: }
1877: } finally {
1878: if (timeoutTask != null) {
1879: timeoutTask.cancel();
1880: }
1881: }
1882:
1883: return rs;
1884: } catch (NullPointerException npe) {
1885: checkClosed(); // we can't synchronize ourselves against async connection-close
1886: // due to deadlock issues, so this is the next best thing for
1887: // this particular corner case.
1888:
1889: throw npe;
1890: }
1891: }
1892:
1893: /**
1894: * A Prepared SQL query is executed and its ResultSet is returned
1895: *
1896: * @return a ResultSet that contains the data produced by the query - never
1897: * null
1898: *
1899: * @exception SQLException
1900: * if a database access error occurs
1901: */
1902: public java.sql.ResultSet executeQuery() throws SQLException {
1903: checkClosed();
1904:
1905: ConnectionImpl locallyScopedConn = this .connection;
1906:
1907: checkForDml(this .originalSql, this .firstCharOfStmt);
1908:
1909: CachedResultSetMetaData cachedMetadata = null;
1910:
1911: // We need to execute this all together
1912: // So synchronize on the Connection's mutex (because
1913: // even queries going through there synchronize
1914: // on the same mutex.
1915: synchronized (locallyScopedConn.getMutex()) {
1916: clearWarnings();
1917:
1918: boolean doStreaming = createStreamingResultSet();
1919:
1920: this .batchedGeneratedKeys = null;
1921:
1922: // Adjust net_write_timeout to a higher value if we're
1923: // streaming result sets. More often than not, someone runs into
1924: // an issue where they blow net_write_timeout when using this
1925: // feature, and if they're willing to hold a result set open
1926: // for 30 seconds or more, one more round-trip isn't going to hurt
1927: //
1928: // This is reset by RowDataDynamic.close().
1929:
1930: if (doStreaming
1931: && this .connection
1932: .getNetTimeoutForStreamingResults() > 0) {
1933: locallyScopedConn
1934: .execSQL(
1935: this ,
1936: "SET net_write_timeout="
1937: + this .connection
1938: .getNetTimeoutForStreamingResults(),
1939: -1, null, ResultSet.TYPE_FORWARD_ONLY,
1940: ResultSet.CONCUR_READ_ONLY, false,
1941: this .currentCatalog, null, false);
1942: }
1943:
1944: Buffer sendPacket = fillSendPacket();
1945:
1946: if (this .results != null) {
1947: if (!this .connection
1948: .getHoldResultsOpenOverStatementClose()) {
1949: if (!this .holdResultsOpenOverClose) {
1950: this .results.realClose(false);
1951: }
1952: }
1953: }
1954:
1955: String oldCatalog = null;
1956:
1957: if (!locallyScopedConn.getCatalog().equals(
1958: this .currentCatalog)) {
1959: oldCatalog = locallyScopedConn.getCatalog();
1960: locallyScopedConn.setCatalog(this .currentCatalog);
1961: }
1962:
1963: //
1964: // Check if we have cached metadata for this query...
1965: //
1966: if (locallyScopedConn.getCacheResultSetMetadata()) {
1967: cachedMetadata = locallyScopedConn
1968: .getCachedMetaData(this .originalSql);
1969: }
1970:
1971: Field[] metadataFromCache = null;
1972:
1973: if (cachedMetadata != null) {
1974: metadataFromCache = cachedMetadata.fields;
1975: }
1976:
1977: if (locallyScopedConn.useMaxRows()) {
1978: // If there isn't a limit clause in the SQL
1979: // then limit the number of rows to return in
1980: // an efficient manner. Only do this if
1981: // setMaxRows() hasn't been used on any Statements
1982: // generated from the current Connection (saves
1983: // a query, and network traffic).
1984: if (this .hasLimitClause) {
1985: this .results = executeInternal(this .maxRows,
1986: sendPacket, createStreamingResultSet(),
1987: true, metadataFromCache, false);
1988: } else {
1989: if (this .maxRows <= 0) {
1990: executeSimpleNonQuery(locallyScopedConn,
1991: "SET OPTION SQL_SELECT_LIMIT=DEFAULT");
1992: } else {
1993: executeSimpleNonQuery(locallyScopedConn,
1994: "SET OPTION SQL_SELECT_LIMIT="
1995: + this .maxRows);
1996: }
1997:
1998: this .results = executeInternal(-1, sendPacket,
1999: doStreaming, true, metadataFromCache, false);
2000:
2001: if (oldCatalog != null) {
2002: this .connection.setCatalog(oldCatalog);
2003: }
2004: }
2005: } else {
2006: this .results = executeInternal(-1, sendPacket,
2007: doStreaming, true, metadataFromCache, false);
2008: }
2009:
2010: if (oldCatalog != null) {
2011: locallyScopedConn.setCatalog(oldCatalog);
2012: }
2013:
2014: if (cachedMetadata != null) {
2015: locallyScopedConn.initializeResultsMetadataFromCache(
2016: this .originalSql, cachedMetadata, this .results);
2017: } else {
2018: if (locallyScopedConn.getCacheResultSetMetadata()) {
2019: locallyScopedConn
2020: .initializeResultsMetadataFromCache(
2021: this .originalSql,
2022: null /* will be created */,
2023: this .results);
2024: }
2025: }
2026: }
2027:
2028: this .lastInsertId = this .results.getUpdateID();
2029:
2030: return this .results;
2031: }
2032:
2033: /**
2034: * Execute a SQL INSERT, UPDATE or DELETE statement. In addition, SQL
2035: * statements that return nothing such as SQL DDL statements can be
2036: * executed.
2037: *
2038: * @return either the row count for INSERT, UPDATE or DELETE; or 0 for SQL
2039: * statements that return nothing.
2040: *
2041: * @exception SQLException
2042: * if a database access error occurs
2043: */
2044: public int executeUpdate() throws SQLException {
2045: return executeUpdate(true, false);
2046: }
2047:
2048: /*
2049: * We need this variant, because ServerPreparedStatement calls this for
2050: * batched updates, which will end up clobbering the warnings and generated
2051: * keys we need to gather for the batch.
2052: */
2053: protected int executeUpdate(
2054: boolean clearBatchedGeneratedKeysAndWarnings,
2055: boolean isBatch) throws SQLException {
2056: if (clearBatchedGeneratedKeysAndWarnings) {
2057: clearWarnings();
2058: this .batchedGeneratedKeys = null;
2059: }
2060:
2061: return executeUpdate(this .parameterValues,
2062: this .parameterStreams, this .isStream,
2063: this .streamLengths, this .isNull, isBatch);
2064: }
2065:
2066: /**
2067: * Added to allow batch-updates
2068: *
2069: * @param batchedParameterStrings
2070: * string values used in single statement
2071: * @param batchedParameterStreams
2072: * stream values used in single statement
2073: * @param batchedIsStream
2074: * flags for streams used in single statement
2075: * @param batchedStreamLengths
2076: * lengths of streams to be read.
2077: * @param batchedIsNull
2078: * flags for parameters that are null
2079: *
2080: * @return the update count
2081: *
2082: * @throws SQLException
2083: * if a database error occurs
2084: */
2085: protected int executeUpdate(byte[][] batchedParameterStrings,
2086: InputStream[] batchedParameterStreams,
2087: boolean[] batchedIsStream, int[] batchedStreamLengths,
2088: boolean[] batchedIsNull, boolean isReallyBatch)
2089: throws SQLException {
2090:
2091: checkClosed();
2092:
2093: ConnectionImpl locallyScopedConn = this .connection;
2094:
2095: if (locallyScopedConn.isReadOnly()) {
2096: throw SQLError.createSQLException(Messages
2097: .getString("PreparedStatement.34") //$NON-NLS-1$
2098: + Messages.getString("PreparedStatement.35"), //$NON-NLS-1$
2099: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2100: }
2101:
2102: if ((this .firstCharOfStmt == 'S') && isSelectQuery()) { //$NON-NLS-1$
2103: throw SQLError.createSQLException(Messages
2104: .getString("PreparedStatement.37"), //$NON-NLS-1$
2105: "01S03"); //$NON-NLS-1$
2106: }
2107:
2108: if (this .results != null) {
2109: if (!locallyScopedConn
2110: .getHoldResultsOpenOverStatementClose()) {
2111: this .results.realClose(false);
2112: }
2113: }
2114:
2115: ResultSetInternalMethods rs = null;
2116:
2117: // The checking and changing of catalogs
2118: // must happen in sequence, so synchronize
2119: // on the same mutex that _conn is using
2120: synchronized (locallyScopedConn.getMutex()) {
2121: Buffer sendPacket = fillSendPacket(batchedParameterStrings,
2122: batchedParameterStreams, batchedIsStream,
2123: batchedStreamLengths);
2124:
2125: String oldCatalog = null;
2126:
2127: if (!locallyScopedConn.getCatalog().equals(
2128: this .currentCatalog)) {
2129: oldCatalog = locallyScopedConn.getCatalog();
2130: locallyScopedConn.setCatalog(this .currentCatalog);
2131: }
2132:
2133: //
2134: // Only apply max_rows to selects
2135: //
2136: if (locallyScopedConn.useMaxRows()) {
2137: executeSimpleNonQuery(locallyScopedConn,
2138: "SET OPTION SQL_SELECT_LIMIT=DEFAULT");
2139: }
2140:
2141: boolean oldInfoMsgState = false;
2142:
2143: if (this .retrieveGeneratedKeys) {
2144: oldInfoMsgState = locallyScopedConn
2145: .isReadInfoMsgEnabled();
2146: locallyScopedConn.setReadInfoMsgEnabled(true);
2147: }
2148:
2149: rs = executeInternal(-1, sendPacket, false, false, null,
2150: isReallyBatch);
2151:
2152: if (this .retrieveGeneratedKeys) {
2153: locallyScopedConn
2154: .setReadInfoMsgEnabled(oldInfoMsgState);
2155: rs.setFirstCharOfQuery(this .firstCharOfStmt);
2156: }
2157:
2158: if (oldCatalog != null) {
2159: locallyScopedConn.setCatalog(oldCatalog);
2160: }
2161: }
2162:
2163: this .results = rs;
2164:
2165: this .updateCount = rs.getUpdateCount();
2166:
2167: int truncatedUpdateCount = 0;
2168:
2169: if (this .updateCount > Integer.MAX_VALUE) {
2170: truncatedUpdateCount = Integer.MAX_VALUE;
2171: } else {
2172: truncatedUpdateCount = (int) this .updateCount;
2173: }
2174:
2175: this .lastInsertId = rs.getUpdateID();
2176:
2177: return truncatedUpdateCount;
2178: }
2179:
2180: private String extractValuesClause() throws SQLException {
2181: if (this .batchedValuesClause == null) {
2182: String quoteCharStr = this .connection.getMetaData()
2183: .getIdentifierQuoteString();
2184:
2185: int indexOfValues = -1;
2186:
2187: if (quoteCharStr.length() > 0) {
2188: indexOfValues = StringUtils
2189: .indexOfIgnoreCaseRespectQuotes(
2190: this .statementAfterCommentsPos,
2191: this .originalSql, "VALUES ",
2192: quoteCharStr.charAt(0), false);
2193: } else {
2194: indexOfValues = StringUtils.indexOfIgnoreCase(
2195: this .statementAfterCommentsPos,
2196: this .originalSql, "VALUES ");
2197: }
2198:
2199: if (indexOfValues == -1) {
2200: return null;
2201: }
2202:
2203: int indexOfFirstParen = this .originalSql.indexOf('(',
2204: indexOfValues + 7);
2205:
2206: if (indexOfFirstParen == -1) {
2207: return null;
2208: }
2209:
2210: int indexOfLastParen = this .originalSql.lastIndexOf(')');
2211:
2212: if (indexOfLastParen == -1) {
2213: return null;
2214: }
2215:
2216: this .batchedValuesClause = this .originalSql.substring(
2217: indexOfFirstParen, indexOfLastParen + 1);
2218: }
2219:
2220: return this .batchedValuesClause;
2221: }
2222:
2223: /**
2224: * Creates the packet that contains the query to be sent to the server.
2225: *
2226: * @return A Buffer filled with the query representing the
2227: * PreparedStatement.
2228: *
2229: * @throws SQLException
2230: * if an error occurs.
2231: */
2232: protected Buffer fillSendPacket() throws SQLException {
2233: return fillSendPacket(this .parameterValues,
2234: this .parameterStreams, this .isStream,
2235: this .streamLengths);
2236: }
2237:
2238: /**
2239: * Creates the packet that contains the query to be sent to the server.
2240: *
2241: * @param batchedParameterStrings
2242: * the parameters as strings
2243: * @param batchedParameterStreams
2244: * the parameters as streams
2245: * @param batchedIsStream
2246: * is the given parameter a stream?
2247: * @param batchedStreamLengths
2248: * the lengths of the streams (if appropriate)
2249: *
2250: * @return a Buffer filled with the query that represents this statement
2251: *
2252: * @throws SQLException
2253: * if an error occurs.
2254: */
2255: protected Buffer fillSendPacket(byte[][] batchedParameterStrings,
2256: InputStream[] batchedParameterStreams,
2257: boolean[] batchedIsStream, int[] batchedStreamLengths)
2258: throws SQLException {
2259: Buffer sendPacket = this .connection.getIO()
2260: .getSharedSendPacket();
2261:
2262: sendPacket.clear();
2263:
2264: sendPacket.writeByte((byte) MysqlDefs.QUERY);
2265:
2266: boolean useStreamLengths = this .connection
2267: .getUseStreamLengthsInPrepStmts();
2268:
2269: //
2270: // Try and get this allocation as close as possible
2271: // for BLOBs
2272: //
2273: int ensurePacketSize = 0;
2274:
2275: String statementComment = this .connection.getStatementComment();
2276:
2277: byte[] commentAsBytes = null;
2278:
2279: if (statementComment != null) {
2280: if (this .charConverter != null) {
2281: commentAsBytes = this .charConverter
2282: .toBytes(statementComment);
2283: } else {
2284: commentAsBytes = StringUtils.getBytes(statementComment,
2285: this .charConverter, this .charEncoding,
2286: this .connection.getServerCharacterEncoding(),
2287: this .connection.parserKnowsUnicode());
2288: }
2289:
2290: ensurePacketSize += commentAsBytes.length;
2291: ensurePacketSize += 6; // for /*[space] [space]*/
2292: }
2293:
2294: for (int i = 0; i < batchedParameterStrings.length; i++) {
2295: if (batchedIsStream[i] && useStreamLengths) {
2296: ensurePacketSize += batchedStreamLengths[i];
2297: }
2298: }
2299:
2300: if (ensurePacketSize != 0) {
2301: sendPacket.ensureCapacity(ensurePacketSize);
2302: }
2303:
2304: if (commentAsBytes != null) {
2305: sendPacket
2306: .writeBytesNoNull(Constants.SLASH_STAR_SPACE_AS_BYTES);
2307: sendPacket.writeBytesNoNull(commentAsBytes);
2308: sendPacket
2309: .writeBytesNoNull(Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
2310: }
2311:
2312: for (int i = 0; i < batchedParameterStrings.length; i++) {
2313: if ((batchedParameterStrings[i] == null)
2314: && (batchedParameterStreams[i] == null)) {
2315: throw SQLError.createSQLException(Messages
2316: .getString("PreparedStatement.40") //$NON-NLS-1$
2317: + (i + 1),
2318: SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);
2319: }
2320:
2321: sendPacket.writeBytesNoNull(this .staticSqlStrings[i]);
2322:
2323: if (batchedIsStream[i]) {
2324: streamToBytes(sendPacket, batchedParameterStreams[i],
2325: true, batchedStreamLengths[i], useStreamLengths);
2326: } else {
2327: sendPacket.writeBytesNoNull(batchedParameterStrings[i]);
2328: }
2329: }
2330:
2331: sendPacket
2332: .writeBytesNoNull(this .staticSqlStrings[batchedParameterStrings.length]);
2333:
2334: return sendPacket;
2335: }
2336:
2337: private String generateBatchedInsertSQL(String valuesClause,
2338: int numBatches) {
2339: StringBuffer newStatementSql = new StringBuffer(
2340: this .originalSql.length()
2341: + (numBatches * (valuesClause.length() + 1)));
2342:
2343: newStatementSql.append(this .originalSql);
2344:
2345: for (int i = 0; i < numBatches - 1; i++) {
2346: newStatementSql.append(',');
2347: newStatementSql.append(valuesClause);
2348: }
2349:
2350: return newStatementSql.toString();
2351: }
2352:
2353: /**
2354: * DOCUMENT ME!
2355: *
2356: * @param parameterIndex
2357: * DOCUMENT ME!
2358: *
2359: * @return DOCUMENT ME!
2360: *
2361: * @throws SQLException
2362: * DOCUMENT ME!
2363: */
2364: public byte[] getBytesRepresentation(int parameterIndex)
2365: throws SQLException {
2366: if (this .isStream[parameterIndex]) {
2367: return streamToBytes(this .parameterStreams[parameterIndex],
2368: false, this .streamLengths[parameterIndex],
2369: this .connection.getUseStreamLengthsInPrepStmts());
2370: }
2371:
2372: byte[] parameterVal = this .parameterValues[parameterIndex];
2373:
2374: if (parameterVal == null) {
2375: return null;
2376: }
2377:
2378: if ((parameterVal[0] == '\'')
2379: && (parameterVal[parameterVal.length - 1] == '\'')) {
2380: byte[] valNoQuotes = new byte[parameterVal.length - 2];
2381: System.arraycopy(parameterVal, 1, valNoQuotes, 0,
2382: parameterVal.length - 2);
2383:
2384: return valNoQuotes;
2385: }
2386:
2387: return parameterVal;
2388: }
2389:
2390: // --------------------------JDBC 2.0-----------------------------
2391:
2392: private final String getDateTimePattern(String dt, boolean toTime)
2393: throws Exception {
2394: //
2395: // Special case
2396: //
2397: int dtLength = (dt != null) ? dt.length() : 0;
2398:
2399: if ((dtLength >= 8) && (dtLength <= 10)) {
2400: int dashCount = 0;
2401: boolean isDateOnly = true;
2402:
2403: for (int i = 0; i < dtLength; i++) {
2404: char c = dt.charAt(i);
2405:
2406: if (!Character.isDigit(c) && (c != '-')) {
2407: isDateOnly = false;
2408:
2409: break;
2410: }
2411:
2412: if (c == '-') {
2413: dashCount++;
2414: }
2415: }
2416:
2417: if (isDateOnly && (dashCount == 2)) {
2418: return "yyyy-MM-dd"; //$NON-NLS-1$
2419: }
2420: }
2421:
2422: //
2423: // Special case - time-only
2424: //
2425: boolean colonsOnly = true;
2426:
2427: for (int i = 0; i < dtLength; i++) {
2428: char c = dt.charAt(i);
2429:
2430: if (!Character.isDigit(c) && (c != ':')) {
2431: colonsOnly = false;
2432:
2433: break;
2434: }
2435: }
2436:
2437: if (colonsOnly) {
2438: return "HH:mm:ss"; //$NON-NLS-1$
2439: }
2440:
2441: int n;
2442: int z;
2443: int count;
2444: int maxvecs;
2445: char c;
2446: char separator;
2447: StringReader reader = new StringReader(dt + " "); //$NON-NLS-1$
2448: ArrayList vec = new ArrayList();
2449: ArrayList vecRemovelist = new ArrayList();
2450: Object[] nv = new Object[3];
2451: Object[] v;
2452: nv[0] = Constants.characterValueOf('y');
2453: nv[1] = new StringBuffer();
2454: nv[2] = Constants.integerValueOf(0);
2455: vec.add(nv);
2456:
2457: if (toTime) {
2458: nv = new Object[3];
2459: nv[0] = Constants.characterValueOf('h');
2460: nv[1] = new StringBuffer();
2461: nv[2] = Constants.integerValueOf(0);
2462: vec.add(nv);
2463: }
2464:
2465: while ((z = reader.read()) != -1) {
2466: separator = (char) z;
2467: maxvecs = vec.size();
2468:
2469: for (count = 0; count < maxvecs; count++) {
2470: v = (Object[]) vec.get(count);
2471: n = ((Integer) v[2]).intValue();
2472: c = getSuccessor(((Character) v[0]).charValue(), n);
2473:
2474: if (!Character.isLetterOrDigit(separator)) {
2475: if ((c == ((Character) v[0]).charValue())
2476: && (c != 'S')) {
2477: vecRemovelist.add(v);
2478: } else {
2479: ((StringBuffer) v[1]).append(separator);
2480:
2481: if ((c == 'X') || (c == 'Y')) {
2482: v[2] = Constants.integerValueOf(4);
2483: }
2484: }
2485: } else {
2486: if (c == 'X') {
2487: c = 'y';
2488: nv = new Object[3];
2489: nv[1] = (new StringBuffer(((StringBuffer) v[1])
2490: .toString())).append('M');
2491: nv[0] = Constants.characterValueOf('M');
2492: nv[2] = Constants.integerValueOf(1);
2493: vec.add(nv);
2494: } else if (c == 'Y') {
2495: c = 'M';
2496: nv = new Object[3];
2497: nv[1] = (new StringBuffer(((StringBuffer) v[1])
2498: .toString())).append('d');
2499: nv[0] = Constants.characterValueOf('d');
2500: nv[2] = Constants.integerValueOf(1);
2501: vec.add(nv);
2502: }
2503:
2504: ((StringBuffer) v[1]).append(c);
2505:
2506: if (c == ((Character) v[0]).charValue()) {
2507: v[2] = Constants.integerValueOf(n + 1);
2508: } else {
2509: v[0] = Constants.characterValueOf(c);
2510: v[2] = Constants.integerValueOf(1);
2511: }
2512: }
2513: }
2514:
2515: int size = vecRemovelist.size();
2516:
2517: for (int i = 0; i < size; i++) {
2518: v = (Object[]) vecRemovelist.get(i);
2519: vec.remove(v);
2520: }
2521:
2522: vecRemovelist.clear();
2523: }
2524:
2525: int size = vec.size();
2526:
2527: for (int i = 0; i < size; i++) {
2528: v = (Object[]) vec.get(i);
2529: c = ((Character) v[0]).charValue();
2530: n = ((Integer) v[2]).intValue();
2531:
2532: boolean bk = getSuccessor(c, n) != c;
2533: boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk);
2534: boolean finishesAtDate = (bk && (c == 'd') && !toTime);
2535: boolean containsEnd = (((StringBuffer) v[1]).toString()
2536: .indexOf('W') != -1);
2537:
2538: if ((!atEnd && !finishesAtDate) || (containsEnd)) {
2539: vecRemovelist.add(v);
2540: }
2541: }
2542:
2543: size = vecRemovelist.size();
2544:
2545: for (int i = 0; i < size; i++) {
2546: vec.remove(vecRemovelist.get(i));
2547: }
2548:
2549: vecRemovelist.clear();
2550: v = (Object[]) vec.get(0); // might throw exception
2551:
2552: StringBuffer format = (StringBuffer) v[1];
2553: format.setLength(format.length() - 1);
2554:
2555: return format.toString();
2556: }
2557:
2558: /**
2559: * The number, types and properties of a ResultSet's columns are provided by
2560: * the getMetaData method.
2561: *
2562: * @return the description of a ResultSet's columns
2563: *
2564: * @exception SQLException
2565: * if a database-access error occurs.
2566: */
2567: public java.sql.ResultSetMetaData getMetaData() throws SQLException {
2568:
2569: //
2570: // We could just tack on a LIMIT 0 here no matter what the
2571: // statement, and check if a result set was returned or not,
2572: // but I'm not comfortable with that, myself, so we take
2573: // the "safer" road, and only allow metadata for _actual_
2574: // SELECTS (but not SHOWs).
2575: //
2576: // CALL's are trapped further up and you end up with a
2577: // CallableStatement anyway.
2578: //
2579:
2580: if (!isSelectQuery()) {
2581: return null;
2582: }
2583:
2584: PreparedStatement mdStmt = null;
2585: java.sql.ResultSet mdRs = null;
2586:
2587: if (this .pstmtResultMetaData == null) {
2588: try {
2589: mdStmt = new PreparedStatement(this .connection,
2590: this .originalSql, this .currentCatalog,
2591: this .parseInfo);
2592:
2593: mdStmt.setMaxRows(0);
2594:
2595: int paramCount = this .parameterValues.length;
2596:
2597: for (int i = 1; i <= paramCount; i++) {
2598: mdStmt.setString(i, ""); //$NON-NLS-1$
2599: }
2600:
2601: boolean hadResults = mdStmt.execute();
2602:
2603: if (hadResults) {
2604: mdRs = mdStmt.getResultSet();
2605:
2606: this .pstmtResultMetaData = mdRs.getMetaData();
2607: } else {
2608: this .pstmtResultMetaData = new ResultSetMetaData(
2609: new Field[0], this .connection
2610: .getUseOldAliasMetadataBehavior());
2611: }
2612: } finally {
2613: SQLException sqlExRethrow = null;
2614:
2615: if (mdRs != null) {
2616: try {
2617: mdRs.close();
2618: } catch (SQLException sqlEx) {
2619: sqlExRethrow = sqlEx;
2620: }
2621:
2622: mdRs = null;
2623: }
2624:
2625: if (mdStmt != null) {
2626: try {
2627: mdStmt.close();
2628: } catch (SQLException sqlEx) {
2629: sqlExRethrow = sqlEx;
2630: }
2631:
2632: mdStmt = null;
2633: }
2634:
2635: if (sqlExRethrow != null) {
2636: throw sqlExRethrow;
2637: }
2638: }
2639: }
2640:
2641: return this .pstmtResultMetaData;
2642: }
2643:
2644: protected boolean isSelectQuery() {
2645: return StringUtils.startsWithIgnoreCaseAndWs(StringUtils
2646: .stripComments(this .originalSql, "'\"", "'\"", true,
2647: false, true, true), "SELECT");
2648: }
2649:
2650: /**
2651: * @see PreparedStatement#getParameterMetaData()
2652: */
2653: public ParameterMetaData getParameterMetaData() throws SQLException {
2654: if (this .parameterMetaData == null) {
2655: if (this .connection.getGenerateSimpleParameterMetadata()) {
2656: this .parameterMetaData = new MysqlParameterMetadata(
2657: this .parameterCount);
2658: } else {
2659: this .parameterMetaData = new MysqlParameterMetadata(
2660: null, this .parameterCount);
2661: }
2662: }
2663:
2664: return this .parameterMetaData;
2665: }
2666:
2667: ParseInfo getParseInfo() {
2668: return this .parseInfo;
2669: }
2670:
2671: private final char getSuccessor(char c, int n) {
2672: return ((c == 'y') && (n == 2)) ? 'X'
2673: : (((c == 'y') && (n < 4)) ? 'y'
2674: : ((c == 'y') ? 'M'
2675: : (((c == 'M') && (n == 2)) ? 'Y'
2676: : (((c == 'M') && (n < 3)) ? 'M'
2677: : ((c == 'M') ? 'd'
2678: : (((c == 'd') && (n < 2)) ? 'd'
2679: : ((c == 'd') ? 'H'
2680: : (((c == 'H') && (n < 2)) ? 'H'
2681: : ((c == 'H') ? 'm'
2682: : (((c == 'm') && (n < 2)) ? 'm'
2683: : ((c == 'm') ? 's'
2684: : (((c == 's') && (n < 2)) ? 's'
2685: : 'W'))))))))))));
2686: }
2687:
2688: /**
2689: * Used to escape binary data with hex for mb charsets
2690: *
2691: * @param buf
2692: * @param packet
2693: * @param size
2694: * @throws SQLException
2695: */
2696: private final void hexEscapeBlock(byte[] buf, Buffer packet,
2697: int size) throws SQLException {
2698: for (int i = 0; i < size; i++) {
2699: byte b = buf[i];
2700: int lowBits = (b & 0xff) / 16;
2701: int highBits = (b & 0xff) % 16;
2702:
2703: packet.writeByte(HEX_DIGITS[lowBits]);
2704: packet.writeByte(HEX_DIGITS[highBits]);
2705: }
2706: }
2707:
2708: private void initializeFromParseInfo() throws SQLException {
2709: this .staticSqlStrings = this .parseInfo.staticSql;
2710: this .hasLimitClause = this .parseInfo.foundLimitClause;
2711: this .isLoadDataQuery = this .parseInfo.foundLoadData;
2712: this .firstCharOfStmt = this .parseInfo.firstStmtChar;
2713:
2714: this .parameterCount = this .staticSqlStrings.length - 1;
2715:
2716: this .parameterValues = new byte[this .parameterCount][];
2717: this .parameterStreams = new InputStream[this .parameterCount];
2718: this .isStream = new boolean[this .parameterCount];
2719: this .streamLengths = new int[this .parameterCount];
2720: this .isNull = new boolean[this .parameterCount];
2721: this .parameterTypes = new int[this .parameterCount];
2722:
2723: clearParameters();
2724:
2725: for (int j = 0; j < this .parameterCount; j++) {
2726: this .isStream[j] = false;
2727: }
2728:
2729: this .statementAfterCommentsPos = this .parseInfo.statementStartPos;
2730: }
2731:
2732: boolean isNull(int paramIndex) {
2733: return this .isNull[paramIndex];
2734: }
2735:
2736: private final int readblock(InputStream i, byte[] b)
2737: throws SQLException {
2738: try {
2739: return i.read(b);
2740: } catch (Throwable E) {
2741: throw SQLError.createSQLException(Messages
2742: .getString("PreparedStatement.56") //$NON-NLS-1$
2743: + E.getClass().getName(),
2744: SQLError.SQL_STATE_GENERAL_ERROR);
2745: }
2746: }
2747:
2748: private final int readblock(InputStream i, byte[] b, int length)
2749: throws SQLException {
2750: try {
2751: int lengthToRead = length;
2752:
2753: if (lengthToRead > b.length) {
2754: lengthToRead = b.length;
2755: }
2756:
2757: return i.read(b, 0, lengthToRead);
2758: } catch (Throwable E) {
2759: throw SQLError.createSQLException(Messages
2760: .getString("PreparedStatement.55") //$NON-NLS-1$
2761: + E.getClass().getName(),
2762: SQLError.SQL_STATE_GENERAL_ERROR);
2763: }
2764: }
2765:
2766: /**
2767: * Closes this statement, releasing all resources
2768: *
2769: * @param calledExplicitly
2770: * was this called by close()?
2771: *
2772: * @throws SQLException
2773: * if an error occurs
2774: */
2775: protected void realClose(boolean calledExplicitly,
2776: boolean closeOpenResults) throws SQLException {
2777: if (this .useUsageAdvisor) {
2778: if (this .numberOfExecutions <= 1) {
2779: String message = Messages
2780: .getString("PreparedStatement.43"); //$NON-NLS-1$
2781:
2782: this .eventSink.consumeEvent(new ProfilerEvent(
2783: ProfilerEvent.TYPE_WARN,
2784: "", this .currentCatalog, //$NON-NLS-1$
2785: this .connectionId, this .getId(), -1, System
2786: .currentTimeMillis(), 0,
2787: Constants.MILLIS_I18N, null,
2788: this .pointOfOrigin, message));
2789: }
2790: }
2791:
2792: super .realClose(calledExplicitly, closeOpenResults);
2793:
2794: this .dbmd = null;
2795: this .originalSql = null;
2796: this .staticSqlStrings = null;
2797: this .parameterValues = null;
2798: this .parameterStreams = null;
2799: this .isStream = null;
2800: this .streamLengths = null;
2801: this .isNull = null;
2802: this .streamConvertBuf = null;
2803: this .parameterTypes = null;
2804: }
2805:
2806: /**
2807: * JDBC 2.0 Set an Array parameter.
2808: *
2809: * @param i
2810: * the first parameter is 1, the second is 2, ...
2811: * @param x
2812: * an object representing an SQL array
2813: *
2814: * @throws SQLException
2815: * because this method is not implemented.
2816: * @throws NotImplemented
2817: * DOCUMENT ME!
2818: */
2819: public void setArray(int i, Array x) throws SQLException {
2820: throw new NotImplemented();
2821: }
2822:
2823: /**
2824: * When a very large ASCII value is input to a LONGVARCHAR parameter, it may
2825: * be more practical to send it via a java.io.InputStream. JDBC will read
2826: * the data from the stream as needed, until it reaches end-of-file. The
2827: * JDBC driver will do any necessary conversion from ASCII to the database
2828: * char format.
2829: *
2830: * <P>
2831: * <B>Note:</B> This stream object can either be a standard Java stream
2832: * object or your own subclass that implements the standard interface.
2833: * </p>
2834: *
2835: * @param parameterIndex
2836: * the first parameter is 1...
2837: * @param x
2838: * the parameter value
2839: * @param length
2840: * the number of bytes in the stream
2841: *
2842: * @exception SQLException
2843: * if a database access error occurs
2844: */
2845: public void setAsciiStream(int parameterIndex, InputStream x,
2846: int length) throws SQLException {
2847: if (x == null) {
2848: setNull(parameterIndex, java.sql.Types.VARCHAR);
2849: } else {
2850: setBinaryStream(parameterIndex, x, length);
2851: }
2852: }
2853:
2854: /**
2855: * Set a parameter to a java.math.BigDecimal value. The driver converts this
2856: * to a SQL NUMERIC value when it sends it to the database.
2857: *
2858: * @param parameterIndex
2859: * the first parameter is 1...
2860: * @param x
2861: * the parameter value
2862: *
2863: * @exception SQLException
2864: * if a database access error occurs
2865: */
2866: public void setBigDecimal(int parameterIndex, BigDecimal x)
2867: throws SQLException {
2868: if (x == null) {
2869: setNull(parameterIndex, java.sql.Types.DECIMAL);
2870: } else {
2871: setInternal(parameterIndex, StringUtils
2872: .fixDecimalExponent(StringUtils
2873: .consistentToString(x)));
2874:
2875: this .parameterTypes[parameterIndex - 1
2876: + getParameterIndexOffset()] = Types.DECIMAL;
2877: }
2878: }
2879:
2880: /**
2881: * When a very large binary value is input to a LONGVARBINARY parameter, it
2882: * may be more practical to send it via a java.io.InputStream. JDBC will
2883: * read the data from the stream as needed, until it reaches end-of-file.
2884: *
2885: * <P>
2886: * <B>Note:</B> This stream object can either be a standard Java stream
2887: * object or your own subclass that implements the standard interface.
2888: * </p>
2889: *
2890: * @param parameterIndex
2891: * the first parameter is 1...
2892: * @param x
2893: * the parameter value
2894: * @param length
2895: * the number of bytes to read from the stream (ignored)
2896: *
2897: * @throws SQLException
2898: * if a database access error occurs
2899: */
2900: public void setBinaryStream(int parameterIndex, InputStream x,
2901: int length) throws SQLException {
2902: if (x == null) {
2903: setNull(parameterIndex, java.sql.Types.BINARY);
2904: } else {
2905: int parameterIndexOffset = getParameterIndexOffset();
2906:
2907: if ((parameterIndex < 1)
2908: || (parameterIndex > this .staticSqlStrings.length)) {
2909: throw SQLError
2910: .createSQLException(
2911: Messages
2912: .getString("PreparedStatement.2") //$NON-NLS-1$
2913: + parameterIndex
2914: + Messages
2915: .getString("PreparedStatement.3") + this .staticSqlStrings.length + Messages.getString("PreparedStatement.4"), //$NON-NLS-1$ //$NON-NLS-2$
2916: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2917: } else if (parameterIndexOffset == -1
2918: && parameterIndex == 1) {
2919: throw SQLError
2920: .createSQLException(
2921: "Can't set IN parameter for return value of stored function call.",
2922: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2923: }
2924:
2925: this .parameterStreams[parameterIndex - 1
2926: + parameterIndexOffset] = x;
2927: this .isStream[parameterIndex - 1 + parameterIndexOffset] = true;
2928: this .streamLengths[parameterIndex - 1
2929: + parameterIndexOffset] = length;
2930: this .isNull[parameterIndex - 1 + parameterIndexOffset] = false;
2931: this .parameterTypes[parameterIndex - 1
2932: + getParameterIndexOffset()] = Types.BLOB;
2933: }
2934: }
2935:
2936: public void setBlob(int parameterIndex, InputStream inputStream,
2937: long length) throws SQLException {
2938: setBinaryStream(parameterIndex, inputStream, (int) length);
2939: }
2940:
2941: /**
2942: * JDBC 2.0 Set a BLOB parameter.
2943: *
2944: * @param i
2945: * the first parameter is 1, the second is 2, ...
2946: * @param x
2947: * an object representing a BLOB
2948: *
2949: * @throws SQLException
2950: * if a database error occurs
2951: */
2952: public void setBlob(int i, java.sql.Blob x) throws SQLException {
2953: if (x == null) {
2954: setNull(i, Types.BLOB);
2955: } else {
2956: ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
2957:
2958: bytesOut.write('\'');
2959: escapeblockFast(x.getBytes(1, (int) x.length()), bytesOut,
2960: (int) x.length());
2961: bytesOut.write('\'');
2962:
2963: setInternal(i, bytesOut.toByteArray());
2964:
2965: this .parameterTypes[i - 1 + getParameterIndexOffset()] = Types.BLOB;
2966: }
2967: }
2968:
2969: /**
2970: * Set a parameter to a Java boolean value. The driver converts this to a
2971: * SQL BIT value when it sends it to the database.
2972: *
2973: * @param parameterIndex
2974: * the first parameter is 1...
2975: * @param x
2976: * the parameter value
2977: *
2978: * @throws SQLException
2979: * if a database access error occurs
2980: */
2981: public void setBoolean(int parameterIndex, boolean x)
2982: throws SQLException {
2983: if (this .useTrueBoolean) {
2984: setInternal(parameterIndex, x ? "1" : "0"); //$NON-NLS-1$ //$NON-NLS-2$
2985: } else {
2986: setInternal(parameterIndex, x ? "'t'" : "'f'"); //$NON-NLS-1$ //$NON-NLS-2$
2987:
2988: this .parameterTypes[parameterIndex - 1
2989: + getParameterIndexOffset()] = Types.BOOLEAN;
2990: }
2991: }
2992:
2993: /**
2994: * Set a parameter to a Java byte value. The driver converts this to a SQL
2995: * TINYINT value when it sends it to the database.
2996: *
2997: * @param parameterIndex
2998: * the first parameter is 1...
2999: * @param x
3000: * the parameter value
3001: *
3002: * @exception SQLException
3003: * if a database access error occurs
3004: */
3005: public void setByte(int parameterIndex, byte x) throws SQLException {
3006: setInternal(parameterIndex, String.valueOf(x));
3007:
3008: this .parameterTypes[parameterIndex - 1
3009: + getParameterIndexOffset()] = Types.TINYINT;
3010: }
3011:
3012: /**
3013: * Set a parameter to a Java array of bytes. The driver converts this to a
3014: * SQL VARBINARY or LONGVARBINARY (depending on the argument's size relative
3015: * to the driver's limits on VARBINARYs) when it sends it to the database.
3016: *
3017: * @param parameterIndex
3018: * the first parameter is 1...
3019: * @param x
3020: * the parameter value
3021: *
3022: * @exception SQLException
3023: * if a database access error occurs
3024: */
3025: public void setBytes(int parameterIndex, byte[] x)
3026: throws SQLException {
3027: setBytes(parameterIndex, x, true, true);
3028:
3029: if (x != null) {
3030: this .parameterTypes[parameterIndex - 1
3031: + getParameterIndexOffset()] = Types.BINARY;
3032: }
3033: }
3034:
3035: protected void setBytes(int parameterIndex, byte[] x,
3036: boolean checkForIntroducer, boolean escapeForMBChars)
3037: throws SQLException {
3038: if (x == null) {
3039: setNull(parameterIndex, java.sql.Types.BINARY);
3040: } else {
3041: String connectionEncoding = this .connection.getEncoding();
3042:
3043: if (this .connection.isNoBackslashEscapesSet()
3044: || (escapeForMBChars
3045: && this .connection.getUseUnicode()
3046: && connectionEncoding != null && CharsetMapping
3047: .isMultibyteCharset(connectionEncoding))) {
3048:
3049: // Send as hex
3050:
3051: ByteArrayOutputStream bOut = new ByteArrayOutputStream(
3052: (x.length * 2) + 3);
3053: bOut.write('x');
3054: bOut.write('\'');
3055:
3056: for (int i = 0; i < x.length; i++) {
3057: int lowBits = (x[i] & 0xff) / 16;
3058: int highBits = (x[i] & 0xff) % 16;
3059:
3060: bOut.write(HEX_DIGITS[lowBits]);
3061: bOut.write(HEX_DIGITS[highBits]);
3062: }
3063:
3064: bOut.write('\'');
3065:
3066: setInternal(parameterIndex, bOut.toByteArray());
3067:
3068: return;
3069: }
3070:
3071: // escape them
3072: int numBytes = x.length;
3073:
3074: int pad = 2;
3075:
3076: boolean needsIntroducer = checkForIntroducer
3077: && this .connection.versionMeetsMinimum(4, 1, 0);
3078:
3079: if (needsIntroducer) {
3080: pad += 7;
3081: }
3082:
3083: ByteArrayOutputStream bOut = new ByteArrayOutputStream(
3084: numBytes + pad);
3085:
3086: if (needsIntroducer) {
3087: bOut.write('_');
3088: bOut.write('b');
3089: bOut.write('i');
3090: bOut.write('n');
3091: bOut.write('a');
3092: bOut.write('r');
3093: bOut.write('y');
3094: }
3095: bOut.write('\'');
3096:
3097: for (int i = 0; i < numBytes; ++i) {
3098: byte b = x[i];
3099:
3100: switch (b) {
3101: case 0: /* Must be escaped for 'mysql' */
3102: bOut.write('\\');
3103: bOut.write('0');
3104:
3105: break;
3106:
3107: case '\n': /* Must be escaped for logs */
3108: bOut.write('\\');
3109: bOut.write('n');
3110:
3111: break;
3112:
3113: case '\r':
3114: bOut.write('\\');
3115: bOut.write('r');
3116:
3117: break;
3118:
3119: case '\\':
3120: bOut.write('\\');
3121: bOut.write('\\');
3122:
3123: break;
3124:
3125: case '\'':
3126: bOut.write('\\');
3127: bOut.write('\'');
3128:
3129: break;
3130:
3131: case '"': /* Better safe than sorry */
3132: bOut.write('\\');
3133: bOut.write('"');
3134:
3135: break;
3136:
3137: case '\032': /* This gives problems on Win32 */
3138: bOut.write('\\');
3139: bOut.write('Z');
3140:
3141: break;
3142:
3143: default:
3144: bOut.write(b);
3145: }
3146: }
3147:
3148: bOut.write('\'');
3149:
3150: setInternal(parameterIndex, bOut.toByteArray());
3151: }
3152: }
3153:
3154: /**
3155: * Used by updatable result sets for refreshRow() because the parameter has
3156: * already been escaped for updater or inserter prepared statements.
3157: *
3158: * @param parameterIndex
3159: * the parameter to set.
3160: * @param parameterAsBytes
3161: * the parameter as a string.
3162: *
3163: * @throws SQLException
3164: * if an error occurs
3165: */
3166: protected void setBytesNoEscape(int parameterIndex,
3167: byte[] parameterAsBytes) throws SQLException {
3168: byte[] parameterWithQuotes = new byte[parameterAsBytes.length + 2];
3169: parameterWithQuotes[0] = '\'';
3170: System.arraycopy(parameterAsBytes, 0, parameterWithQuotes, 1,
3171: parameterAsBytes.length);
3172: parameterWithQuotes[parameterAsBytes.length + 1] = '\'';
3173:
3174: setInternal(parameterIndex, parameterWithQuotes);
3175: }
3176:
3177: protected void setBytesNoEscapeNoQuotes(int parameterIndex,
3178: byte[] parameterAsBytes) throws SQLException {
3179: setInternal(parameterIndex, parameterAsBytes);
3180: }
3181:
3182: /**
3183: * JDBC 2.0 When a very large UNICODE value is input to a LONGVARCHAR
3184: * parameter, it may be more practical to send it via a java.io.Reader. JDBC
3185: * will read the data from the stream as needed, until it reaches
3186: * end-of-file. The JDBC driver will do any necessary conversion from
3187: * UNICODE to the database char format.
3188: *
3189: * <P>
3190: * <B>Note:</B> This stream object can either be a standard Java stream
3191: * object or your own subclass that implements the standard interface.
3192: * </p>
3193: *
3194: * @param parameterIndex
3195: * the first parameter is 1, the second is 2, ...
3196: * @param reader
3197: * the java reader which contains the UNICODE data
3198: * @param length
3199: * the number of characters in the stream
3200: *
3201: * @exception SQLException
3202: * if a database-access error occurs.
3203: */
3204: public void setCharacterStream(int parameterIndex,
3205: java.io.Reader reader, int length) throws SQLException {
3206: try {
3207: if (reader == null) {
3208: setNull(parameterIndex, Types.LONGVARCHAR);
3209: } else {
3210: char[] c = null;
3211: int len = 0;
3212:
3213: boolean useLength = this .connection
3214: .getUseStreamLengthsInPrepStmts();
3215:
3216: String forcedEncoding = this .connection
3217: .getClobCharacterEncoding();
3218:
3219: if (useLength && (length != -1)) {
3220: c = new char[length];
3221:
3222: int numCharsRead = readFully(reader, c, length); // blocks
3223: // until
3224: // all
3225: // read
3226:
3227: if (forcedEncoding == null) {
3228: setString(parameterIndex, new String(c, 0,
3229: numCharsRead));
3230: } else {
3231: try {
3232: setBytes(parameterIndex, new String(c, 0,
3233: numCharsRead)
3234: .getBytes(forcedEncoding));
3235: } catch (UnsupportedEncodingException uee) {
3236: throw SQLError
3237: .createSQLException(
3238: "Unsupported character encoding "
3239: + forcedEncoding,
3240: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3241: }
3242: }
3243: } else {
3244: c = new char[4096];
3245:
3246: StringBuffer buf = new StringBuffer();
3247:
3248: while ((len = reader.read(c)) != -1) {
3249: buf.append(c, 0, len);
3250: }
3251:
3252: if (forcedEncoding == null) {
3253: setString(parameterIndex, buf.toString());
3254: } else {
3255: try {
3256: setBytes(parameterIndex, buf.toString()
3257: .getBytes(forcedEncoding));
3258: } catch (UnsupportedEncodingException uee) {
3259: throw SQLError
3260: .createSQLException(
3261: "Unsupported character encoding "
3262: + forcedEncoding,
3263: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3264: }
3265: }
3266: }
3267:
3268: this .parameterTypes[parameterIndex - 1
3269: + getParameterIndexOffset()] = Types.CLOB;
3270: }
3271: } catch (java.io.IOException ioEx) {
3272: throw SQLError.createSQLException(ioEx.toString(),
3273: SQLError.SQL_STATE_GENERAL_ERROR);
3274: }
3275: }
3276:
3277: /**
3278: * JDBC 2.0 Set a CLOB parameter.
3279: *
3280: * @param i
3281: * the first parameter is 1, the second is 2, ...
3282: * @param x
3283: * an object representing a CLOB
3284: *
3285: * @throws SQLException
3286: * if a database error occurs
3287: */
3288: public void setClob(int i, Clob x) throws SQLException {
3289: if (x == null) {
3290: setNull(i, Types.CLOB);
3291: } else {
3292:
3293: String forcedEncoding = this .connection
3294: .getClobCharacterEncoding();
3295:
3296: if (forcedEncoding == null) {
3297: setString(i, x.getSubString(1L, (int) x.length()));
3298: } else {
3299: try {
3300: setBytes(i, x.getSubString(1L, (int) x.length())
3301: .getBytes(forcedEncoding));
3302: } catch (UnsupportedEncodingException uee) {
3303: throw SQLError.createSQLException(
3304: "Unsupported character encoding "
3305: + forcedEncoding,
3306: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3307: }
3308: }
3309:
3310: this .parameterTypes[i - 1 + getParameterIndexOffset()] = Types.CLOB;
3311: }
3312: }
3313:
3314: /**
3315: * Set a parameter to a java.sql.Date value. The driver converts this to a
3316: * SQL DATE value when it sends it to the database.
3317: *
3318: * @param parameterIndex
3319: * the first parameter is 1...
3320: * @param x
3321: * the parameter value
3322: *
3323: * @exception java.sql.SQLException
3324: * if a database access error occurs
3325: */
3326: public void setDate(int parameterIndex, java.sql.Date x)
3327: throws java.sql.SQLException {
3328: if (x == null) {
3329: setNull(parameterIndex, java.sql.Types.DATE);
3330: } else {
3331: // FIXME: Have instance version of this, problem as it's
3332: // not thread-safe :(
3333: SimpleDateFormat dateFormatter = new SimpleDateFormat(
3334: "''yyyy-MM-dd''", Locale.US); //$NON-NLS-1$
3335: setInternal(parameterIndex, dateFormatter.format(x));
3336:
3337: this .parameterTypes[parameterIndex - 1
3338: + getParameterIndexOffset()] = Types.DATE;
3339: }
3340: }
3341:
3342: /**
3343: * Set a parameter to a java.sql.Date value. The driver converts this to a
3344: * SQL DATE value when it sends it to the database.
3345: *
3346: * @param parameterIndex
3347: * the first parameter is 1, the second is 2, ...
3348: * @param x
3349: * the parameter value
3350: * @param cal
3351: * the calendar to interpret the date with
3352: *
3353: * @exception SQLException
3354: * if a database-access error occurs.
3355: */
3356: public void setDate(int parameterIndex, java.sql.Date x,
3357: Calendar cal) throws SQLException {
3358: setDate(parameterIndex, x);
3359: }
3360:
3361: /**
3362: * Set a parameter to a Java double value. The driver converts this to a SQL
3363: * DOUBLE value when it sends it to the database
3364: *
3365: * @param parameterIndex
3366: * the first parameter is 1...
3367: * @param x
3368: * the parameter value
3369: *
3370: * @exception SQLException
3371: * if a database access error occurs
3372: */
3373: public void setDouble(int parameterIndex, double x)
3374: throws SQLException {
3375:
3376: if (!this .connection.getAllowNanAndInf()
3377: && (x == Double.POSITIVE_INFINITY
3378: || x == Double.NEGATIVE_INFINITY || Double
3379: .isNaN(x))) {
3380: throw SQLError
3381: .createSQLException(
3382: "'"
3383: + x
3384: + "' is not a valid numeric or approximate numeric value",
3385: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3386:
3387: }
3388:
3389: setInternal(parameterIndex, StringUtils
3390: .fixDecimalExponent(String.valueOf(x)));
3391:
3392: this .parameterTypes[parameterIndex - 1
3393: + getParameterIndexOffset()] = Types.DOUBLE;
3394: }
3395:
3396: /**
3397: * Set a parameter to a Java float value. The driver converts this to a SQL
3398: * FLOAT value when it sends it to the database.
3399: *
3400: * @param parameterIndex
3401: * the first parameter is 1...
3402: * @param x
3403: * the parameter value
3404: *
3405: * @exception SQLException
3406: * if a database access error occurs
3407: */
3408: public void setFloat(int parameterIndex, float x)
3409: throws SQLException {
3410: setInternal(parameterIndex, StringUtils
3411: .fixDecimalExponent(String.valueOf(x)));
3412:
3413: this .parameterTypes[parameterIndex - 1
3414: + getParameterIndexOffset()] = Types.FLOAT;
3415: }
3416:
3417: /**
3418: * Set a parameter to a Java int value. The driver converts this to a SQL
3419: * INTEGER value when it sends it to the database.
3420: *
3421: * @param parameterIndex
3422: * the first parameter is 1...
3423: * @param x
3424: * the parameter value
3425: *
3426: * @exception SQLException
3427: * if a database access error occurs
3428: */
3429: public void setInt(int parameterIndex, int x) throws SQLException {
3430: setInternal(parameterIndex, String.valueOf(x));
3431:
3432: this .parameterTypes[parameterIndex - 1
3433: + getParameterIndexOffset()] = Types.INTEGER;
3434: }
3435:
3436: protected final void setInternal(int paramIndex, byte[] val)
3437: throws SQLException {
3438: if (this .isClosed) {
3439: throw SQLError.createSQLException(Messages
3440: .getString("PreparedStatement.48"), //$NON-NLS-1$
3441: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3442: }
3443:
3444: int parameterIndexOffset = getParameterIndexOffset();
3445:
3446: checkBounds(paramIndex, parameterIndexOffset);
3447:
3448: this .isStream[paramIndex - 1 + parameterIndexOffset] = false;
3449: this .isNull[paramIndex - 1 + parameterIndexOffset] = false;
3450: this .parameterStreams[paramIndex - 1 + parameterIndexOffset] = null;
3451: this .parameterValues[paramIndex - 1 + parameterIndexOffset] = val;
3452: }
3453:
3454: private void checkBounds(int paramIndex, int parameterIndexOffset)
3455: throws SQLException {
3456: if ((paramIndex < 1)) {
3457: throw SQLError
3458: .createSQLException(
3459: Messages.getString("PreparedStatement.49") //$NON-NLS-1$
3460: + paramIndex
3461: + Messages
3462: .getString("PreparedStatement.50"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
3463: } else if (paramIndex > this .parameterCount) {
3464: throw SQLError
3465: .createSQLException(
3466: Messages.getString("PreparedStatement.51") //$NON-NLS-1$
3467: + paramIndex
3468: + Messages
3469: .getString("PreparedStatement.52") + (this .parameterValues.length) + Messages.getString("PreparedStatement.53"), //$NON-NLS-1$ //$NON-NLS-2$
3470: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3471: } else if (parameterIndexOffset == -1 && paramIndex == 1) {
3472: throw SQLError
3473: .createSQLException(
3474: "Can't set IN parameter for return value of stored function call.",
3475: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3476: }
3477: }
3478:
3479: protected final void setInternal(int paramIndex, String val)
3480: throws SQLException {
3481: checkClosed();
3482:
3483: byte[] parameterAsBytes = null;
3484:
3485: if (this .charConverter != null) {
3486: parameterAsBytes = this .charConverter.toBytes(val);
3487: } else {
3488: parameterAsBytes = StringUtils.getBytes(val,
3489: this .charConverter, this .charEncoding,
3490: this .connection.getServerCharacterEncoding(),
3491: this .connection.parserKnowsUnicode());
3492: }
3493:
3494: setInternal(paramIndex, parameterAsBytes);
3495: }
3496:
3497: /**
3498: * Set a parameter to a Java long value. The driver converts this to a SQL
3499: * BIGINT value when it sends it to the database.
3500: *
3501: * @param parameterIndex
3502: * the first parameter is 1...
3503: * @param x
3504: * the parameter value
3505: *
3506: * @exception SQLException
3507: * if a database access error occurs
3508: */
3509: public void setLong(int parameterIndex, long x) throws SQLException {
3510: setInternal(parameterIndex, String.valueOf(x));
3511:
3512: this .parameterTypes[parameterIndex - 1
3513: + getParameterIndexOffset()] = Types.BIGINT;
3514: }
3515:
3516: /**
3517: * Set a parameter to SQL NULL
3518: *
3519: * <p>
3520: * <B>Note:</B> You must specify the parameters SQL type (although MySQL
3521: * ignores it)
3522: * </p>
3523: *
3524: * @param parameterIndex
3525: * the first parameter is 1, etc...
3526: * @param sqlType
3527: * the SQL type code defined in java.sql.Types
3528: *
3529: * @exception SQLException
3530: * if a database access error occurs
3531: */
3532: public void setNull(int parameterIndex, int sqlType)
3533: throws SQLException {
3534: setInternal(parameterIndex, "null"); //$NON-NLS-1$
3535: this .isNull[parameterIndex - 1] = true;
3536:
3537: this .parameterTypes[parameterIndex - 1
3538: + getParameterIndexOffset()] = Types.NULL;
3539: }
3540:
3541: /**
3542: * Set a parameter to SQL NULL.
3543: *
3544: * <P>
3545: * <B>Note:</B> You must specify the parameter's SQL type.
3546: * </p>
3547: *
3548: * @param parameterIndex
3549: * the first parameter is 1, the second is 2, ...
3550: * @param sqlType
3551: * SQL type code defined by java.sql.Types
3552: * @param arg
3553: * argument parameters for null
3554: *
3555: * @exception SQLException
3556: * if a database-access error occurs.
3557: */
3558: public void setNull(int parameterIndex, int sqlType, String arg)
3559: throws SQLException {
3560: setNull(parameterIndex, sqlType);
3561:
3562: this .parameterTypes[parameterIndex - 1
3563: + getParameterIndexOffset()] = Types.NULL;
3564: }
3565:
3566: private void setNumericObject(int parameterIndex,
3567: Object parameterObj, int targetSqlType, int scale)
3568: throws SQLException {
3569: Number parameterAsNum;
3570:
3571: if (parameterObj instanceof Boolean) {
3572: parameterAsNum = ((Boolean) parameterObj).booleanValue() ? Constants
3573: .integerValueOf(1)
3574: : Constants.integerValueOf(0);
3575: } else if (parameterObj instanceof String) {
3576: switch (targetSqlType) {
3577: case Types.BIT:
3578: boolean parameterAsBoolean = "true"
3579: .equalsIgnoreCase((String) parameterObj);
3580:
3581: parameterAsNum = parameterAsBoolean ? Constants
3582: .integerValueOf(1) : Constants
3583: .integerValueOf(0);
3584:
3585: break;
3586:
3587: case Types.TINYINT:
3588: case Types.SMALLINT:
3589: case Types.INTEGER:
3590: parameterAsNum = Integer.valueOf((String) parameterObj);
3591:
3592: break;
3593:
3594: case Types.BIGINT:
3595: parameterAsNum = Long.valueOf((String) parameterObj);
3596:
3597: break;
3598:
3599: case Types.REAL:
3600: parameterAsNum = Float.valueOf((String) parameterObj);
3601:
3602: break;
3603:
3604: case Types.FLOAT:
3605: case Types.DOUBLE:
3606: parameterAsNum = Double.valueOf((String) parameterObj);
3607:
3608: break;
3609:
3610: case Types.DECIMAL:
3611: case Types.NUMERIC:
3612: default:
3613: parameterAsNum = new java.math.BigDecimal(
3614: (String) parameterObj);
3615: }
3616: } else {
3617: parameterAsNum = (Number) parameterObj;
3618: }
3619:
3620: switch (targetSqlType) {
3621: case Types.BIT:
3622: case Types.TINYINT:
3623: case Types.SMALLINT:
3624: case Types.INTEGER:
3625: setInt(parameterIndex, parameterAsNum.intValue());
3626:
3627: break;
3628:
3629: case Types.BIGINT:
3630: setLong(parameterIndex, parameterAsNum.longValue());
3631:
3632: break;
3633:
3634: case Types.REAL:
3635: setFloat(parameterIndex, parameterAsNum.floatValue());
3636:
3637: break;
3638:
3639: case Types.FLOAT:
3640: case Types.DOUBLE:
3641: setDouble(parameterIndex, parameterAsNum.doubleValue());
3642:
3643: break;
3644:
3645: case Types.DECIMAL:
3646: case Types.NUMERIC:
3647:
3648: if (parameterAsNum instanceof java.math.BigDecimal) {
3649: BigDecimal scaledBigDecimal = null;
3650:
3651: try {
3652: scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum)
3653: .setScale(scale);
3654: } catch (ArithmeticException ex) {
3655: try {
3656: scaledBigDecimal = ((java.math.BigDecimal) parameterAsNum)
3657: .setScale(scale,
3658: BigDecimal.ROUND_HALF_UP);
3659: } catch (ArithmeticException arEx) {
3660: throw SQLError.createSQLException(
3661: "Can't set scale of '" + scale
3662: + "' for DECIMAL argument '"
3663: + parameterAsNum + "'",
3664: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3665: }
3666: }
3667:
3668: setBigDecimal(parameterIndex, scaledBigDecimal);
3669: } else if (parameterAsNum instanceof java.math.BigInteger) {
3670: setBigDecimal(parameterIndex, new java.math.BigDecimal(
3671: (java.math.BigInteger) parameterAsNum, scale));
3672: } else {
3673: setBigDecimal(parameterIndex, new java.math.BigDecimal(
3674: parameterAsNum.doubleValue()));
3675: }
3676:
3677: break;
3678: }
3679: }
3680:
3681: /**
3682: * DOCUMENT ME!
3683: *
3684: * @param parameterIndex
3685: * DOCUMENT ME!
3686: * @param parameterObj
3687: * DOCUMENT ME!
3688: *
3689: * @throws SQLException
3690: * DOCUMENT ME!
3691: */
3692: public void setObject(int parameterIndex, Object parameterObj)
3693: throws SQLException {
3694: if (parameterObj == null) {
3695: setNull(parameterIndex, java.sql.Types.OTHER);
3696: } else {
3697: if (parameterObj instanceof Byte) {
3698: setInt(parameterIndex, ((Byte) parameterObj).intValue());
3699: } else if (parameterObj instanceof String) {
3700: setString(parameterIndex, (String) parameterObj);
3701: } else if (parameterObj instanceof BigDecimal) {
3702: setBigDecimal(parameterIndex, (BigDecimal) parameterObj);
3703: } else if (parameterObj instanceof Short) {
3704: setShort(parameterIndex, ((Short) parameterObj)
3705: .shortValue());
3706: } else if (parameterObj instanceof Integer) {
3707: setInt(parameterIndex, ((Integer) parameterObj)
3708: .intValue());
3709: } else if (parameterObj instanceof Long) {
3710: setLong(parameterIndex, ((Long) parameterObj)
3711: .longValue());
3712: } else if (parameterObj instanceof Float) {
3713: setFloat(parameterIndex, ((Float) parameterObj)
3714: .floatValue());
3715: } else if (parameterObj instanceof Double) {
3716: setDouble(parameterIndex, ((Double) parameterObj)
3717: .doubleValue());
3718: } else if (parameterObj instanceof byte[]) {
3719: setBytes(parameterIndex, (byte[]) parameterObj);
3720: } else if (parameterObj instanceof java.sql.Date) {
3721: setDate(parameterIndex, (java.sql.Date) parameterObj);
3722: } else if (parameterObj instanceof Time) {
3723: setTime(parameterIndex, (Time) parameterObj);
3724: } else if (parameterObj instanceof Timestamp) {
3725: setTimestamp(parameterIndex, (Timestamp) parameterObj);
3726: } else if (parameterObj instanceof Boolean) {
3727: setBoolean(parameterIndex, ((Boolean) parameterObj)
3728: .booleanValue());
3729: } else if (parameterObj instanceof InputStream) {
3730: setBinaryStream(parameterIndex,
3731: (InputStream) parameterObj, -1);
3732: } else if (parameterObj instanceof java.sql.Blob) {
3733: setBlob(parameterIndex, (java.sql.Blob) parameterObj);
3734: } else if (parameterObj instanceof java.sql.Clob) {
3735: setClob(parameterIndex, (java.sql.Clob) parameterObj);
3736: } else if (this .connection.getTreatUtilDateAsTimestamp()
3737: && parameterObj instanceof java.util.Date) {
3738: setTimestamp(parameterIndex, new Timestamp(
3739: ((java.util.Date) parameterObj).getTime()));
3740: } else if (parameterObj instanceof BigInteger) {
3741: setString(parameterIndex, parameterObj.toString());
3742: } else {
3743: setSerializableObject(parameterIndex, parameterObj);
3744: }
3745: }
3746: }
3747:
3748: /**
3749: * DOCUMENT ME!
3750: *
3751: * @param parameterIndex
3752: * DOCUMENT ME!
3753: * @param parameterObj
3754: * DOCUMENT ME!
3755: * @param targetSqlType
3756: * DOCUMENT ME!
3757: *
3758: * @throws SQLException
3759: * DOCUMENT ME!
3760: */
3761: public void setObject(int parameterIndex, Object parameterObj,
3762: int targetSqlType) throws SQLException {
3763: if (!(parameterObj instanceof BigDecimal)) {
3764: setObject(parameterIndex, parameterObj, targetSqlType, 0);
3765: } else {
3766: setObject(parameterIndex, parameterObj, targetSqlType,
3767: ((BigDecimal) parameterObj).scale());
3768: }
3769: }
3770:
3771: /**
3772: * Set the value of a parameter using an object; use the java.lang
3773: * equivalent objects for integral values.
3774: *
3775: * <P>
3776: * The given Java object will be converted to the targetSqlType before being
3777: * sent to the database.
3778: * </p>
3779: *
3780: * <P>
3781: * note that this method may be used to pass database-specific abstract data
3782: * types. This is done by using a Driver-specific Java type and using a
3783: * targetSqlType of java.sql.Types.OTHER
3784: * </p>
3785: *
3786: * @param parameterIndex
3787: * the first parameter is 1...
3788: * @param parameterObj
3789: * the object containing the input parameter value
3790: * @param targetSqlType
3791: * The SQL type to be send to the database
3792: * @param scale
3793: * For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
3794: * this is the number of digits after the decimal. For all other
3795: * types this value will be ignored.
3796: *
3797: * @throws SQLException
3798: * if a database access error occurs
3799: */
3800: public void setObject(int parameterIndex, Object parameterObj,
3801: int targetSqlType, int scale) throws SQLException {
3802: if (parameterObj == null) {
3803: setNull(parameterIndex, java.sql.Types.OTHER);
3804: } else {
3805: try {
3806: switch (targetSqlType) {
3807: case Types.BOOLEAN:
3808: /*
3809: From Table-B5 in the JDBC-3.0 Spec
3810:
3811: T S I B R F D D N B B C V L
3812: I M N I E L O E U I O H A O
3813: N A T G A O U C M T O A R N
3814: Y L E I L A B I E L R C G
3815: I L G N T L M R E H V
3816: N I E T E A I A A A
3817: T N R L C N R R
3818: T C
3819: H
3820: A
3821: R
3822: -----------------------------------
3823: Boolean x x x x x x x x x x x x x x
3824: */
3825:
3826: if (parameterObj instanceof Boolean) {
3827: setBoolean(parameterIndex,
3828: ((Boolean) parameterObj).booleanValue());
3829:
3830: break;
3831: } else if (parameterObj instanceof String) {
3832: setBoolean(
3833: parameterIndex,
3834: "true"
3835: .equalsIgnoreCase((String) parameterObj)
3836: || !"0"
3837: .equalsIgnoreCase((String) parameterObj));
3838:
3839: break;
3840: } else if (parameterObj instanceof Number) {
3841: int intValue = ((Number) parameterObj)
3842: .intValue();
3843:
3844: setBoolean(parameterIndex, intValue != 0);
3845:
3846: break;
3847: } else {
3848: throw SQLError
3849: .createSQLException(
3850: "No conversion from "
3851: + parameterObj
3852: .getClass()
3853: .getName()
3854: + " to Types.BOOLEAN possible.",
3855: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3856: }
3857:
3858: case Types.BIT:
3859: case Types.TINYINT:
3860: case Types.SMALLINT:
3861: case Types.INTEGER:
3862: case Types.BIGINT:
3863: case Types.REAL:
3864: case Types.FLOAT:
3865: case Types.DOUBLE:
3866: case Types.DECIMAL:
3867: case Types.NUMERIC:
3868:
3869: setNumericObject(parameterIndex, parameterObj,
3870: targetSqlType, scale);
3871:
3872: break;
3873:
3874: case Types.CHAR:
3875: case Types.VARCHAR:
3876: case Types.LONGVARCHAR:
3877: if (parameterObj instanceof BigDecimal) {
3878: setString(
3879: parameterIndex,
3880: (StringUtils
3881: .fixDecimalExponent(StringUtils
3882: .consistentToString((BigDecimal) parameterObj))));
3883: } else {
3884: setString(parameterIndex, parameterObj
3885: .toString());
3886: }
3887:
3888: break;
3889:
3890: case Types.CLOB:
3891:
3892: if (parameterObj instanceof java.sql.Clob) {
3893: setClob(parameterIndex,
3894: (java.sql.Clob) parameterObj);
3895: } else {
3896: setString(parameterIndex, parameterObj
3897: .toString());
3898: }
3899:
3900: break;
3901:
3902: case Types.BINARY:
3903: case Types.VARBINARY:
3904: case Types.LONGVARBINARY:
3905: case Types.BLOB:
3906:
3907: if (parameterObj instanceof byte[]) {
3908: setBytes(parameterIndex, (byte[]) parameterObj);
3909: } else if (parameterObj instanceof java.sql.Blob) {
3910: setBlob(parameterIndex,
3911: (java.sql.Blob) parameterObj);
3912: } else {
3913: setBytes(parameterIndex, StringUtils.getBytes(
3914: parameterObj.toString(),
3915: this .charConverter, this .charEncoding,
3916: this .connection
3917: .getServerCharacterEncoding(),
3918: this .connection.parserKnowsUnicode()));
3919: }
3920:
3921: break;
3922:
3923: case Types.DATE:
3924: case Types.TIMESTAMP:
3925:
3926: java.util.Date parameterAsDate;
3927:
3928: if (parameterObj instanceof String) {
3929: ParsePosition pp = new ParsePosition(0);
3930: java.text.DateFormat sdf = new java.text.SimpleDateFormat(
3931: getDateTimePattern(
3932: (String) parameterObj, false),
3933: Locale.US);
3934: parameterAsDate = sdf.parse(
3935: (String) parameterObj, pp);
3936: } else {
3937: parameterAsDate = (java.util.Date) parameterObj;
3938: }
3939:
3940: switch (targetSqlType) {
3941: case Types.DATE:
3942:
3943: if (parameterAsDate instanceof java.sql.Date) {
3944: setDate(parameterIndex,
3945: (java.sql.Date) parameterAsDate);
3946: } else {
3947: setDate(parameterIndex, new java.sql.Date(
3948: parameterAsDate.getTime()));
3949: }
3950:
3951: break;
3952:
3953: case Types.TIMESTAMP:
3954:
3955: if (parameterAsDate instanceof java.sql.Timestamp) {
3956: setTimestamp(
3957: parameterIndex,
3958: (java.sql.Timestamp) parameterAsDate);
3959: } else {
3960: setTimestamp(parameterIndex,
3961: new java.sql.Timestamp(
3962: parameterAsDate.getTime()));
3963: }
3964:
3965: break;
3966: }
3967:
3968: break;
3969:
3970: case Types.TIME:
3971:
3972: if (parameterObj instanceof String) {
3973: java.text.DateFormat sdf = new java.text.SimpleDateFormat(
3974: getDateTimePattern(
3975: (String) parameterObj, true),
3976: Locale.US);
3977: setTime(parameterIndex,
3978: new java.sql.Time(sdf.parse(
3979: (String) parameterObj)
3980: .getTime()));
3981: } else if (parameterObj instanceof Timestamp) {
3982: Timestamp xT = (Timestamp) parameterObj;
3983: setTime(parameterIndex, new java.sql.Time(xT
3984: .getTime()));
3985: } else {
3986: setTime(parameterIndex,
3987: (java.sql.Time) parameterObj);
3988: }
3989:
3990: break;
3991:
3992: case Types.OTHER:
3993: setSerializableObject(parameterIndex, parameterObj);
3994:
3995: break;
3996:
3997: default:
3998: throw SQLError.createSQLException(Messages
3999: .getString("PreparedStatement.16"), //$NON-NLS-1$
4000: SQLError.SQL_STATE_GENERAL_ERROR);
4001: }
4002: } catch (Exception ex) {
4003: if (ex instanceof SQLException) {
4004: throw (SQLException) ex;
4005: }
4006:
4007: throw SQLError
4008: .createSQLException(
4009: Messages
4010: .getString("PreparedStatement.17") //$NON-NLS-1$
4011: + parameterObj.getClass()
4012: .toString()
4013: + Messages
4014: .getString("PreparedStatement.18") //$NON-NLS-1$
4015: + ex.getClass().getName()
4016: + Messages
4017: .getString("PreparedStatement.19") + ex.getMessage(), //$NON-NLS-1$
4018: SQLError.SQL_STATE_GENERAL_ERROR);
4019: }
4020: }
4021: }
4022:
4023: protected int setOneBatchedParameterSet(
4024: java.sql.PreparedStatement batchedStatement,
4025: int batchedParamIndex, Object paramSet) throws SQLException {
4026: BatchParams paramArg = (BatchParams) paramSet;
4027:
4028: boolean[] isNullBatch = paramArg.isNull;
4029: boolean[] isStreamBatch = paramArg.isStream;
4030:
4031: for (int j = 0; j < isNullBatch.length; j++) {
4032: if (isNullBatch[j]) {
4033: batchedStatement.setNull(batchedParamIndex++,
4034: Types.NULL);
4035: } else {
4036: if (isStreamBatch[j]) {
4037: batchedStatement.setBinaryStream(
4038: batchedParamIndex++,
4039: paramArg.parameterStreams[j],
4040: paramArg.streamLengths[j]);
4041: } else {
4042: ((com.mysql.jdbc.PreparedStatement) batchedStatement)
4043: .setBytesNoEscapeNoQuotes(
4044: batchedParamIndex++,
4045: paramArg.parameterStrings[j]);
4046: }
4047: }
4048: }
4049:
4050: return batchedParamIndex;
4051: }
4052:
4053: /**
4054: * JDBC 2.0 Set a REF(<structured-type>) parameter.
4055: *
4056: * @param i
4057: * the first parameter is 1, the second is 2, ...
4058: * @param x
4059: * an object representing data of an SQL REF Type
4060: *
4061: * @throws SQLException
4062: * if a database error occurs
4063: * @throws NotImplemented
4064: * DOCUMENT ME!
4065: */
4066: public void setRef(int i, Ref x) throws SQLException {
4067: throw new NotImplemented();
4068: }
4069:
4070: /**
4071: * Sets the concurrency for result sets generated by this statement
4072: *
4073: * @param concurrencyFlag
4074: * DOCUMENT ME!
4075: */
4076: void setResultSetConcurrency(int concurrencyFlag) {
4077: this .resultSetConcurrency = concurrencyFlag;
4078: }
4079:
4080: /**
4081: * Sets the result set type for result sets generated by this statement
4082: *
4083: * @param typeFlag
4084: * DOCUMENT ME!
4085: */
4086: void setResultSetType(int typeFlag) {
4087: this .resultSetType = typeFlag;
4088: }
4089:
4090: /**
4091: * DOCUMENT ME!
4092: *
4093: * @param retrieveGeneratedKeys
4094: */
4095: protected void setRetrieveGeneratedKeys(
4096: boolean retrieveGeneratedKeys) {
4097: this .retrieveGeneratedKeys = retrieveGeneratedKeys;
4098: }
4099:
4100: /**
4101: * Sets the value for the placeholder as a serialized Java object (used by
4102: * various forms of setObject()
4103: *
4104: * @param parameterIndex
4105: * DOCUMENT ME!
4106: * @param parameterObj
4107: * DOCUMENT ME!
4108: *
4109: * @throws SQLException
4110: * DOCUMENT ME!
4111: */
4112: private final void setSerializableObject(int parameterIndex,
4113: Object parameterObj) throws SQLException {
4114: try {
4115: ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
4116: ObjectOutputStream objectOut = new ObjectOutputStream(
4117: bytesOut);
4118: objectOut.writeObject(parameterObj);
4119: objectOut.flush();
4120: objectOut.close();
4121: bytesOut.flush();
4122: bytesOut.close();
4123:
4124: byte[] buf = bytesOut.toByteArray();
4125: ByteArrayInputStream bytesIn = new ByteArrayInputStream(buf);
4126: setBinaryStream(parameterIndex, bytesIn, buf.length);
4127: this .parameterTypes[parameterIndex - 1
4128: + getParameterIndexOffset()] = Types.JAVA_OBJECT;
4129: } catch (Exception ex) {
4130: throw SQLError.createSQLException(Messages
4131: .getString("PreparedStatement.54") //$NON-NLS-1$
4132: + ex.getClass().getName(),
4133: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4134: }
4135: }
4136:
4137: /**
4138: * Set a parameter to a Java short value. The driver converts this to a SQL
4139: * SMALLINT value when it sends it to the database.
4140: *
4141: * @param parameterIndex
4142: * the first parameter is 1...
4143: * @param x
4144: * the parameter value
4145: *
4146: * @exception SQLException
4147: * if a database access error occurs
4148: */
4149: public void setShort(int parameterIndex, short x)
4150: throws SQLException {
4151: setInternal(parameterIndex, String.valueOf(x));
4152:
4153: this .parameterTypes[parameterIndex - 1
4154: + getParameterIndexOffset()] = Types.SMALLINT;
4155: }
4156:
4157: /**
4158: * Set a parameter to a Java String value. The driver converts this to a SQL
4159: * VARCHAR or LONGVARCHAR value (depending on the arguments size relative to
4160: * the driver's limits on VARCHARs) when it sends it to the database.
4161: *
4162: * @param parameterIndex
4163: * the first parameter is 1...
4164: * @param x
4165: * the parameter value
4166: *
4167: * @exception SQLException
4168: * if a database access error occurs
4169: */
4170: public void setString(int parameterIndex, String x)
4171: throws SQLException {
4172: // if the passed string is null, then set this column to null
4173: if (x == null) {
4174: setNull(parameterIndex, Types.CHAR);
4175: } else {
4176: checkClosed();
4177:
4178: int stringLength = x.length();
4179:
4180: if (this .connection.isNoBackslashEscapesSet()) {
4181: // Scan for any nasty chars
4182:
4183: boolean needsHexEscape = isEscapeNeededForString(x,
4184: stringLength);
4185:
4186: if (!needsHexEscape) {
4187: byte[] parameterAsBytes = null;
4188:
4189: StringBuffer quotedString = new StringBuffer(x
4190: .length() + 2);
4191: quotedString.append('\'');
4192: quotedString.append(x);
4193: quotedString.append('\'');
4194:
4195: if (!this .isLoadDataQuery) {
4196: parameterAsBytes = StringUtils.getBytes(
4197: quotedString.toString(),
4198: this .charConverter, this .charEncoding,
4199: this .connection
4200: .getServerCharacterEncoding(),
4201: this .connection.parserKnowsUnicode());
4202: } else {
4203: // Send with platform character encoding
4204: parameterAsBytes = quotedString.toString()
4205: .getBytes();
4206: }
4207:
4208: setInternal(parameterIndex, parameterAsBytes);
4209: } else {
4210: byte[] parameterAsBytes = null;
4211:
4212: if (!this .isLoadDataQuery) {
4213: parameterAsBytes = StringUtils.getBytes(x,
4214: this .charConverter, this .charEncoding,
4215: this .connection
4216: .getServerCharacterEncoding(),
4217: this .connection.parserKnowsUnicode());
4218: } else {
4219: // Send with platform character encoding
4220: parameterAsBytes = x.getBytes();
4221: }
4222:
4223: setBytes(parameterIndex, parameterAsBytes);
4224: }
4225:
4226: return;
4227: }
4228:
4229: String parameterAsString = x;
4230: boolean needsQuoted = true;
4231:
4232: if (this .isLoadDataQuery
4233: || isEscapeNeededForString(x, stringLength)) {
4234: needsQuoted = false; // saves an allocation later
4235:
4236: StringBuffer buf = new StringBuffer(
4237: (int) (x.length() * 1.1));
4238:
4239: buf.append('\'');
4240:
4241: //
4242: // Note: buf.append(char) is _faster_ than
4243: // appending in blocks, because the block
4244: // append requires a System.arraycopy()....
4245: // go figure...
4246: //
4247:
4248: for (int i = 0; i < stringLength; ++i) {
4249: char c = x.charAt(i);
4250:
4251: switch (c) {
4252: case 0: /* Must be escaped for 'mysql' */
4253: buf.append('\\');
4254: buf.append('0');
4255:
4256: break;
4257:
4258: case '\n': /* Must be escaped for logs */
4259: buf.append('\\');
4260: buf.append('n');
4261:
4262: break;
4263:
4264: case '\r':
4265: buf.append('\\');
4266: buf.append('r');
4267:
4268: break;
4269:
4270: case '\\':
4271: buf.append('\\');
4272: buf.append('\\');
4273:
4274: break;
4275:
4276: case '\'':
4277: buf.append('\\');
4278: buf.append('\'');
4279:
4280: break;
4281:
4282: case '"': /* Better safe than sorry */
4283: if (this .usingAnsiMode) {
4284: buf.append('\\');
4285: }
4286:
4287: buf.append('"');
4288:
4289: break;
4290:
4291: case '\032': /* This gives problems on Win32 */
4292: buf.append('\\');
4293: buf.append('Z');
4294:
4295: break;
4296:
4297: default:
4298: buf.append(c);
4299: }
4300: }
4301:
4302: buf.append('\'');
4303:
4304: parameterAsString = buf.toString();
4305: }
4306:
4307: byte[] parameterAsBytes = null;
4308:
4309: if (!this .isLoadDataQuery) {
4310: if (needsQuoted) {
4311: parameterAsBytes = StringUtils.getBytesWrapped(
4312: parameterAsString, '\'', '\'',
4313: this .charConverter, this .charEncoding,
4314: this .connection
4315: .getServerCharacterEncoding(),
4316: this .connection.parserKnowsUnicode());
4317: } else {
4318: parameterAsBytes = StringUtils.getBytes(
4319: parameterAsString, this .charConverter,
4320: this .charEncoding, this .connection
4321: .getServerCharacterEncoding(),
4322: this .connection.parserKnowsUnicode());
4323: }
4324: } else {
4325: // Send with platform character encoding
4326: parameterAsBytes = parameterAsString.getBytes();
4327: }
4328:
4329: setInternal(parameterIndex, parameterAsBytes);
4330:
4331: this .parameterTypes[parameterIndex - 1
4332: + getParameterIndexOffset()] = Types.VARCHAR;
4333: }
4334: }
4335:
4336: private boolean isEscapeNeededForString(String x, int stringLength) {
4337: boolean needsHexEscape = false;
4338:
4339: for (int i = 0; i < stringLength; ++i) {
4340: char c = x.charAt(i);
4341:
4342: switch (c) {
4343: case 0: /* Must be escaped for 'mysql' */
4344:
4345: needsHexEscape = true;
4346: break;
4347:
4348: case '\n': /* Must be escaped for logs */
4349: needsHexEscape = true;
4350:
4351: break;
4352:
4353: case '\r':
4354: needsHexEscape = true;
4355: break;
4356:
4357: case '\\':
4358: needsHexEscape = true;
4359:
4360: break;
4361:
4362: case '\'':
4363: needsHexEscape = true;
4364:
4365: break;
4366:
4367: case '"': /* Better safe than sorry */
4368: needsHexEscape = true;
4369:
4370: break;
4371:
4372: case '\032': /* This gives problems on Win32 */
4373: needsHexEscape = true;
4374: break;
4375: }
4376:
4377: if (needsHexEscape) {
4378: break; // no need to scan more
4379: }
4380: }
4381: return needsHexEscape;
4382: }
4383:
4384: /**
4385: * Set a parameter to a java.sql.Time value. The driver converts this to a
4386: * SQL TIME value when it sends it to the database.
4387: *
4388: * @param parameterIndex
4389: * the first parameter is 1, the second is 2, ...
4390: * @param x
4391: * the parameter value
4392: * @param cal
4393: * the cal specifying the timezone
4394: *
4395: * @throws SQLException
4396: * if a database-access error occurs.
4397: */
4398: public void setTime(int parameterIndex, java.sql.Time x,
4399: Calendar cal) throws SQLException {
4400: setTimeInternal(parameterIndex, x, cal, cal.getTimeZone(), true);
4401: }
4402:
4403: /**
4404: * Set a parameter to a java.sql.Time value. The driver converts this to a
4405: * SQL TIME value when it sends it to the database.
4406: *
4407: * @param parameterIndex
4408: * the first parameter is 1...));
4409: * @param x
4410: * the parameter value
4411: *
4412: * @throws java.sql.SQLException
4413: * if a database access error occurs
4414: */
4415: public void setTime(int parameterIndex, Time x)
4416: throws java.sql.SQLException {
4417: setTimeInternal(parameterIndex, x, null, Util
4418: .getDefaultTimeZone(), false);
4419: }
4420:
4421: /**
4422: * Set a parameter to a java.sql.Time value. The driver converts this to a
4423: * SQL TIME value when it sends it to the database, using the given
4424: * timezone.
4425: *
4426: * @param parameterIndex
4427: * the first parameter is 1...));
4428: * @param x
4429: * the parameter value
4430: * @param tz
4431: * the timezone to use
4432: *
4433: * @throws java.sql.SQLException
4434: * if a database access error occurs
4435: */
4436: private void setTimeInternal(int parameterIndex, Time x,
4437: Calendar targetCalendar, TimeZone tz, boolean rollForward)
4438: throws java.sql.SQLException {
4439: if (x == null) {
4440: setNull(parameterIndex, java.sql.Types.TIME);
4441: } else {
4442: checkClosed();
4443:
4444: Calendar sessionCalendar = getCalendarInstanceForSessionOrNew();
4445:
4446: synchronized (sessionCalendar) {
4447: x = TimeUtil.changeTimezone(this .connection,
4448: sessionCalendar, targetCalendar, x, tz,
4449: this .connection.getServerTimezoneTZ(),
4450: rollForward);
4451: }
4452:
4453: setInternal(parameterIndex, "'" + x.toString() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
4454:
4455: this .parameterTypes[parameterIndex - 1
4456: + getParameterIndexOffset()] = Types.TIME;
4457: }
4458: }
4459:
4460: /**
4461: * Set a parameter to a java.sql.Timestamp value. The driver converts this
4462: * to a SQL TIMESTAMP value when it sends it to the database.
4463: *
4464: * @param parameterIndex
4465: * the first parameter is 1, the second is 2, ...
4466: * @param x
4467: * the parameter value
4468: * @param cal
4469: * the calendar specifying the timezone to use
4470: *
4471: * @throws SQLException
4472: * if a database-access error occurs.
4473: */
4474: public void setTimestamp(int parameterIndex, java.sql.Timestamp x,
4475: Calendar cal) throws SQLException {
4476: setTimestampInternal(parameterIndex, x, cal, cal.getTimeZone(),
4477: true);
4478: }
4479:
4480: /**
4481: * Set a parameter to a java.sql.Timestamp value. The driver converts this
4482: * to a SQL TIMESTAMP value when it sends it to the database.
4483: *
4484: * @param parameterIndex
4485: * the first parameter is 1...
4486: * @param x
4487: * the parameter value
4488: *
4489: * @throws java.sql.SQLException
4490: * if a database access error occurs
4491: */
4492: public void setTimestamp(int parameterIndex, Timestamp x)
4493: throws java.sql.SQLException {
4494: setTimestampInternal(parameterIndex, x, null, Util
4495: .getDefaultTimeZone(), false);
4496: }
4497:
4498: /**
4499: * Set a parameter to a java.sql.Timestamp value. The driver converts this
4500: * to a SQL TIMESTAMP value when it sends it to the database.
4501: *
4502: * @param parameterIndex
4503: * the first parameter is 1, the second is 2, ...
4504: * @param x
4505: * the parameter value
4506: * @param tz
4507: * the timezone to use
4508: *
4509: * @throws SQLException
4510: * if a database-access error occurs.
4511: */
4512: private void setTimestampInternal(int parameterIndex, Timestamp x,
4513: Calendar targetCalendar, TimeZone tz, boolean rollForward)
4514: throws SQLException {
4515: if (x == null) {
4516: setNull(parameterIndex, java.sql.Types.TIMESTAMP);
4517: } else {
4518: checkClosed();
4519:
4520: String timestampString = null;
4521:
4522: Calendar sessionCalendar = this .connection
4523: .getUseJDBCCompliantTimezoneShift() ? this .connection
4524: .getUtcCalendar()
4525: : getCalendarInstanceForSessionOrNew();
4526:
4527: synchronized (sessionCalendar) {
4528: x = TimeUtil.changeTimezone(this .connection,
4529: sessionCalendar, targetCalendar, x, tz,
4530: this .connection.getServerTimezoneTZ(),
4531: rollForward);
4532: }
4533:
4534: if (this .connection.getUseSSPSCompatibleTimezoneShift()) {
4535: doSSPSCompatibleTimezoneShift(parameterIndex, x,
4536: sessionCalendar);
4537: } else {
4538:
4539: if (this .tsdf == null) {
4540: this .tsdf = new SimpleDateFormat(
4541: "''yyyy-MM-dd HH:mm:ss''", Locale.US); //$NON-NLS-1$
4542: }
4543:
4544: timestampString = this .tsdf.format(x);
4545:
4546: setInternal(parameterIndex, timestampString); // SimpleDateFormat is not
4547: // thread-safe
4548: }
4549:
4550: this .parameterTypes[parameterIndex - 1
4551: + getParameterIndexOffset()] = Types.TIMESTAMP;
4552: }
4553: }
4554:
4555: private void doSSPSCompatibleTimezoneShift(int parameterIndex,
4556: Timestamp x, Calendar sessionCalendar) throws SQLException {
4557: Calendar sessionCalendar2 = (this .connection
4558: .getUseJDBCCompliantTimezoneShift()) ? this .connection
4559: .getUtcCalendar()
4560: : getCalendarInstanceForSessionOrNew();
4561:
4562: synchronized (sessionCalendar2) {
4563: java.util.Date oldTime = sessionCalendar2.getTime();
4564:
4565: try {
4566: sessionCalendar2.setTime(x);
4567:
4568: int year = sessionCalendar2.get(Calendar.YEAR);
4569: int month = sessionCalendar2.get(Calendar.MONTH) + 1;
4570: int date = sessionCalendar2.get(Calendar.DAY_OF_MONTH);
4571:
4572: int hour = sessionCalendar2.get(Calendar.HOUR_OF_DAY);
4573: int minute = sessionCalendar2.get(Calendar.MINUTE);
4574: int seconds = sessionCalendar2.get(Calendar.SECOND);
4575:
4576: StringBuffer tsBuf = new StringBuffer();
4577:
4578: tsBuf.append('\'');
4579: tsBuf.append(year);
4580:
4581: tsBuf.append("-");
4582:
4583: if (month < 10) {
4584: tsBuf.append('0');
4585: }
4586:
4587: tsBuf.append(month);
4588:
4589: tsBuf.append('-');
4590:
4591: if (date < 10) {
4592: tsBuf.append('0');
4593: }
4594:
4595: tsBuf.append(date);
4596:
4597: tsBuf.append(' ');
4598:
4599: if (hour < 10) {
4600: tsBuf.append('0');
4601: }
4602:
4603: tsBuf.append(hour);
4604:
4605: tsBuf.append(':');
4606:
4607: if (minute < 10) {
4608: tsBuf.append('0');
4609: }
4610:
4611: tsBuf.append(minute);
4612:
4613: tsBuf.append(':');
4614:
4615: if (seconds < 10) {
4616: tsBuf.append('0');
4617: }
4618:
4619: tsBuf.append(seconds);
4620:
4621: tsBuf.append('\'');
4622:
4623: setInternal(parameterIndex, tsBuf.toString());
4624:
4625: } finally {
4626: sessionCalendar.setTime(oldTime);
4627: }
4628: }
4629: }
4630:
4631: /**
4632: * When a very large Unicode value is input to a LONGVARCHAR parameter, it
4633: * may be more practical to send it via a java.io.InputStream. JDBC will
4634: * read the data from the stream as needed, until it reaches end-of-file.
4635: * The JDBC driver will do any necessary conversion from UNICODE to the
4636: * database char format.
4637: *
4638: * <P>
4639: * <B>Note:</B> This stream object can either be a standard Java stream
4640: * object or your own subclass that implements the standard interface.
4641: * </p>
4642: *
4643: * @param parameterIndex
4644: * the first parameter is 1...
4645: * @param x
4646: * the parameter value
4647: * @param length
4648: * the number of bytes to read from the stream
4649: *
4650: * @throws SQLException
4651: * if a database access error occurs
4652: *
4653: * @deprecated
4654: */
4655: public void setUnicodeStream(int parameterIndex, InputStream x,
4656: int length) throws SQLException {
4657: if (x == null) {
4658: setNull(parameterIndex, java.sql.Types.VARCHAR);
4659: } else {
4660: setBinaryStream(parameterIndex, x, length);
4661:
4662: this .parameterTypes[parameterIndex - 1
4663: + getParameterIndexOffset()] = Types.CLOB;
4664: }
4665: }
4666:
4667: /**
4668: * @see PreparedStatement#setURL(int, URL)
4669: */
4670: public void setURL(int parameterIndex, URL arg) throws SQLException {
4671: if (arg != null) {
4672: setString(parameterIndex, arg.toString());
4673:
4674: this .parameterTypes[parameterIndex - 1
4675: + getParameterIndexOffset()] = Types.DATALINK;
4676: } else {
4677: setNull(parameterIndex, Types.CHAR);
4678: }
4679: }
4680:
4681: private final void streamToBytes(Buffer packet, InputStream in,
4682: boolean escape, int streamLength, boolean useLength)
4683: throws SQLException {
4684: try {
4685: String connectionEncoding = this .connection.getEncoding();
4686:
4687: boolean hexEscape = false;
4688:
4689: if (this .connection.isNoBackslashEscapesSet()
4690: || (this .connection.getUseUnicode()
4691: && connectionEncoding != null
4692: && CharsetMapping
4693: .isMultibyteCharset(connectionEncoding) && !this .connection
4694: .parserKnowsUnicode())) {
4695: hexEscape = true;
4696: }
4697:
4698: if (streamLength == -1) {
4699: useLength = false;
4700: }
4701:
4702: int bc = -1;
4703:
4704: if (useLength) {
4705: bc = readblock(in, streamConvertBuf, streamLength);
4706: } else {
4707: bc = readblock(in, streamConvertBuf);
4708: }
4709:
4710: int lengthLeftToRead = streamLength - bc;
4711:
4712: if (hexEscape) {
4713: packet.writeStringNoNull("x");
4714: } else if (this .connection.getIO().versionMeetsMinimum(4,
4715: 1, 0)) {
4716: packet.writeStringNoNull("_binary");
4717: }
4718:
4719: if (escape) {
4720: packet.writeByte((byte) '\'');
4721: }
4722:
4723: while (bc > 0) {
4724: if (hexEscape) {
4725: hexEscapeBlock(streamConvertBuf, packet, bc);
4726: } else if (escape) {
4727: escapeblockFast(streamConvertBuf, packet, bc);
4728: } else {
4729: packet.writeBytesNoNull(streamConvertBuf, 0, bc);
4730: }
4731:
4732: if (useLength) {
4733: bc = readblock(in, streamConvertBuf,
4734: lengthLeftToRead);
4735:
4736: if (bc > 0) {
4737: lengthLeftToRead -= bc;
4738: }
4739: } else {
4740: bc = readblock(in, streamConvertBuf);
4741: }
4742: }
4743:
4744: if (escape) {
4745: packet.writeByte((byte) '\'');
4746: }
4747: } finally {
4748: if (this .connection.getAutoClosePStmtStreams()) {
4749: try {
4750: in.close();
4751: } catch (IOException ioEx) {
4752: ;
4753: }
4754:
4755: in = null;
4756: }
4757: }
4758: }
4759:
4760: private final byte[] streamToBytes(InputStream in, boolean escape,
4761: int streamLength, boolean useLength) throws SQLException {
4762: try {
4763: if (streamLength == -1) {
4764: useLength = false;
4765: }
4766:
4767: ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
4768:
4769: int bc = -1;
4770:
4771: if (useLength) {
4772: bc = readblock(in, this .streamConvertBuf, streamLength);
4773: } else {
4774: bc = readblock(in, this .streamConvertBuf);
4775: }
4776:
4777: int lengthLeftToRead = streamLength - bc;
4778:
4779: if (escape) {
4780: if (this .connection.versionMeetsMinimum(4, 1, 0)) {
4781: bytesOut.write('_');
4782: bytesOut.write('b');
4783: bytesOut.write('i');
4784: bytesOut.write('n');
4785: bytesOut.write('a');
4786: bytesOut.write('r');
4787: bytesOut.write('y');
4788: }
4789:
4790: bytesOut.write('\'');
4791: }
4792:
4793: while (bc > 0) {
4794: if (escape) {
4795: escapeblockFast(this .streamConvertBuf, bytesOut, bc);
4796: } else {
4797: bytesOut.write(this .streamConvertBuf, 0, bc);
4798: }
4799:
4800: if (useLength) {
4801: bc = readblock(in, this .streamConvertBuf,
4802: lengthLeftToRead);
4803:
4804: if (bc > 0) {
4805: lengthLeftToRead -= bc;
4806: }
4807: } else {
4808: bc = readblock(in, this .streamConvertBuf);
4809: }
4810: }
4811:
4812: if (escape) {
4813: bytesOut.write('\'');
4814: }
4815:
4816: return bytesOut.toByteArray();
4817: } finally {
4818: if (this .connection.getAutoClosePStmtStreams()) {
4819: try {
4820: in.close();
4821: } catch (IOException ioEx) {
4822: ;
4823: }
4824:
4825: in = null;
4826: }
4827: }
4828: }
4829:
4830: /**
4831: * Returns this PreparedStatement represented as a string.
4832: *
4833: * @return this PreparedStatement represented as a string.
4834: */
4835: public String toString() {
4836: StringBuffer buf = new StringBuffer();
4837: buf.append(super .toString());
4838: buf.append(": "); //$NON-NLS-1$
4839:
4840: try {
4841: buf.append(asSql());
4842: } catch (SQLException sqlEx) {
4843: buf.append("EXCEPTION: " + sqlEx.toString());
4844: }
4845:
4846: return buf.toString();
4847: }
4848:
4849: public synchronized boolean isClosed() throws SQLException {
4850: return this .isClosed;
4851: }
4852:
4853: /**
4854: * For calling stored functions, this will be -1 as we don't really count
4855: * the first '?' parameter marker, it's only syntax, but JDBC counts it
4856: * as #1, otherwise it will return 0
4857: *
4858: */
4859:
4860: protected int getParameterIndexOffset() {
4861: return 0;
4862: }
4863:
4864: public void setAsciiStream(int parameterIndex, InputStream x)
4865: throws SQLException {
4866: setAsciiStream(parameterIndex, x, -1);
4867: }
4868:
4869: public void setAsciiStream(int parameterIndex, InputStream x,
4870: long length) throws SQLException {
4871: setAsciiStream(parameterIndex, x, (int) length);
4872: this .parameterTypes[parameterIndex - 1
4873: + getParameterIndexOffset()] = Types.CLOB;
4874: }
4875:
4876: public void setBinaryStream(int parameterIndex, InputStream x)
4877: throws SQLException {
4878: setBinaryStream(parameterIndex, x, -1);
4879: }
4880:
4881: public void setBinaryStream(int parameterIndex, InputStream x,
4882: long length) throws SQLException {
4883: setBinaryStream(parameterIndex, x, (int) length);
4884: }
4885:
4886: public void setBlob(int parameterIndex, InputStream inputStream)
4887: throws SQLException {
4888: setBinaryStream(parameterIndex, inputStream);
4889: }
4890:
4891: public void setCharacterStream(int parameterIndex, Reader reader)
4892: throws SQLException {
4893: setCharacterStream(parameterIndex, reader, -1);
4894: }
4895:
4896: public void setCharacterStream(int parameterIndex, Reader reader,
4897: long length) throws SQLException {
4898: setCharacterStream(parameterIndex, reader, (int) length);
4899:
4900: }
4901:
4902: public void setClob(int parameterIndex, Reader reader)
4903: throws SQLException {
4904: setCharacterStream(parameterIndex, reader);
4905:
4906: }
4907:
4908: public void setClob(int parameterIndex, Reader reader, long length)
4909: throws SQLException {
4910: setCharacterStream(parameterIndex, reader, length);
4911: }
4912:
4913: public void setNCharacterStream(int parameterIndex, Reader value)
4914: throws SQLException {
4915: setNCharacterStream(parameterIndex, value, -1);
4916: }
4917:
4918: /**
4919: * Set a parameter to a Java String value. The driver converts this to a SQL
4920: * VARCHAR or LONGVARCHAR value with introducer _utf8 (depending on the
4921: * arguments size relative to the driver's limits on VARCHARs) when it sends
4922: * it to the database. If charset is set as utf8, this method just call setString.
4923: *
4924: * @param parameterIndex
4925: * the first parameter is 1...
4926: * @param x
4927: * the parameter value
4928: *
4929: * @exception SQLException
4930: * if a database access error occurs
4931: */
4932: public void setNString(int parameterIndex, String x)
4933: throws SQLException {
4934: if (this .charEncoding.equalsIgnoreCase("UTF-8")
4935: || this .charEncoding.equalsIgnoreCase("utf8")) {
4936: setString(parameterIndex, x);
4937: return;
4938: }
4939:
4940: // if the passed string is null, then set this column to null
4941: if (x == null) {
4942: setNull(parameterIndex, java.sql.Types.CHAR);
4943: } else {
4944: int stringLength = x.length();
4945: // Ignore sql_mode=NO_BACKSLASH_ESCAPES in current implementation.
4946:
4947: // Add introducer _utf8 for NATIONAL CHARACTER
4948: StringBuffer buf = new StringBuffer(
4949: (int) (x.length() * 1.1 + 4));
4950: buf.append("_utf8");
4951: buf.append('\'');
4952:
4953: //
4954: // Note: buf.append(char) is _faster_ than
4955: // appending in blocks, because the block
4956: // append requires a System.arraycopy()....
4957: // go figure...
4958: //
4959:
4960: for (int i = 0; i < stringLength; ++i) {
4961: char c = x.charAt(i);
4962:
4963: switch (c) {
4964: case 0: /* Must be escaped for 'mysql' */
4965: buf.append('\\');
4966: buf.append('0');
4967:
4968: break;
4969:
4970: case '\n': /* Must be escaped for logs */
4971: buf.append('\\');
4972: buf.append('n');
4973:
4974: break;
4975:
4976: case '\r':
4977: buf.append('\\');
4978: buf.append('r');
4979:
4980: break;
4981:
4982: case '\\':
4983: buf.append('\\');
4984: buf.append('\\');
4985:
4986: break;
4987:
4988: case '\'':
4989: buf.append('\\');
4990: buf.append('\'');
4991:
4992: break;
4993:
4994: case '"': /* Better safe than sorry */
4995: if (this .usingAnsiMode) {
4996: buf.append('\\');
4997: }
4998:
4999: buf.append('"');
5000:
5001: break;
5002:
5003: case '\032': /* This gives problems on Win32 */
5004: buf.append('\\');
5005: buf.append('Z');
5006:
5007: break;
5008:
5009: default:
5010: buf.append(c);
5011: }
5012: }
5013:
5014: buf.append('\'');
5015:
5016: String parameterAsString = buf.toString();
5017:
5018: byte[] parameterAsBytes = null;
5019:
5020: if (!this .isLoadDataQuery) {
5021: parameterAsBytes = StringUtils.getBytes(
5022: parameterAsString, this .connection
5023: .getCharsetConverter("UTF-8"), "UTF-8",
5024: this .connection.getServerCharacterEncoding(),
5025: this .connection.parserKnowsUnicode());
5026: } else {
5027: // Send with platform character encoding
5028: parameterAsBytes = parameterAsString.getBytes();
5029: }
5030:
5031: setInternal(parameterIndex, parameterAsBytes);
5032:
5033: this .parameterTypes[parameterIndex - 1
5034: + getParameterIndexOffset()] = -9; /* Types.NVARCHAR */
5035: }
5036: }
5037:
5038: /**
5039: * JDBC 2.0 When a very large UNICODE value is input to a LONGVARCHAR
5040: * parameter, it may be more practical to send it via a java.io.Reader. JDBC
5041: * will read the data from the stream as needed, until it reaches
5042: * end-of-file. The JDBC driver will do any necessary conversion from
5043: * UNICODE to the database char format.
5044: *
5045: * <P>
5046: * <B>Note:</B> This stream object can either be a standard Java stream
5047: * object or your own subclass that implements the standard interface.
5048: * </p>
5049: *
5050: * @param parameterIndex
5051: * the first parameter is 1, the second is 2, ...
5052: * @param reader
5053: * the java reader which contains the UNICODE data
5054: * @param length
5055: * the number of characters in the stream
5056: *
5057: * @exception SQLException
5058: * if a database-access error occurs.
5059: */
5060: public void setNCharacterStream(int parameterIndex, Reader reader,
5061: long length) throws SQLException {
5062: try {
5063: if (reader == null) {
5064: setNull(parameterIndex, java.sql.Types.LONGVARCHAR);
5065:
5066: } else {
5067: char[] c = null;
5068: int len = 0;
5069:
5070: boolean useLength = this .connection
5071: .getUseStreamLengthsInPrepStmts();
5072:
5073: // Ignore "clobCharacterEncoding" because utf8 should be used this time.
5074:
5075: if (useLength && (length != -1)) {
5076: c = new char[(int) length]; // can't take more than Integer.MAX_VALUE
5077:
5078: int numCharsRead = readFully(reader, c,
5079: (int) length); // blocks
5080: // until
5081: // all
5082: // read
5083: setNString(parameterIndex, new String(c, 0,
5084: numCharsRead));
5085:
5086: } else {
5087: c = new char[4096];
5088:
5089: StringBuffer buf = new StringBuffer();
5090:
5091: while ((len = reader.read(c)) != -1) {
5092: buf.append(c, 0, len);
5093: }
5094:
5095: setNString(parameterIndex, buf.toString());
5096: }
5097:
5098: this .parameterTypes[parameterIndex - 1
5099: + getParameterIndexOffset()] = 2011; /* Types.NCLOB */
5100: }
5101: } catch (java.io.IOException ioEx) {
5102: throw SQLError.createSQLException(ioEx.toString(),
5103: SQLError.SQL_STATE_GENERAL_ERROR);
5104: }
5105: }
5106:
5107: public void setNClob(int parameterIndex, Reader reader)
5108: throws SQLException {
5109: setNCharacterStream(parameterIndex, reader);
5110: }
5111:
5112: /**
5113: * JDBC 4.0 Set a NCLOB parameter.
5114: *
5115: * @param parameterIndex
5116: * the first parameter is 1, the second is 2, ...
5117: * @param reader
5118: * the java reader which contains the UNICODE data
5119: * @param length
5120: * the number of characters in the stream
5121: *
5122: * @throws SQLException
5123: * if a database error occurs
5124: */
5125: public void setNClob(int parameterIndex, Reader reader, long length)
5126: throws SQLException {
5127: if (reader == null) {
5128: setNull(parameterIndex, java.sql.Types.LONGVARCHAR);
5129: } else {
5130: setNCharacterStream(parameterIndex, reader, length);
5131: }
5132: }
5133:
5134: public ParameterBindings getParameterBindings() throws SQLException {
5135: return new EmulatedPreparedStatementBindings();
5136: }
5137:
5138: class EmulatedPreparedStatementBindings implements
5139: ParameterBindings {
5140:
5141: private ResultSetImpl bindingsAsRs;
5142: private boolean[] parameterIsNull;
5143:
5144: public EmulatedPreparedStatementBindings() throws SQLException {
5145: List rows = new ArrayList();
5146: parameterIsNull = new boolean[parameterCount];
5147: System.arraycopy(isNull, 0, this .parameterIsNull, 0,
5148: parameterCount);
5149: byte[][] rowData = new byte[parameterCount][];
5150: Field[] typeMetadata = new Field[parameterCount];
5151:
5152: for (int i = 0; i < parameterCount; i++) {
5153: rowData[i] = getBytesRepresentation(i);
5154:
5155: int charsetIndex = 0;
5156:
5157: if (parameterTypes[i] == Types.BINARY
5158: || parameterTypes[i] == Types.BLOB) {
5159: charsetIndex = 63;
5160: } else {
5161: String mysqlEncodingName = CharsetMapping
5162: .getMysqlEncodingForJavaEncoding(connection
5163: .getEncoding(), connection);
5164: charsetIndex = CharsetMapping
5165: .getCharsetIndexForMysqlEncodingName(mysqlEncodingName);
5166: }
5167:
5168: Field parameterMetadata = new Field(null, "parameter_"
5169: + (i + 1), charsetIndex, parameterTypes[i],
5170: rowData[i].length);
5171: parameterMetadata.setConnection(connection);
5172: typeMetadata[i] = parameterMetadata;
5173: }
5174:
5175: rows.add(new ByteArrayRow(rowData));
5176:
5177: this .bindingsAsRs = new ResultSetImpl(connection
5178: .getCatalog(), typeMetadata,
5179: new RowDataStatic(rows), connection, null);
5180: this .bindingsAsRs.next();
5181: }
5182:
5183: public Array getArray(int parameterIndex) throws SQLException {
5184: return this .bindingsAsRs.getArray(parameterIndex);
5185: }
5186:
5187: public InputStream getAsciiStream(int parameterIndex)
5188: throws SQLException {
5189: return this .bindingsAsRs.getAsciiStream(parameterIndex);
5190: }
5191:
5192: public BigDecimal getBigDecimal(int parameterIndex)
5193: throws SQLException {
5194: return this .bindingsAsRs.getBigDecimal(parameterIndex);
5195: }
5196:
5197: public InputStream getBinaryStream(int parameterIndex)
5198: throws SQLException {
5199: return this .bindingsAsRs.getBinaryStream(parameterIndex);
5200: }
5201:
5202: public java.sql.Blob getBlob(int parameterIndex)
5203: throws SQLException {
5204: return this .bindingsAsRs.getBlob(parameterIndex);
5205: }
5206:
5207: public boolean getBoolean(int parameterIndex)
5208: throws SQLException {
5209: return this .bindingsAsRs.getBoolean(parameterIndex);
5210: }
5211:
5212: public byte getByte(int parameterIndex) throws SQLException {
5213: return this .bindingsAsRs.getByte(parameterIndex);
5214: }
5215:
5216: public byte[] getBytes(int parameterIndex) throws SQLException {
5217: return this .bindingsAsRs.getBytes(parameterIndex);
5218: }
5219:
5220: public Reader getCharacterStream(int parameterIndex)
5221: throws SQLException {
5222: return this .bindingsAsRs.getCharacterStream(parameterIndex);
5223: }
5224:
5225: public java.sql.Clob getClob(int parameterIndex)
5226: throws SQLException {
5227: return this .bindingsAsRs.getClob(parameterIndex);
5228: }
5229:
5230: public Date getDate(int parameterIndex) throws SQLException {
5231: return this .bindingsAsRs.getDate(parameterIndex);
5232: }
5233:
5234: public double getDouble(int parameterIndex) throws SQLException {
5235: return this .bindingsAsRs.getDouble(parameterIndex);
5236: }
5237:
5238: public float getFloat(int parameterIndex) throws SQLException {
5239: return this .bindingsAsRs.getFloat(parameterIndex);
5240: }
5241:
5242: public int getInt(int parameterIndex) throws SQLException {
5243: return this .bindingsAsRs.getInt(parameterIndex);
5244: }
5245:
5246: public long getLong(int parameterIndex) throws SQLException {
5247: return this .bindingsAsRs.getLong(parameterIndex);
5248: }
5249:
5250: public Reader getNCharacterStream(int parameterIndex)
5251: throws SQLException {
5252: return this .bindingsAsRs.getCharacterStream(parameterIndex);
5253: }
5254:
5255: public Reader getNClob(int parameterIndex) throws SQLException {
5256: return this .bindingsAsRs.getCharacterStream(parameterIndex);
5257: }
5258:
5259: public Object getObject(int parameterIndex) throws SQLException {
5260: checkBounds(parameterIndex, 0);
5261:
5262: if (parameterIsNull[parameterIndex - 1]) {
5263: return null;
5264: }
5265:
5266: // we can't rely on the default mapping for JDBC's
5267: // ResultSet.getObject() for numerics, they're not one-to-one with
5268: // PreparedStatement.setObject
5269:
5270: switch (parameterTypes[parameterIndex - 1]) {
5271: case Types.TINYINT:
5272: return new Byte(getByte(parameterIndex));
5273: case Types.SMALLINT:
5274: return new Short(getShort(parameterIndex));
5275: case Types.INTEGER:
5276: return new Integer(getInt(parameterIndex));
5277: case Types.BIGINT:
5278: return new Long(getLong(parameterIndex));
5279: case Types.FLOAT:
5280: return new Float(getFloat(parameterIndex));
5281: case Types.DOUBLE:
5282: return new Double(getDouble(parameterIndex));
5283: default:
5284: return this .bindingsAsRs.getObject(parameterIndex);
5285: }
5286: }
5287:
5288: public Ref getRef(int parameterIndex) throws SQLException {
5289: return this .bindingsAsRs.getRef(parameterIndex);
5290: }
5291:
5292: public short getShort(int parameterIndex) throws SQLException {
5293: return this .bindingsAsRs.getShort(parameterIndex);
5294: }
5295:
5296: public String getString(int parameterIndex) throws SQLException {
5297: return this .bindingsAsRs.getString(parameterIndex);
5298: }
5299:
5300: public Time getTime(int parameterIndex) throws SQLException {
5301: return this .bindingsAsRs.getTime(parameterIndex);
5302: }
5303:
5304: public Timestamp getTimestamp(int parameterIndex)
5305: throws SQLException {
5306: return this .bindingsAsRs.getTimestamp(parameterIndex);
5307: }
5308:
5309: public URL getURL(int parameterIndex) throws SQLException {
5310: return this .bindingsAsRs.getURL(parameterIndex);
5311: }
5312:
5313: public boolean isNull(int parameterIndex) throws SQLException {
5314: checkBounds(parameterIndex, 0);
5315:
5316: return this .parameterIsNull[parameterIndex - 1];
5317: }
5318: }
5319: }
|