0001: /**
0002: * Sequoia: Database clustering technology.
0003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004: * Science And Control (INRIA).
0005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
0006: * Contact: sequoia@continuent.org
0007: *
0008: * Licensed under the Apache License, Version 2.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.apache.org/licenses/LICENSE-2.0
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: * Initial developer(s): Emmanuel Cecchet.
0021: * Contributor(s): Nicolas Modrzyk, Jaco Swart.
0022: */package org.continuent.sequoia.driver;
0023:
0024: import java.io.ByteArrayOutputStream;
0025: import java.io.IOException;
0026: import java.io.InputStream;
0027: import java.io.ObjectOutputStream;
0028: import java.io.Serializable;
0029: import java.math.BigDecimal;
0030: import java.sql.Array;
0031: import java.sql.BatchUpdateException;
0032: import java.sql.Blob;
0033: import java.sql.Date;
0034: import java.sql.ParameterMetaData;
0035: import java.sql.Ref;
0036: import java.sql.SQLException;
0037: import java.sql.Time;
0038: import java.sql.Timestamp;
0039: import java.sql.Types;
0040: import java.util.LinkedList;
0041: import java.util.Vector;
0042:
0043: import org.continuent.sequoia.common.exceptions.NotImplementedException;
0044: import org.continuent.sequoia.common.protocol.PreparedStatementSerialization;
0045: import org.continuent.sequoia.common.sql.filters.AbstractBlobFilter;
0046: import org.continuent.sequoia.common.util.Strings;
0047:
0048: /**
0049: * A SQL Statement is pre-compiled and stored in a
0050: * <code>PreparedStatement</code> object. This object can then be used to
0051: * efficiently execute this statement multiple times.
0052: * <p>
0053: * <b>Note: </b> The setXXX methods for setting IN parameter values must specify
0054: * types that are compatible with the defined SQL type of the input parameter.
0055: * For instance, if the IN parameter has SQL type Integer, then setInt should be
0056: * used.
0057: * <p>
0058: * If arbitrary parameter type conversions are required, then the setObject
0059: * method should be used with a target SQL type.
0060: * <p>
0061: * In the old days, this was just a dirty copy/paste from the PostgreSQL driver.
0062: * Some irrelevant comments are left-over here and there.
0063: * <p>
0064: * This class could maybe be splitted into DriverProcessedPreparedStatement and
0065: * ProxyModeProcessedStatement
0066: *
0067: * @see DriverResultSet
0068: * @see java.sql.PreparedStatement
0069: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0070: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
0071: * @author <a href="mailto:marc.wick@monte-bre.ch">Marc Wick </a>
0072: * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
0073: * @version 1.0
0074: */
0075: public class PreparedStatement extends Statement implements
0076: java.sql.PreparedStatement {
0077: /** Original, untouched request (only trimmed) */
0078: protected String sql;
0079: /** IN parameters, ready to be inlined in the request */
0080: private String[] inStrings;
0081:
0082: // Some performance caches
0083: protected StringBuffer sbuf = new StringBuffer();
0084:
0085: /**
0086: * Constructor. Counts the number of question mark placeholders to size the
0087: * parameters array.
0088: *
0089: * @param connection the instantiating connection
0090: * @param sqlStatement the SQL statement with ? for IN markers
0091: * @param driver the Driver used to create connections
0092: */
0093: PreparedStatement(Connection connection, String sqlStatement,
0094: Driver driver) {
0095: super (connection, driver);
0096:
0097: // The following two boolean switches are used to make sure we're not
0098: // counting "?" in either strings or metadata strings. For instance the
0099: // following query:
0100: // select '?' "A ? value" from dual
0101: // doesn't have any parameters.
0102:
0103: boolean inString = false;
0104: boolean inMetaString = false;
0105: int nbParam = 0;
0106:
0107: this .sql = sqlStatement.trim();
0108: this .connection = connection;
0109:
0110: // Count how many parameters have to be set
0111: for (int i = 0; i < sql.length(); ++i) {
0112: if (sql.charAt(i) == '\'')
0113: if (i > 0 && sql.charAt(i - 1) != '\\')
0114: inString = !inString;
0115: if (sql.charAt(i) == '"')
0116: if (i > 0 && sql.charAt(i - 1) != '\\')
0117: inMetaString = !inMetaString;
0118: if ((sql.charAt(i) == '?') && (!(inString || inMetaString)))
0119: nbParam++;
0120: }
0121:
0122: inStrings = new String[nbParam];
0123:
0124: if (connection.isAlwaysGettingGeneratedKeys())
0125: generatedKeysFlag = RETURN_GENERATED_KEYS;
0126: }
0127:
0128: /**
0129: * @see PreparedStatement#PreparedStatement(Connection, String, Driver)
0130: */
0131: PreparedStatement(Connection connection, String sqlStatement,
0132: Driver driver, int autoGeneratedKeysArg) {
0133: this (connection, sqlStatement, driver);
0134: if (!connection.isAlwaysGettingGeneratedKeys())
0135: generatedKeysFlag = autoGeneratedKeysArg;
0136: }
0137:
0138: /**
0139: * Release objects for garbage collection and call Statement.close().
0140: *
0141: * @throws SQLException if an error occurs
0142: */
0143: public void close() throws SQLException {
0144: sql = null;
0145: inStrings = null;
0146:
0147: super .close();
0148: }
0149:
0150: /**
0151: * A Prepared SQL query is executed and its <code>ResultSet</code> is
0152: * returned.
0153: *
0154: * @return a <code>ResultSet</code> that contains the data produced by the *
0155: * query - never <code>null</code>.
0156: * @exception SQLException if a database access error occurs
0157: */
0158: public java.sql.ResultSet executeQuery() throws SQLException {
0159: // in Statement class
0160: return super .executeQuery(sql, compileParameters(false));
0161: }
0162:
0163: /**
0164: * Execute a SQL INSERT, UPDATE or DELETE statement. In addition, SQL
0165: * statements that return nothing such as SQL DDL statements can be executed.
0166: *
0167: * @return either the row count for <code>INSERT</code>,
0168: * <code>UPDATE</code> or <code>DELETE</code>; or 0 for SQL
0169: * statements that return nothing.
0170: * @exception SQLException if a database access error occurs
0171: */
0172: public int executeUpdate() throws SQLException {
0173: // in Statement class
0174: return super .executeUpdateWithSkeleton(sql,
0175: compileParameters(false));
0176: }
0177:
0178: /**
0179: * Sets the length of the temporary buffer to zero and returns a trimmed
0180: * version of the buffer's content. This ensures that we are not leaking
0181: * memory and that we manipulate Strings which have the minimal possible
0182: * memory footprint. Useful when handling BLOBs. Please refer to bug #4546734
0183: * is Sun's bug database.
0184: *
0185: * @return a String object containing a trimmed version of the StringBuffer's
0186: * content
0187: */
0188: protected String trimStringBuffer() {
0189: String trimmedBuf = new String(sbuf.toString());
0190: sbuf.setLength(0);
0191: return trimmedBuf;
0192: }
0193:
0194: /**
0195: * Helper - this compiles the SQL query, inlining the parameters in the
0196: * request String. This is identical to <code>this.toString()</code> except
0197: * it throws an exception if a parameter was not set.
0198: *
0199: * @param fillEmptyParametersWithCSParamTag true if called from a
0200: * CallableStatement
0201: * @return the compiled query
0202: * @throws SQLException if an error occurs
0203: */
0204: protected synchronized String compileParameters(
0205: boolean fillEmptyParametersWithCSParamTag)
0206: throws SQLException {
0207: if (inStrings.length == 0) {
0208: return "";
0209: }
0210:
0211: sbuf.setLength(0);
0212: for (int i = 0; i < inStrings.length; ++i) {
0213: if (inStrings[i] == null) {
0214: if (!fillEmptyParametersWithCSParamTag)
0215: throw new SQLException("Parameter " + (i + 1)
0216: + " is not set");
0217: setParameterWithTag(i + 1,
0218: PreparedStatementSerialization.CS_PARAM_TAG, "");
0219: }
0220: sbuf.append(inStrings[i]);
0221: }
0222: return trimStringBuffer();
0223: }
0224:
0225: /**
0226: * Escape the input string. <br>
0227: * <char>' </char> is replaced by <char>\' </char> <br>
0228: * <char>\ </char> is replaced by <char>\\ </char> <br>
0229: * if connection.escapeProcessing is set to true, surround the new string with
0230: * <char>\' </char>
0231: *
0232: * @param x the string to process
0233: * @return escaped string
0234: */
0235: protected String doEscapeProcessing(String x) {
0236: // use the shared buffer object. Should never clash but this
0237: // makes us thread safe!
0238: synchronized (sbuf) {
0239: sbuf.setLength(0);
0240: int i;
0241: sbuf.append(connection.getEscapeChar());
0242: for (i = 0; i < x.length(); ++i) {
0243: char c = x.charAt(i);
0244: if ((c == '\'' && connection.isEscapeSingleQuote())
0245: || (c == '\\' && connection.isEscapeBackslash()))
0246: sbuf.append(c);
0247: sbuf.append(c);
0248: }
0249: sbuf.append(connection.getEscapeChar());
0250: }
0251: return trimStringBuffer();
0252: }
0253:
0254: /**
0255: * Sets a parameter to SQL NULL.
0256: *
0257: * @param parameterIndex the first parameter is 1, etc...
0258: * @param sqlType the SQL type code defined in java.sql.Types
0259: * @exception SQLException if a database access error occurs
0260: */
0261: public void setNull(int parameterIndex, int sqlType)
0262: throws SQLException {
0263: // NULL_VALUE is (confusingly) also used as the "NULL_TAG" to proxy
0264: // the setNull() call
0265: setParameterWithTag(parameterIndex,
0266: PreparedStatementSerialization.NULL_VALUE, String
0267: .valueOf(sqlType));
0268: }
0269:
0270: /**
0271: * Sets a parameter to a Java boolean value. The driver converts this to a SQL
0272: * BIT value when it sends it to the database.
0273: *
0274: * @param parameterIndex the first parameter is 1...
0275: * @param x the parameter value
0276: * @exception SQLException if a database access error occurs
0277: */
0278: public void setBoolean(int parameterIndex, boolean x)
0279: throws SQLException {
0280: setParameterWithTag(parameterIndex,
0281: PreparedStatementSerialization.BOOLEAN_TAG, String
0282: .valueOf(x));
0283: }
0284:
0285: /**
0286: * Sets a parameter to a Java byte value.
0287: *
0288: * @param parameterIndex the first parameter is 1...
0289: * @param x the parameter value
0290: * @exception SQLException if a database access error occurs
0291: */
0292: public void setByte(int parameterIndex, byte x) throws SQLException {
0293: setParameterWithTag(parameterIndex,
0294: PreparedStatementSerialization.BYTE_TAG, Integer
0295: .toString(x));
0296: }
0297:
0298: /**
0299: * Sets a parameter to a Java short value. The driver converts this to a SQL
0300: * SMALLINT value when it sends it to the database.
0301: *
0302: * @param parameterIndex the first parameter is 1...
0303: * @param x the parameter value
0304: * @exception SQLException if a database access error occurs
0305: */
0306: public void setShort(int parameterIndex, short x)
0307: throws SQLException {
0308: setParameterWithTag(parameterIndex,
0309: PreparedStatementSerialization.SHORT_TAG, Integer
0310: .toString(x));
0311: }
0312:
0313: /**
0314: * Sets a parameter to a Java int value. The driver converts this to a SQL
0315: * INTEGER value when it sends it to the database.
0316: *
0317: * @param parameterIndex the first parameter is 1...
0318: * @param x the parameter value
0319: * @exception SQLException if a database access error occurs
0320: */
0321: public void setInt(int parameterIndex, int x) throws SQLException {
0322: setParameterWithTag(parameterIndex,
0323: PreparedStatementSerialization.INTEGER_TAG, Integer
0324: .toString(x));
0325: }
0326:
0327: /**
0328: * Sets a parameter to a Java long value. The driver converts this to a SQL
0329: * BIGINT value when it sends it to the database.
0330: *
0331: * @param parameterIndex the first parameter is 1...
0332: * @param x the parameter value
0333: * @exception SQLException if a database access error occurs
0334: */
0335: public void setLong(int parameterIndex, long x) throws SQLException {
0336: setParameterWithTag(parameterIndex,
0337: PreparedStatementSerialization.LONG_TAG, Long
0338: .toString(x));
0339: }
0340:
0341: /**
0342: * Sets a parameter to a Java float value. The driver converts this to a SQL
0343: * FLOAT value when it sends it to the database.
0344: *
0345: * @param parameterIndex the first parameter is 1...
0346: * @param x the parameter value
0347: * @exception SQLException if a database access error occurs
0348: */
0349: public void setFloat(int parameterIndex, float x)
0350: throws SQLException {
0351: setParameterWithTag(parameterIndex,
0352: PreparedStatementSerialization.FLOAT_TAG, Float
0353: .toString(x));
0354: }
0355:
0356: /**
0357: * Sets a parameter to a Java double value. The driver converts this to a SQL
0358: * DOUBLE value when it sends it to the database.
0359: *
0360: * @param parameterIndex the first parameter is 1...
0361: * @param x the parameter value
0362: * @exception SQLException if a database access error occurs
0363: */
0364: public void setDouble(int parameterIndex, double x)
0365: throws SQLException {
0366: setParameterWithTag(parameterIndex,
0367: PreparedStatementSerialization.DOUBLE_TAG, Double
0368: .toString(x));
0369: }
0370:
0371: /**
0372: * Sets a parameter to a java.lang.BigDecimal value. The driver converts this
0373: * to a SQL NUMERIC value when it sends it to the database.
0374: *
0375: * @param parameterIndex the first parameter is 1...
0376: * @param x the parameter value
0377: * @exception SQLException if a database access error occurs
0378: */
0379: public void setBigDecimal(int parameterIndex, BigDecimal x)
0380: throws SQLException {
0381: String serializedParam = (x == null ? null : x.toString());
0382:
0383: setParameterWithTag(parameterIndex,
0384: PreparedStatementSerialization.BIG_DECIMAL_TAG,
0385: serializedParam);
0386: }
0387:
0388: /**
0389: * Sets a parameter to a Java String value. The driver converts this to a SQL
0390: * VARCHAR or LONGVARCHAR value (depending on the arguments size relative to
0391: * the driver's limits on VARCHARs) when it sends it to the database.
0392: *
0393: * @param parameterIndex the first parameter is 1...
0394: * @param x the parameter value
0395: * @exception SQLException if a database access error occurs
0396: */
0397: public void setString(int parameterIndex, String x)
0398: throws SQLException {
0399: if (PreparedStatementSerialization.NULL_VALUE.equals(x))
0400: // Someone is trying to set a String that matches our NULL tag, a real
0401: // bad luck, use our special type NULL_STRING_TAG!
0402: setParameterWithTag(parameterIndex,
0403: PreparedStatementSerialization.NULL_STRING_TAG, x);
0404: else
0405: setParameterWithTag(parameterIndex,
0406: PreparedStatementSerialization.STRING_TAG, x);
0407: }
0408:
0409: /**
0410: * Sets a parameter to a Java array of bytes.
0411: * <p>
0412: *
0413: * @param parameterIndex the first parameter is 1...
0414: * @param x the parameter value
0415: * @exception SQLException if a database access error occurs
0416: */
0417: public void setBytes(int parameterIndex, byte[] x)
0418: throws SQLException {
0419: try {
0420: /**
0421: * Encoded only for request inlining. Decoded right away by the controller
0422: * at static
0423: * {@link #setPreparedStatement(String, java.sql.PreparedStatement)}
0424: */
0425: String encodedString = AbstractBlobFilter
0426: .getDefaultBlobFilter().encode(x);
0427: setParameterWithTag(parameterIndex,
0428: PreparedStatementSerialization.BYTES_TAG,
0429: encodedString);
0430: } catch (OutOfMemoryError oome) {
0431: System.gc();
0432: throw new SQLException("Out of memory while encoding bytes");
0433: }
0434: }
0435:
0436: /**
0437: * Sets a parameter to a java.sql.Date value. The driver converts this to a
0438: * SQL DATE value when it sends it to the database.
0439: *
0440: * @param parameterIndex the first parameter is 1...
0441: * @param x the parameter value
0442: * @exception SQLException if a database access error occurs
0443: */
0444: public void setDate(int parameterIndex, java.sql.Date x)
0445: throws SQLException {
0446: String serializedParam = (x == null ? null : new java.sql.Date(
0447: x.getTime()).toString());
0448:
0449: setParameterWithTag(parameterIndex,
0450: PreparedStatementSerialization.DATE_TAG,
0451: serializedParam);
0452: }
0453:
0454: /**
0455: * Sets a parameter to a <code>java.sql.Time</code> value. The driver
0456: * converts this to a SQL TIME value when it sends it to the database.
0457: *
0458: * @param parameterIndex the first parameter is 1...));
0459: * @param x the parameter value
0460: * @exception SQLException if a database access error occurs
0461: */
0462: public void setTime(int parameterIndex, Time x) throws SQLException {
0463: String serializedParam = (x == null ? null : x.toString());
0464:
0465: setParameterWithTag(parameterIndex,
0466: PreparedStatementSerialization.TIME_TAG,
0467: serializedParam);
0468: }
0469:
0470: /**
0471: * Sets a parameter to a <code>java.sql.Timestamp</code> value. The driver
0472: * converts this to a SQL TIMESTAMP value when it sends it to the database.
0473: *
0474: * @param parameterIndex the first parameter is 1...
0475: * @param x the parameter value
0476: * @exception SQLException if a database access error occurs
0477: */
0478: public void setTimestamp(int parameterIndex, Timestamp x)
0479: throws SQLException {
0480: if (x == null)
0481: setParameterWithTag(parameterIndex,
0482: PreparedStatementSerialization.TIMESTAMP_TAG, null);
0483: else {
0484: if (x.getClass().equals(Timestamp.class))
0485: setParameterWithTag(parameterIndex,
0486: PreparedStatementSerialization.TIMESTAMP_TAG, x
0487: .toString());
0488: else
0489: setParameterWithTag(parameterIndex,
0490: PreparedStatementSerialization.TIMESTAMP_TAG,
0491: new Timestamp(x.getTime()).toString());
0492: }
0493: }
0494:
0495: /**
0496: * When a very large ASCII value is input to a LONGVARCHAR parameter, it may
0497: * be more practical to send it via a java.io.InputStream. JDBC will read the
0498: * data from the stream as needed, until it reaches end-of-file. The JDBC
0499: * driver will do any necessary conversion from ASCII to the database char
0500: * format.
0501: * <p>
0502: * <b>Note: </b> this stream object can either be a standard Java stream
0503: * object or your own subclass that implements the standard interface.
0504: *
0505: * @param parameterIndex the first parameter is 1...
0506: * @param x the parameter value
0507: * @param length the number of bytes in the stream
0508: * @exception SQLException if a database access error occurs
0509: */
0510: public void setAsciiStream(int parameterIndex, InputStream x,
0511: int length) throws SQLException {
0512: setBinaryStream(parameterIndex, x, length);
0513: }
0514:
0515: /**
0516: * When a very large Unicode value is input to a LONGVARCHAR parameter, it may
0517: * be more practical to send it via a java.io.InputStream. JDBC will read the
0518: * data from the stream as needed, until it reaches end-of-file. The JDBC
0519: * driver will do any necessary conversion from UNICODE to the database char
0520: * format.
0521: * <p>** DEPRECIATED IN JDBC 2 **
0522: * <p>
0523: * <b>Note: </b> this stream object can either be a standard Java stream
0524: * object or your own subclass that implements the standard interface.
0525: *
0526: * @param parameterIndex the first parameter is 1...
0527: * @param x the parameter value
0528: * @param length the parameter length
0529: * @exception SQLException if a database access error occurs
0530: * @deprecated
0531: */
0532: public void setUnicodeStream(int parameterIndex, InputStream x,
0533: int length) throws SQLException {
0534: setBinaryStream(parameterIndex, x, length);
0535: }
0536:
0537: /**
0538: * Stores a binary stream into parameters array, using an intermediate byte[].
0539: * When a very large binary value is input to a LONGVARBINARY parameter, it
0540: * may be more practical to send it via a java.io.InputStream. JDBC will read
0541: * the data from the stream as needed, until it reaches end-of-file. This
0542: * should be more or less equivalent to setBytes(blob.getBytes()).
0543: * <p>
0544: * <b>Note: </b> This stream object can either be a standard Java stream
0545: * object or your own subclass that implements the standard interface.
0546: *
0547: * @param parameterIndex the first parameter is 1...
0548: * @param inStreamArg the parameter value
0549: * @param length the parameter length
0550: * @exception SQLException if a database access error occurs
0551: * @see java.sql.PreparedStatement#setBinaryStream(int, java.io.InputStream,
0552: * int)
0553: */
0554: public void setBinaryStream(int parameterIndex,
0555: InputStream inStreamArg, int length) throws SQLException {
0556: byte[] data = new byte[length];
0557: try {
0558: inStreamArg.read(data, 0, length);
0559: } catch (Exception ioe) {
0560: throw new SQLException("Problem with streaming of data");
0561: }
0562: // TODO: optimize me and avoid the copy thanks to a new setBytesFromStream()
0563: // setBytes does the blob filter encoding.
0564: setBytes(parameterIndex, data);
0565: }
0566:
0567: /**
0568: * In general, parameter values remain in force for repeated used of a
0569: * <code>Statement</code>. Setting a parameter value automatically clears
0570: * its previous value. However, in coms cases, it is useful to immediately
0571: * release the resources used by the current parameter values; this can be
0572: * done by calling <code>clearParameters()</code>.
0573: *
0574: * @exception SQLException if a database access error occurs
0575: */
0576: public void clearParameters() throws SQLException {
0577: int i;
0578:
0579: for (i = 0; i < inStrings.length; i++)
0580: inStrings[i] = null;
0581: }
0582:
0583: /**
0584: * Sets the value of a parameter using an object; use the
0585: * <code>java.lang</code> equivalent objects for integral values.
0586: * <p>
0587: * The given Java object will be converted to the targetSqlType before being
0588: * sent to the database.
0589: * <p>
0590: * Note that this method may be used to pass database-specific abstract data
0591: * types. This is done by using a Driver-specific Java type and using a
0592: * <code>targetSqlType</code> of <code>java.sql.Types.OTHER</code>.
0593: *
0594: * @param parameterIndex the first parameter is 1...
0595: * @param x the object containing the input parameter value
0596: * @param targetSqlType The SQL type to be send to the database
0597: * @param scale for <code>java.sql.Types.DECIMAL</code> or
0598: * <code>java.sql.Types.NUMERIC</code> types this is the number of
0599: * digits after the decimal. For all other types this value will be
0600: * ignored.
0601: * @exception SQLException if a database access error or an incompatible type
0602: * match occurs
0603: * @see java.sql.PreparedStatement#setObject(int, java.lang.Object, int, int)
0604: */
0605: public void setObject(int parameterIndex, Object x,
0606: int targetSqlType, int scale) throws SQLException {
0607: if (x == null) {
0608: setNull(parameterIndex, targetSqlType);
0609: return;
0610: }
0611:
0612: try {
0613: boolean failed = false;
0614: switch (targetSqlType) {
0615: /**
0616: * Reference is table "Conversions Performed by setObject()..." in JDBC
0617: * Reference Book (table 47.9.5 in 2nd edition, 50.5 in 3rd edition).
0618: * Also available online in Sun's "JDBC Technology Guide: Getting
0619: * Started", section "Mapping SQL and Java Types".
0620: */
0621:
0622: // Some drivers (at least postgresql > 8.1) don't accept setInt for tiny
0623: // and small ints. We can safely use setShort instead. See bug
0624: // SEQUOIA-543
0625: // setShort().
0626: case Types.TINYINT:
0627: case Types.SMALLINT:
0628: if (x instanceof Number)
0629: setShort(parameterIndex, ((Number) x).shortValue());
0630: else if (x instanceof Boolean)
0631: setShort(parameterIndex, ((Boolean) x)
0632: .booleanValue() ? (short) 1 : (short) 0);
0633: else if (x instanceof String)
0634: setShort(parameterIndex, Short
0635: .parseShort((String) x));
0636: else
0637: failed = true;
0638: break;
0639: // setInt()
0640: case Types.INTEGER:
0641: if (x instanceof Number)
0642: setInt(parameterIndex, ((Number) x).intValue());
0643: else if (x instanceof Boolean)
0644: setInt(parameterIndex,
0645: ((Boolean) x).booleanValue() ? 1 : 0);
0646: else if (x instanceof String)
0647: setInt(parameterIndex, Integer.parseInt((String) x));
0648: else
0649: failed = true;
0650: break;
0651: // setLong()
0652: case Types.BIGINT:
0653: if (x instanceof Number)
0654: setLong(parameterIndex, ((Number) x).longValue());
0655: else if (x instanceof String)
0656: setLong(parameterIndex, Long.parseLong((String) x));
0657: else if (x instanceof Boolean)
0658: setLong(parameterIndex, ((Boolean) x)
0659: .booleanValue() ? 1 : 0);
0660: else
0661: failed = true;
0662: break;
0663: // setDouble()
0664: case Types.REAL:
0665: case Types.FLOAT:
0666: case Types.DOUBLE:
0667: if (x instanceof Number)
0668: setDouble(parameterIndex, ((Number) x)
0669: .doubleValue());
0670: else if (x instanceof String)
0671: setDouble(parameterIndex, Double
0672: .parseDouble((String) x));
0673: else if (x instanceof Boolean)
0674: setDouble(parameterIndex, ((Boolean) x)
0675: .booleanValue() ? 1 : 0);
0676: else
0677: failed = true;
0678: break;
0679: // setBigDecimal()
0680: case Types.DECIMAL:
0681: case Types.NUMERIC:
0682: BigDecimal bd;
0683: if (x instanceof Boolean)
0684: bd = new BigDecimal(
0685: ((Boolean) x).booleanValue() ? 1d : 0d);
0686: else if (x instanceof Number)
0687: bd = new BigDecimal(((Number) x).toString());
0688: else if (x instanceof String)
0689: bd = new BigDecimal((String) x);
0690: else {
0691: failed = true;
0692: break;
0693: }
0694: bd = bd.setScale(scale, BigDecimal.ROUND_HALF_UP);
0695: setBigDecimal(parameterIndex, bd);
0696: break;
0697: // setBoolean()
0698: case Types.BIT:
0699: case Types.BOOLEAN:
0700: if (x instanceof Number)
0701: setBoolean(parameterIndex, 0 != ((Number) x)
0702: .longValue());
0703: else if (x instanceof Boolean)
0704: setBoolean(parameterIndex, ((Boolean) x)
0705: .booleanValue());
0706: else if (x instanceof String)
0707: setBoolean(parameterIndex, Boolean.valueOf(
0708: (String) x).booleanValue());
0709: else
0710: failed = true;
0711: break;
0712: // setString()
0713: case Types.CHAR:
0714: case Types.VARCHAR:
0715: case Types.LONGVARCHAR:
0716: setString(parameterIndex, x.toString());
0717: break;
0718: // setBytes(), setBlob(),...
0719: case Types.BINARY:
0720: case Types.VARBINARY:
0721: case Types.LONGVARBINARY:
0722: if (x instanceof byte[])
0723: setBytes(parameterIndex, (byte[]) x);
0724: else if (x instanceof Blob)
0725: setBlob(parameterIndex, (Blob) x);
0726: else if (x instanceof Serializable)
0727: // Try it as an Object (serialized in bytes in setObject below)
0728: setObject(parameterIndex, x);
0729: else
0730: failed = true;
0731: break;
0732: // setDate()
0733: case Types.DATE:
0734: if (x instanceof String)
0735: setDate(parameterIndex, java.sql.Date
0736: .valueOf((String) x));
0737: else if (x instanceof java.sql.Date)
0738: setDate(parameterIndex, (java.sql.Date) x);
0739: else if (x instanceof Timestamp)
0740: setDate(parameterIndex, new java.sql.Date(
0741: ((Timestamp) x).getTime()));
0742: else
0743: failed = true;
0744: break;
0745: // setTime()
0746: case Types.TIME:
0747: if (x instanceof String)
0748: setTime(parameterIndex, Time.valueOf((String) x));
0749: else if (x instanceof Time)
0750: setTime(parameterIndex, (Time) x);
0751: else if (x instanceof Timestamp)
0752: setTime(parameterIndex, new Time(((Timestamp) x)
0753: .getTime()));
0754: else
0755: failed = true;
0756: break;
0757: // setTimeStamp()
0758: case Types.TIMESTAMP:
0759: if (x instanceof String)
0760: setTimestamp(parameterIndex, Timestamp
0761: .valueOf((String) x));
0762: else if (x instanceof Date)
0763: setTimestamp(parameterIndex, new Timestamp(
0764: ((Date) x).getTime()));
0765: else if (x instanceof Timestamp)
0766: setTimestamp(parameterIndex, (Timestamp) x);
0767: else
0768: failed = true;
0769: break;
0770: // setBlob()
0771: case Types.BLOB:
0772: if (x instanceof Blob)
0773: setBlob(parameterIndex, (Blob) x);
0774: else
0775: failed = true;
0776: break;
0777: // setURL()
0778: case Types.DATALINK:
0779: if (x instanceof java.net.URL)
0780: setURL(parameterIndex, (java.net.URL) x);
0781: else
0782: setURL(parameterIndex, new java.net.URL(x
0783: .toString()));
0784: break;
0785: case Types.JAVA_OBJECT:
0786: case Types.OTHER:
0787: // let's ignore the unknown target type given.
0788: setObject(parameterIndex, x);
0789: break;
0790: default:
0791: throw new SQLException("Unsupported type value");
0792: }
0793: if (true == failed)
0794: throw new IllegalArgumentException(
0795: "Attempt to perform an illegal conversion");
0796: } catch (Exception e) {
0797: SQLException outE = new SQLException(
0798: "Exception while converting type " + x.getClass()
0799: + " to SQL type " + targetSqlType);
0800: outE.initCause(e);
0801: throw outE;
0802: }
0803: }
0804:
0805: /**
0806: * @see java.sql.PreparedStatement#setObject(int, java.lang.Object, int)
0807: */
0808: public void setObject(int parameterIndex, Object x,
0809: int targetSqlType) throws SQLException {
0810: setObject(parameterIndex, x, targetSqlType, 0);
0811: }
0812:
0813: /**
0814: * This stores an Object parameter into the parameters array.
0815: *
0816: * @param parameterIndex the first parameter is 1...
0817: * @param x the object to set
0818: * @exception SQLException if a database access error occurs
0819: */
0820: public void setObject(int parameterIndex, Object x)
0821: throws SQLException {
0822: if (x == null) {
0823: setParameterWithTag(parameterIndex,
0824: PreparedStatementSerialization.OBJECT_TAG, null);
0825: } else { // This is an optimization, faster than going through
0826: // the generic setObject() method and calling instanceof again.
0827: // This has to be in the end equivalent to
0828: // setObject(index, object, DEFAULT_targetSqlType, 0)
0829: // where DEFAULT_targetSqlType is defined in table:
0830: // "Java Object Type Mapped to JDBC Types".
0831: // It's currently not exactly the same, since generic setObject()
0832: // is not strict enough in its conversions. For instance
0833: // setObject(target=Float) actually calls "setDouble()" -- MH.
0834:
0835: if (x instanceof String)
0836: setString(parameterIndex, (String) x);
0837: else if (x instanceof BigDecimal)
0838: setBigDecimal(parameterIndex, (BigDecimal) x);
0839: else if (x instanceof Boolean)
0840: setBoolean(parameterIndex, ((Boolean) x).booleanValue());
0841: else if (x instanceof Short)
0842: setShort(parameterIndex, ((Short) x).shortValue());
0843: else if (x instanceof Integer)
0844: setInt(parameterIndex, ((Integer) x).intValue());
0845: else if (x instanceof Long)
0846: setLong(parameterIndex, ((Long) x).longValue());
0847: else if (x instanceof Float)
0848: setFloat(parameterIndex, ((Float) x).floatValue());
0849: else if (x instanceof Double)
0850: setDouble(parameterIndex, ((Double) x).doubleValue());
0851: else if (x instanceof byte[])
0852: setBytes(parameterIndex, (byte[]) x);
0853: else if (x instanceof java.sql.Date)
0854: setDate(parameterIndex, (java.sql.Date) x);
0855: else if (x instanceof Time)
0856: setTime(parameterIndex, (Time) x);
0857: else if (x instanceof Timestamp)
0858: setTimestamp(parameterIndex, (Timestamp) x);
0859: else if (x instanceof Blob)
0860: setBlob(parameterIndex, (Blob) x);
0861: else if (x instanceof java.net.URL)
0862: setURL(parameterIndex, (java.net.URL) x);
0863: else if (x instanceof Serializable) {
0864: ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
0865: try {
0866: // Serialize object to byte array
0867: ObjectOutputStream objectOutputStream = new ObjectOutputStream(
0868: byteOutputStream);
0869: objectOutputStream.writeObject(x);
0870: objectOutputStream.close();
0871: synchronized (this .sbuf) {
0872: this .sbuf.setLength(0);
0873: /**
0874: * Encoded only for request inlining. Decoded right away by the
0875: * controller
0876: */
0877: this .sbuf
0878: .append(AbstractBlobFilter
0879: .getDefaultBlobFilter().encode(
0880: byteOutputStream
0881: .toByteArray()));
0882: setParameterWithTag(
0883: parameterIndex,
0884: PreparedStatementSerialization.OBJECT_TAG,
0885: trimStringBuffer());
0886: }
0887: } catch (IOException e) {
0888: throw new SQLException(
0889: "Failed to serialize object: " + e);
0890: }
0891: } else
0892: throw new SQLException("Objects of type "
0893: + x.getClass() + " are not supported.");
0894: }
0895: }
0896:
0897: /**
0898: * Some prepared statements return multiple results; the execute method
0899: * handles these complex statements as well as the simpler form of statements
0900: * handled by <code>executeQuery()</code> and <code>executeUpdate()</code>.
0901: *
0902: * @return <code>true</code> if the next result is a
0903: * <code>ResultSet<code>; <code>false<code> if it is an update count
0904: * or there are no more results
0905: * @exception SQLException if a database access error occurs
0906: */
0907: public boolean execute() throws SQLException {
0908: if (this .generatedKeysFlag == RETURN_GENERATED_KEYS) {
0909: if (connection.isAlwaysGettingGeneratedKeys()
0910: && !sql.toLowerCase().trim().startsWith("insert")) {
0911: return super .execute(sql, compileParameters(false));
0912: }
0913: int result = executeUpdate();
0914: resultList = new LinkedList();
0915: resultList.add(new Integer(result));
0916: resultListIterator = resultList.iterator();
0917: return getMoreResults();
0918: }
0919: return super .execute(sql, compileParameters(false));
0920: }
0921:
0922: /**
0923: * Returns the SQL statement with the current template values substituted.
0924: * <p>
0925: * <b>Note: </b>: This is identical to <code>compileQuery()</code> except
0926: * instead of throwing SQLException if a parameter is <code>null</code>, it
0927: * places ? instead.
0928: *
0929: * @return the SQL statement
0930: */
0931: public String toString() {
0932: synchronized (sbuf) {
0933: sbuf.setLength(0);
0934: sbuf.append(sql);
0935: int i;
0936:
0937: if (inStrings == null)
0938: return sbuf.toString();
0939:
0940: for (i = 0; i < inStrings.length; ++i) {
0941: if (inStrings[i] == null)
0942: sbuf.append('?');
0943: else
0944: sbuf.append(inStrings[i]);
0945: }
0946: return trimStringBuffer();
0947: }
0948: }
0949:
0950: // ** JDBC 2 Extensions **
0951:
0952: /**
0953: * This parses the query and adds it to the current batch
0954: *
0955: * @throws SQLException if an error occurs
0956: */
0957: public synchronized void addBatch() throws SQLException {
0958: if (batch == null)
0959: batch = new Vector();
0960: batch
0961: .addElement(new BatchElement(sql,
0962: compileParameters(false)));
0963: }
0964:
0965: /**
0966: * Execute a batch of commands
0967: *
0968: * @return an array containing update count that corresponding to the commands
0969: * that executed successfully
0970: * @exception BatchUpdateException if an error occurs on one statement (the
0971: * number of updated rows for the successfully executed
0972: * statements can be found in
0973: * BatchUpdateException.getUpdateCounts())
0974: */
0975: public int[] executeBatch() throws BatchUpdateException {
0976: if (batch == null || batch.isEmpty())
0977: return new int[0];
0978:
0979: int size = batch.size();
0980: int[] nbsRowsUpdated = new int[size];
0981: int i = 0;
0982:
0983: try {
0984: for (i = 0; i < size; i++) {
0985: BatchElement be = (BatchElement) batch.elementAt(i);
0986: nbsRowsUpdated[i] = this .executeUpdateWithSkeleton(be
0987: .getSqlTemplate(), be.getParameters());
0988: }
0989: return nbsRowsUpdated;
0990: } catch (SQLException e) {
0991: String message = "Batch failed for request "
0992: + i
0993: + ": "
0994: + ((BatchElement) batch.elementAt(i))
0995: .getSqlTemplate() + " (" + e + ")";
0996:
0997: // shrink the returned array
0998: int[] updateCounts = new int[i];
0999: System.arraycopy(nbsRowsUpdated, 0, updateCounts, 0, i);
1000:
1001: throw new BatchUpdateException(message, updateCounts);
1002: } finally {
1003: batch.removeAllElements();
1004: }
1005: }
1006:
1007: /**
1008: * Returns the <code>MetaData</code> for the last <code>ResultSet</code>
1009: * returned.
1010: *
1011: * @return The ResultSet Metadata
1012: * @throws SQLException if an error occurs
1013: */
1014: public java.sql.ResultSetMetaData getMetaData() throws SQLException {
1015: java.sql.ResultSet rs = getResultSet();
1016: if (rs != null)
1017: return rs.getMetaData();
1018: else
1019: return connection.preparedStatementGetMetaData(sql);
1020: }
1021:
1022: /**
1023: * @see java.sql.PreparedStatement#setArray(int, java.sql.Array)
1024: */
1025: public void setArray(int i, Array x) throws SQLException {
1026: throw new NotImplementedException("setArray()");
1027: }
1028:
1029: /**
1030: * @see java.sql.PreparedStatement#setBlob(int, Blob)
1031: */
1032: public void setBlob(int paramIndex, Blob sqlBlobParam)
1033: throws SQLException {
1034: if (sqlBlobParam == null) {
1035: setParameterWithTag(paramIndex,
1036: PreparedStatementSerialization.BLOB_TAG, null);
1037: return;
1038: }
1039:
1040: // sqlBlobParam.getBytes() seems limited in size ?
1041: // So we use .getBinaryStream()
1042: InputStream blobBinStream = sqlBlobParam.getBinaryStream();
1043:
1044: byte[] data = new byte[(int) sqlBlobParam.length()];
1045: try {
1046: blobBinStream.read(data, 0, (int) sqlBlobParam.length());
1047: } catch (Exception ioe) {
1048: throw new SQLException("Problem with data streaming");
1049: }
1050: try {
1051: synchronized (this .sbuf) {
1052: this .sbuf.setLength(0);
1053: /**
1054: * Encoded only for request inlining. Decoded right away by the
1055: * controller at static
1056: * {@link #setPreparedStatement(String, java.sql.PreparedStatement)}
1057: */
1058: this .sbuf.append(AbstractBlobFilter
1059: .getDefaultBlobFilter().encode(data));
1060: // this will make yet-another copy of the stringified blob.
1061: // as a short-term fix for SEQUOIA-106, we should inline this call.
1062: // The long term fix is to send binary parameters
1063: setParameterWithTag(paramIndex,
1064: PreparedStatementSerialization.BLOB_TAG,
1065: trimStringBuffer());
1066: }
1067: } catch (OutOfMemoryError oome) {
1068: this .sbuf = null;
1069: System.gc();
1070: throw new SQLException("Out of memory");
1071: }
1072: }
1073:
1074: /**
1075: * @see java.sql.PreparedStatement#setCharacterStream(int, java.io.Reader,
1076: * int)
1077: */
1078: public void setCharacterStream(int i, java.io.Reader x, int length)
1079: throws SQLException {
1080: char[] data = new char[length];
1081: try {
1082: x.read(data, 0, length);
1083: } catch (Exception ioe) {
1084: throw new SQLException("Problem with streaming of data");
1085: }
1086: setString(i, new String(data));
1087: }
1088:
1089: /**
1090: * @see java.sql.PreparedStatement#setClob(int, java.sql.Clob)
1091: */
1092: public void setClob(int i, java.sql.Clob clobArg)
1093: throws SQLException {
1094: String serializedParam = (clobArg == null ? null : clobArg
1095: .getSubString(0, (int) clobArg.length()));
1096:
1097: setParameterWithTag(i, PreparedStatementSerialization.CLOB_TAG,
1098: serializedParam);
1099: }
1100:
1101: /**
1102: * @see java.sql.PreparedStatement#setNull(int, int, java.lang.String)
1103: */
1104: public void setNull(int i, int t, String s) throws SQLException {
1105: setNull(i, t);
1106: }
1107:
1108: /**
1109: * @see java.sql.PreparedStatement#setRef(int, java.sql.Ref)
1110: */
1111: public void setRef(int i, Ref x) throws SQLException {
1112: String serializedParam = (x == null ? null : x.toString());
1113:
1114: setParameterWithTag(i, PreparedStatementSerialization.REF_TAG,
1115: serializedParam);
1116: }
1117:
1118: /**
1119: * @see java.sql.PreparedStatement#setDate(int, java.sql.Date,
1120: * java.util.Calendar)
1121: */
1122: public void setDate(int i, java.sql.Date d, java.util.Calendar cal)
1123: throws SQLException {
1124: if (d == null)
1125: setParameterWithTag(i,
1126: PreparedStatementSerialization.DATE_TAG, null);
1127: else {
1128: if (cal == null)
1129: setDate(i, d);
1130: else {
1131: cal.setTime(d);
1132: setDate(i, new java.sql.Date(cal.getTime().getTime()));
1133: }
1134: }
1135: }
1136:
1137: /**
1138: * @see java.sql.PreparedStatement#setTime(int, java.sql.Time,
1139: * java.util.Calendar)
1140: */
1141: public void setTime(int i, Time t, java.util.Calendar cal)
1142: throws SQLException {
1143: if (t == null)
1144: setParameterWithTag(i,
1145: PreparedStatementSerialization.TIME_TAG, null);
1146: else {
1147: if (cal == null)
1148: setTime(i, t);
1149: else {
1150: cal.setTime(t);
1151: setTime(i, new java.sql.Time(cal.getTime().getTime()));
1152: }
1153: }
1154: }
1155:
1156: /**
1157: * @see java.sql.PreparedStatement#setTimestamp(int, java.sql.Timestamp,
1158: * java.util.Calendar)
1159: */
1160: public void setTimestamp(int i, Timestamp t, java.util.Calendar cal)
1161: throws SQLException {
1162: if (t == null)
1163: setParameterWithTag(i,
1164: PreparedStatementSerialization.TIMESTAMP_TAG, null);
1165: else {
1166: if (cal == null)
1167: setTimestamp(i, t);
1168: else {
1169: cal.setTime(t);
1170: setTimestamp(i, new java.sql.Timestamp(cal.getTime()
1171: .getTime()));
1172: }
1173: }
1174: }
1175:
1176: // ------------------------- JDBC 3.0 -----------------------------------
1177:
1178: /**
1179: * Sets the designated parameter to the given <code>java.net.URL</code>
1180: * value. The driver converts this to an SQL <code>DATALINK</code> value
1181: * when it sends it to the database.
1182: *
1183: * @param parameterIndex the first parameter is 1, the second is 2, ...
1184: * @param x the <code>java.net.URL</code> object to be set
1185: * @exception SQLException if a database access error occurs
1186: * @since JDK 1.4
1187: */
1188: public void setURL(int parameterIndex, java.net.URL x)
1189: throws SQLException {
1190: String serializedParam = (x == null ? null : x.toString());
1191:
1192: setParameterWithTag(parameterIndex,
1193: PreparedStatementSerialization.URL_TAG, serializedParam);
1194: }
1195:
1196: /**
1197: * Retrieves the number, types and properties of this
1198: * <code>PreparedStatement</code> object's parameters.
1199: *
1200: * @return a <code>ParameterMetaData</code> object that contains information
1201: * about the number, types and properties of this
1202: * <code>PreparedStatement</code> object's parameters
1203: * @exception SQLException if a database access error occurs
1204: * @see ParameterMetaData
1205: * @since JDK 1.4
1206: */
1207: public ParameterMetaData getParameterMetaData() throws SQLException {
1208: throw new NotImplementedException("getParameterMetaData");
1209: }
1210:
1211: // **************************************************************
1212: // END OF PUBLIC INTERFACE
1213: // **************************************************************
1214:
1215: /**
1216: * Stores a parameter into parameters String array. Called by most setXXX()
1217: * methods.
1218: *
1219: * @param paramIndex the index into the inString
1220: * @param s a string to be stored
1221: * @exception SQLException if something goes wrong
1222: */
1223: protected void setParameter(int paramIndex, String s)
1224: throws SQLException {
1225: if (paramIndex < 1 || paramIndex > inStrings.length)
1226: throw new SQLException("Parameter index out of range.");
1227: inStrings[paramIndex - 1] = s;
1228: }
1229:
1230: /**
1231: * Return a stored parameter tag and value.
1232: *
1233: * @param paramIndex the index into the inString
1234: * @return a the parameter tag and the parameter value
1235: * @exception SQLException if something goes wrong
1236: */
1237: protected String[] getParameterTagAndValue(int paramIndex)
1238: throws SQLException {
1239: if (paramIndex < 1 || paramIndex > inStrings.length)
1240: throw new SQLException("Parameter index out of range.");
1241: int typeStart = PreparedStatementSerialization.START_PARAM_TAG
1242: .length();
1243:
1244: // Here we assume that all tags have the same length as the boolean tag.
1245: String tagString = inStrings[paramIndex - 1];
1246: String paramType = tagString.substring(typeStart, typeStart
1247: + PreparedStatementSerialization.BOOLEAN_TAG.length());
1248: String paramValue = tagString
1249: .substring(
1250: typeStart
1251: + PreparedStatementSerialization.BOOLEAN_TAG
1252: .length(),
1253: tagString
1254: .indexOf(PreparedStatementSerialization.END_PARAM_TAG));
1255: paramValue = Strings.replace(paramValue,
1256: PreparedStatementSerialization.TAG_MARKER_ESCAPE,
1257: PreparedStatementSerialization.TAG_MARKER);
1258: return new String[] { paramType, paramValue };
1259: }
1260:
1261: /**
1262: * Stores parameter and its type as a <em>quoted</em> String, so the
1263: * controller can decode them back.
1264: * <p>
1265: * We could avoid inlining the arguments and just tag them and send them apart
1266: * as an object list. But this would imply a couple of changes elsewhere,
1267: * among other: macro-handling, recoverylog,...
1268: *
1269: * @param paramIndex the index into the inString
1270: * @param typeTag type of the parameter
1271: * @param param the parameter string to be stored
1272: * @exception SQLException if something goes wrong
1273: * @see PreparedStatementSerialization#setPreparedStatement(String,
1274: * java.sql.PreparedStatement)
1275: */
1276: void setParameterWithTag(int paramIndex, String typeTag,
1277: String param) throws SQLException {
1278: if (isClosed())
1279: throw new SQLException(
1280: "Unable to set a parameter on a closed statement");
1281:
1282: /**
1283: * insert TAGS so the controller can parse and "unset" the request using
1284: * {@link #setPreparedStatement(String, java.sql.PreparedStatement)
1285: */
1286: if (param == null)
1287: param = PreparedStatementSerialization.NULL_VALUE;
1288: else
1289: // escape the markers in argument data
1290: param = Strings.replace(param,
1291: PreparedStatementSerialization.TAG_MARKER,
1292: PreparedStatementSerialization.TAG_MARKER_ESCAPE);
1293:
1294: setParameter(paramIndex, new String(
1295: PreparedStatementSerialization.START_PARAM_TAG
1296: + typeTag + param
1297: + PreparedStatementSerialization.END_PARAM_TAG));
1298: }
1299:
1300: /**
1301: * This class defines a BatchElement used for the batch update vector of
1302: * PreparedStatements to execute.
1303: *
1304: * @author <a href="mailto:emmanuel.cecchet@emicnetworks.com">Emmanuel Cecchet
1305: * </a>
1306: * @version 1.0
1307: */
1308: protected class BatchElement {
1309: private String sqlTemplate;
1310: private String parameters;
1311:
1312: /**
1313: * Creates a new <code>BatchElement</code> object
1314: *
1315: * @param sqlTemplate SQL query template (aka skeleton)
1316: * @param parameters prepared statement parameters
1317: */
1318: public BatchElement(String sqlTemplate, String parameters) {
1319: this .sqlTemplate = sqlTemplate;
1320: this .parameters = parameters;
1321: }
1322:
1323: /**
1324: * Returns the compiledSql value.
1325: *
1326: * @return Returns the compiledSql.
1327: */
1328: public String getParameters() {
1329: return parameters;
1330: }
1331:
1332: /**
1333: * Returns the sqlTemplate value.
1334: *
1335: * @return Returns the sqlTemplate.
1336: */
1337: public String getSqlTemplate() {
1338: return sqlTemplate;
1339: }
1340: }
1341: }
|