0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.jdbc.EmbedPreparedStatement
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. 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: */
0021:
0022: package org.apache.derby.impl.jdbc;
0023:
0024: import org.apache.derby.iapi.services.sanity.SanityManager;
0025:
0026: import org.apache.derby.iapi.types.VariableSizeDataValue;
0027:
0028: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0029: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0030: import org.apache.derby.iapi.sql.PreparedStatement;
0031: import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
0032: import org.apache.derby.iapi.sql.ResultSet;
0033: import org.apache.derby.iapi.sql.Activation;
0034: import org.apache.derby.iapi.sql.ParameterValueSet;
0035: import org.apache.derby.iapi.sql.ResultDescription;
0036: import org.apache.derby.iapi.types.DataTypeDescriptor;
0037: import org.apache.derby.iapi.types.DataValueDescriptor;
0038: import org.apache.derby.iapi.types.RawToBinaryFormatStream;
0039: import org.apache.derby.iapi.types.ReaderToUTF8Stream;
0040:
0041: import org.apache.derby.iapi.error.StandardException;
0042:
0043: import org.apache.derby.iapi.services.io.LimitReader;
0044:
0045: import org.apache.derby.iapi.reference.SQLState;
0046: import org.apache.derby.iapi.reference.JDBC40Translation;
0047: import org.apache.derby.iapi.reference.JDBC30Translation;
0048: import org.apache.derby.iapi.reference.JDBC20Translation;
0049:
0050: import java.util.Calendar;
0051: import java.util.Vector;
0052:
0053: /*
0054: We would import these, but have name-overlap
0055: import java.sql.PreparedStatement;
0056: import java.sql.ResultSet;
0057: */
0058: import java.sql.ResultSetMetaData;
0059: import java.sql.SQLException;
0060: import java.sql.Date;
0061: import java.sql.Time;
0062: import java.sql.Timestamp;
0063: import java.sql.Clob;
0064: import java.sql.Blob;
0065:
0066: import java.io.InputStream;
0067: import java.io.DataInputStream;
0068: import java.io.IOException;
0069: import java.io.EOFException;
0070: import java.io.Reader;
0071: import java.sql.Types;
0072:
0073: import org.apache.derby.iapi.jdbc.BrokeredConnectionControl;
0074: import org.apache.derby.iapi.jdbc.EngineParameterMetaData;
0075: import org.apache.derby.iapi.jdbc.EnginePreparedStatement;
0076:
0077: /**
0078: *
0079: * EmbedPreparedStatement is a local JDBC statement.
0080: <P><B>Supports</B>
0081: <UL>
0082: <LI> JSR169
0083: </UL>
0084: */
0085: public abstract class EmbedPreparedStatement extends EmbedStatement
0086: implements EnginePreparedStatement {
0087:
0088: //Moving jdbc2.0 batch related code in this class because callableStatement in jdbc 20 needs
0089: //this code too and it doesn't derive from prepared statement in jdbc 20 in our implementation.
0090:
0091: protected ResultSetMetaData rMetaData;
0092: //bug 4579-If the prepared statement was revalidated after doing getMetaData(), we
0093: //should get the metadata info again on next getMetaData(). We store the generated
0094: //class name in following variable during getMetaData() call. If it differs from the
0095: //current generated class name, then that indicates a refetch of metadata is required.
0096: private String gcDuringGetMetaData;
0097:
0098: protected PreparedStatement preparedStatement;
0099: private Activation activation;
0100:
0101: private BrokeredConnectionControl bcc = null;
0102:
0103: /*
0104: Constructor assumes caller will setup context stack
0105: and restore it.
0106: */
0107: public EmbedPreparedStatement(EmbedConnection conn, String sql,
0108: boolean forMetaData, int resultSetType,
0109: int resultSetConcurrency, int resultSetHoldability,
0110: int autoGeneratedKeys, int[] columnIndexes,
0111: String[] columnNames) throws SQLException {
0112:
0113: super (conn, forMetaData, resultSetType, resultSetConcurrency,
0114: resultSetHoldability);
0115: // PreparedStatement is poolable by default
0116: isPoolable = true;
0117:
0118: // if the sql string is null, raise an error
0119: if (sql == null)
0120: throw newSQLException(SQLState.NULL_SQL_TEXT);
0121:
0122: // set up the SQLText in EmbedStatement
0123: SQLText = sql;
0124:
0125: try {
0126: preparedStatement = lcc
0127: .prepareInternalStatement(
0128: lcc.getDefaultSchema(),
0129: sql,
0130: resultSetConcurrency == JDBC20Translation.CONCUR_READ_ONLY,
0131: forMetaData);
0132:
0133: addWarning(preparedStatement.getCompileTimeWarnings());
0134:
0135: activation = preparedStatement
0136: .getActivation(
0137: lcc,
0138: resultSetType == JDBC20Translation.TYPE_SCROLL_INSENSITIVE);
0139:
0140: checkRequiresCallableStatement(activation);
0141:
0142: //bug 4838 - save the auto-generated key information in activation. keeping this
0143: //information in lcc will not work work as it can be tampered by a nested trasaction
0144: if (autoGeneratedKeys == JDBC30Translation.RETURN_GENERATED_KEYS)
0145: activation.setAutoGeneratedKeysResultsetInfo(
0146: columnIndexes, columnNames);
0147:
0148: } catch (Throwable t) {
0149: throw handleException(t);
0150: }
0151: }
0152:
0153: /**
0154: JDBC states that a Statement is closed when garbage collected.
0155:
0156: @exception Throwable Allows any exception to be thrown during finalize
0157: */
0158: protected void finalize() throws Throwable {
0159: super .finalize();
0160:
0161: /*
0162: ** We mark the activation as not being used and
0163: ** that is it. We rely on the connection to sweep
0164: ** through the activations to find the ones that
0165: ** aren't in use, and to close them. We cannot
0166: ** do a activation.close() here because there are
0167: ** synchronized methods under close that cannot
0168: ** be called during finalization.
0169: */
0170: if (activation != null) {
0171: activation.markUnused();
0172: }
0173: }
0174:
0175: /*
0176: * Statement interface
0177: we override all Statement methods that take a SQL
0178: string as they must thrown an exception in a PreparedStatement.
0179: See the JDBC 3.0 spec.
0180: */
0181: public final boolean execute(String sql) throws SQLException {
0182: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0183: "execute(String)");
0184: }
0185:
0186: public final boolean execute(String sql, int autoGenKeys)
0187: throws SQLException {
0188: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0189: "execute(String, int)");
0190: }
0191:
0192: public final boolean execute(String sql, int[] columnIndexes)
0193: throws SQLException {
0194: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0195: "execute(String, int[])");
0196: }
0197:
0198: public final boolean execute(String sql, String[] columnNames)
0199: throws SQLException {
0200: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0201: "execute(String, String[])");
0202: }
0203:
0204: public final java.sql.ResultSet executeQuery(String sql)
0205: throws SQLException {
0206: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0207: "executeQuery(String)");
0208: }
0209:
0210: public final int executeUpdate(String sql) throws SQLException {
0211: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0212: "executeUpdate(String)");
0213: }
0214:
0215: public final int executeUpdate(String sql, int autoGenKeys)
0216: throws SQLException {
0217: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0218: "executeUpdate(String, int)");
0219: }
0220:
0221: public final int executeUpdate(String sql, int[] columnIndexes)
0222: throws SQLException {
0223: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0224: "executeUpdate(String, int[])");
0225: }
0226:
0227: public final int executeUpdate(String sql, String[] columnNames)
0228: throws SQLException {
0229: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0230: "executeUpdate(String, String[])");
0231: }
0232:
0233: public final void addBatch(String sql) throws SQLException {
0234: throw newSQLException(SQLState.NOT_FOR_PREPARED_STATEMENT,
0235: "addBatch(String)");
0236: }
0237:
0238: /**
0239: * Additional close to close our activation.
0240: * In the case that a XAConnection is involved in the creation of this
0241: * PreparedStatement for e.g in the following case
0242: *
0243: * <code>
0244: * XAConnection xaconn = xadatasource.getXAConnection();//where xadatasource is an object of XADataSource
0245: * Connection conn = xaconnection.getConnection();
0246: * PreparedStatement ps = conn.preparedStatement("values 1");
0247: * </code>
0248: *
0249: * In the above case the PreparedStatement will actually be a
0250: * BrokeredPreparedStatement40 object. Hence when we call
0251: * bcc.onStatementClose and pass the PreparedStatement that caused it
0252: * applicationStatement will be the appropriate choice since it will
0253: * contain the appropriate instance of PreparedStatement in each case
0254: *
0255: * @throws SQLException upon failure
0256: *
0257: */
0258: void closeActions() throws SQLException {
0259:
0260: if (bcc != null) {
0261: java.sql.PreparedStatement ps_app = (java.sql.PreparedStatement) applicationStatement;
0262: bcc.onStatementClose(ps_app);
0263: }
0264: //we release the resource for preparedStatement
0265: preparedStatement = null;
0266:
0267: try {
0268: setupContextStack();
0269: } catch (SQLException se) {
0270: //we may have already committed the transaction in which case
0271: //setupContextStack will fail, the close should just return
0272: return;
0273: }
0274: try {
0275: activation.close();
0276: activation = null;
0277: } catch (Throwable t) {
0278: throw handleException(t);
0279: } finally {
0280: restoreContextStack();
0281: }
0282: }
0283:
0284: /*
0285: * PreparedStatement interface; we have inherited from
0286: * EmbedStatement to get the Statement interface for
0287: * EmbedPreparedStatement (needed by PreparedStatement)
0288: * These are the JDBC interface comments, so we know
0289: * what to do.
0290: */
0291:
0292: /**
0293: * A prepared SQL query is executed and its ResultSet is returned.
0294: *
0295: * @return a ResultSet that contains the data produced by the
0296: * query; never null
0297: * @exception SQLException thrown on failure.
0298: */
0299: public final java.sql.ResultSet executeQuery() throws SQLException {
0300: try {
0301: executeStatement(activation, true, false);
0302: } catch (SQLException sqle) {
0303: checkStatementValidity(sqle);
0304: }
0305:
0306: if (SanityManager.DEBUG) {
0307: if (results == null)
0308: SanityManager
0309: .THROWASSERT("no results returned on executeQuery()");
0310: }
0311:
0312: return results;
0313: }
0314:
0315: /**
0316: * Execute a SQL INSERT, UPDATE or DELETE statement. In addition,
0317: * SQL statements that return nothing such as SQL DDL statements
0318: * can be executed.
0319: *
0320: * @return either the row count for INSERT, UPDATE or DELETE; or 0
0321: * for SQL statements that return nothing
0322: * @exception SQLException thrown on failure.
0323: */
0324: public final int executeUpdate() throws SQLException {
0325: try {
0326: executeStatement(activation, false, true);
0327: } catch (SQLException sqle) {
0328: checkStatementValidity(sqle);
0329: }
0330: return updateCount;
0331: }
0332:
0333: /**
0334: * Set a parameter to SQL NULL.
0335: *
0336: * <P><B>Note:</B> You must specify the parameter's SQL type.
0337: *
0338: * @param parameterIndex the first parameter is 1, the second is 2, ...
0339: * @param sqlType SQL type code defined by java.sql.Types
0340: * @exception SQLException thrown on failure.
0341: */
0342: public void setNull(int parameterIndex, int sqlType)
0343: throws SQLException {
0344:
0345: checkForSupportedDataType(sqlType);
0346: checkStatus();
0347:
0348: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0349:
0350: if (!DataTypeDescriptor.isJDBCTypeEquivalent(jdbcTypeId,
0351: sqlType)) {
0352:
0353: throw dataTypeConversion(parameterIndex, Util
0354: .typeName(sqlType));
0355: }
0356:
0357: try {
0358: /* JDBC is one-based, DBMS is zero-based */
0359: getParms().getParameterForSet(parameterIndex - 1)
0360: .setToNull();
0361: } catch (StandardException t) {
0362: throw EmbedResultSet.noStateChangeException(t);
0363: }
0364:
0365: }
0366:
0367: /**
0368: * Set a parameter to a Java boolean value. According to the JDBC API spec,
0369: * the driver converts this to a SQL BIT value when it sends it to the
0370: * database. But we don't have to do this, since the database engine
0371: * supports a boolean type.
0372: *
0373: * @param parameterIndex the first parameter is 1, the second is 2, ...
0374: * @param x the parameter value
0375: * @exception SQLException thrown on failure.
0376: */
0377: public void setBoolean(int parameterIndex, boolean x)
0378: throws SQLException {
0379:
0380: checkStatus();
0381: try {
0382: /* JDBC is one-based, DBMS is zero-based */
0383: getParms().getParameterForSet(parameterIndex - 1).setValue(
0384: x);
0385:
0386: } catch (StandardException t) {
0387: throw EmbedResultSet.noStateChangeException(t);
0388: }
0389: }
0390:
0391: /**
0392: * Set a parameter to a Java byte value. The driver converts this
0393: * to a SQL TINYINT value when it sends it to the database.
0394: *
0395: * @param parameterIndex the first parameter is 1, the second is 2, ...
0396: * @param x the parameter value
0397: * @exception SQLException thrown on failure.
0398: */
0399: public void setByte(int parameterIndex, byte x) throws SQLException {
0400:
0401: checkStatus();
0402: try {
0403:
0404: getParms().getParameterForSet(parameterIndex - 1).setValue(
0405: x);
0406:
0407: } catch (Throwable t) {
0408: throw EmbedResultSet.noStateChangeException(t);
0409: }
0410: }
0411:
0412: /**
0413: * Set a parameter to a Java short value. The driver converts this
0414: * to a SQL SMALLINT value when it sends it to the database.
0415: *
0416: * @param parameterIndex the first parameter is 1, the second is 2, ...
0417: * @param x the parameter value
0418: * @exception SQLException thrown on failure.
0419: */
0420: public void setShort(int parameterIndex, short x)
0421: throws SQLException {
0422:
0423: checkStatus();
0424: try {
0425: /* JDBC is one-based, DBMS is zero-based */
0426: getParms().getParameterForSet(parameterIndex - 1).setValue(
0427: x);
0428:
0429: } catch (Throwable t) {
0430: throw EmbedResultSet.noStateChangeException(t);
0431: }
0432: }
0433:
0434: /**
0435: * Set a parameter to a Java int value. The driver converts this
0436: * to a SQL INTEGER value when it sends it to the database.
0437: *
0438: * @param parameterIndex the first parameter is 1, the second is 2, ...
0439: * @param x the parameter value
0440: * @exception SQLException thrown on failure.
0441: */
0442: public void setInt(int parameterIndex, int x) throws SQLException {
0443: checkStatus();
0444:
0445: try {
0446: /* JDBC is one-based, DBMS is zero-based */
0447: getParms().getParameterForSet(parameterIndex - 1).setValue(
0448: x);
0449: } catch (Throwable t) {
0450: throw EmbedResultSet.noStateChangeException(t);
0451: }
0452: }
0453:
0454: /**
0455: * Set a parameter to a Java long value. The driver converts this
0456: * to a SQL BIGINT value when it sends it to the database.
0457: *
0458: * @param parameterIndex the first parameter is 1, the second is 2, ...
0459: * @param x the parameter value
0460: * @exception SQLException thrown on failure.
0461: */
0462: public void setLong(int parameterIndex, long x) throws SQLException {
0463: checkStatus();
0464: try {
0465: /* JDBC is one-based, DBMS is zero-based */
0466: getParms().getParameterForSet(parameterIndex - 1).setValue(
0467: x);
0468:
0469: } catch (Throwable t) {
0470: throw EmbedResultSet.noStateChangeException(t);
0471: }
0472:
0473: }
0474:
0475: /**
0476: * Set a parameter to a Java float value. The driver converts this
0477: * to a SQL FLOAT value when it sends it to the database.
0478: *
0479: * @param parameterIndex the first parameter is 1, the second is 2, ...
0480: * @param x the parameter value
0481: * @exception SQLException thrown on failure.
0482: */
0483: public void setFloat(int parameterIndex, float x)
0484: throws SQLException {
0485: checkStatus();
0486: try {
0487: /* JDBC is one-based, DBMS is zero-based */
0488: getParms().getParameterForSet(parameterIndex - 1).setValue(
0489: x);
0490:
0491: } catch (Throwable t) {
0492: throw EmbedResultSet.noStateChangeException(t);
0493: }
0494:
0495: }
0496:
0497: /**
0498: * Set a parameter to a Java double value. The driver converts this
0499: * to a SQL DOUBLE value when it sends it to the database.
0500: *
0501: * @param parameterIndex the first parameter is 1, the second is 2, ...
0502: * @param x the parameter value
0503: * @exception SQLException thrown on failure.
0504: */
0505: public void setDouble(int parameterIndex, double x)
0506: throws SQLException {
0507: checkStatus();
0508:
0509: try {
0510: /* JDBC is one-based, DBMS is zero-based */
0511: getParms().getParameterForSet(parameterIndex - 1).setValue(
0512: x);
0513:
0514: } catch (Throwable t) {
0515: throw EmbedResultSet.noStateChangeException(t);
0516: }
0517:
0518: }
0519:
0520: /**
0521: * Set a parameter to a Java String value. The driver converts this
0522: * to a SQL VARCHAR or LONGVARCHAR value (depending on the arguments
0523: * size relative to the driver's limits on VARCHARs) when it sends
0524: * it to the database.
0525: *
0526: * @param parameterIndex the first parameter is 1, the second is 2, ...
0527: * @param x the parameter value
0528: * @exception SQLException thrown on failure.
0529: */
0530: public void setString(int parameterIndex, String x)
0531: throws SQLException {
0532: checkStatus();
0533: try {
0534: /* JDBC is one-based, DBMS is zero-based */
0535: getParms().getParameterForSet(parameterIndex - 1).setValue(
0536: x);
0537:
0538: } catch (Throwable t) {
0539: throw EmbedResultSet.noStateChangeException(t);
0540: }
0541: }
0542:
0543: /**
0544: * Set a parameter to a Java array of bytes. The driver converts
0545: * this to a SQL VARBINARY or LONGVARBINARY (depending on the
0546: * argument's size relative to the driver's limits on VARBINARYs)
0547: * when it sends it to the database.
0548: *
0549: * @param parameterIndex the first parameter is 1, the second is 2, ...
0550: * @param x the parameter value
0551: * @exception SQLException thrown on failure.
0552: */
0553: public void setBytes(int parameterIndex, byte x[])
0554: throws SQLException {
0555: checkStatus();
0556:
0557: try {
0558: /* JDBC is one-based, DBMS is zero-based */
0559: getParms().getParameterForSet(parameterIndex - 1).setValue(
0560: x);
0561:
0562: } catch (Throwable t) {
0563: throw EmbedResultSet.noStateChangeException(t);
0564: }
0565:
0566: }
0567:
0568: /**
0569: * Set a parameter to a java.sql.Date value. The driver converts this
0570: * to a SQL DATE value when it sends it to the database.
0571: *
0572: * @param parameterIndex the first parameter is 1, the second is 2, ...
0573: * @param x the parameter value
0574: * @exception SQLException thrown on failure.
0575: */
0576: public void setDate(int parameterIndex, Date x) throws SQLException {
0577: setDate(parameterIndex, x, (Calendar) null);
0578: }
0579:
0580: /**
0581: * Set a parameter to a java.sql.Time value. The driver converts this
0582: * to a SQL TIME value when it sends it to the database.
0583: *
0584: * @param parameterIndex the first parameter is 1, the second is 2, ...
0585: * @param x the parameter value
0586: * @exception SQLException thrown on failure.
0587: */
0588: public void setTime(int parameterIndex, Time x) throws SQLException {
0589: setTime(parameterIndex, x, (Calendar) null);
0590: }
0591:
0592: /**
0593: * Set a parameter to a java.sql.Timestamp value. The driver
0594: * converts this to a SQL TIMESTAMP value when it sends it to the
0595: * database.
0596: *
0597: * @param parameterIndex the first parameter is 1, the second is 2, ...
0598: * @param x the parameter value
0599: * @exception SQLException thrown on failure.
0600: */
0601: public void setTimestamp(int parameterIndex, Timestamp x)
0602: throws SQLException {
0603: setTimestamp(parameterIndex, x, (Calendar) null);
0604: }
0605:
0606: /**
0607: * We do this inefficiently and read it all in here. The target type
0608: * is assumed to be a String.
0609: *
0610: * @param parameterIndex the first parameter is 1, the second is 2, ...
0611: * @param x the java input stream which contains the ASCII parameter value
0612: * @param length the number of bytes in the stream
0613: * @exception SQLException thrown on failure.
0614: */
0615: public final void setAsciiStream(int parameterIndex, InputStream x,
0616: long length) throws SQLException {
0617: checkAsciiStreamConditions(parameterIndex);
0618: java.io.Reader r = null;
0619:
0620: if (x != null) {
0621: // Use ISO-8859-1 and not US-ASCII as JDBC seems to define
0622: // ASCII as 8 bits. US-ASCII is 7.
0623: try {
0624: r = new java.io.InputStreamReader(x, "ISO-8859-1");
0625: } catch (java.io.UnsupportedEncodingException uee) {
0626: throw new SQLException(uee.getMessage());
0627: }
0628: }
0629:
0630: setCharacterStreamInternal(parameterIndex, r, false, length);
0631: }
0632:
0633: /**
0634: * We do this inefficiently and read it all in here. The target type
0635: * is assumed to be a String.
0636: *
0637: * @param parameterIndex the first parameter is 1, the second is 2, ...
0638: * @param x the java input stream which contains the ASCII parameter value
0639: * @param length the number of bytes in the stream
0640: * @exception SQLException thrown on failure.
0641: */
0642:
0643: public final void setAsciiStream(int parameterIndex, InputStream x,
0644: int length) throws SQLException {
0645: setAsciiStream(parameterIndex, x, (long) length);
0646: }
0647:
0648: /**
0649: Deprecated in JDBC 3.0
0650: *
0651: * @param parameterIndex the first parameter is 1, the second is 2, ...
0652: * @param x the java input stream which contains the
0653: * UNICODE parameter value
0654: * @param length the number of bytes in the stream
0655: * @exception SQLException thrown on failure.
0656: */
0657: public void setUnicodeStream(int parameterIndex, InputStream x,
0658: int length) throws SQLException {
0659: throw Util.notImplemented("setUnicodeStream");
0660: }
0661:
0662: /**
0663: * When a very large UNICODE value is input to a LONGVARCHAR
0664: * parameter, it may be more practical to send it via a
0665: * java.io.Reader. JDBC will read the data from the stream
0666: * as needed, until it reaches end-of-file. The JDBC driver will
0667: * do any necessary conversion from UNICODE to the database char format.
0668: *
0669: * <P><B>Note:</B> This stream object can either be a standard
0670: * Java stream object or your own subclass that implements the
0671: * standard interface.
0672: *
0673: * @param parameterIndex the first parameter is 1, the second is 2, ...
0674: * @param reader the java reader which contains the UNICODE data
0675: * @param length the number of characters in the stream
0676: * @exception SQLException if a database-access error occurs.
0677: */
0678: public final void setCharacterStream(int parameterIndex,
0679: java.io.Reader reader, long length) throws SQLException {
0680: checkCharacterStreamConditions(parameterIndex);
0681: setCharacterStreamInternal(parameterIndex, reader, false,
0682: length);
0683: }
0684:
0685: /**
0686: * When a very large UNICODE value is input to a LONGVARCHAR
0687: * parameter, it may be more practical to send it via a
0688: * java.io.Reader. JDBC will read the data from the stream
0689: * as needed, until it reaches end-of-file. The JDBC driver will
0690: * do any necessary conversion from UNICODE to the database char format.
0691: *
0692: * <P><B>Note:</B> This stream object can either be a standard
0693: * Java stream object or your own subclass that implements the
0694: * standard interface.
0695: *
0696: * @param parameterIndex the first parameter is 1, the second is 2, ...
0697: * @param reader the java reader which contains the UNICODE data
0698: * @param length the number of characters in the stream
0699: * @exception SQLException if a database-access error occurs.
0700: */
0701: public final void setCharacterStream(int parameterIndex,
0702: java.io.Reader reader, int length) throws SQLException {
0703: setCharacterStream(parameterIndex, reader, (long) length);
0704: }
0705:
0706: /**
0707: * Check general preconditions for setCharacterStream methods.
0708: *
0709: * @param parameterIndex 1-based index of the parameter.
0710: */
0711: private final void checkCharacterStreamConditions(int parameterIndex)
0712: throws SQLException {
0713: checkStatus();
0714: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0715: if (!DataTypeDescriptor.isCharacterStreamAssignable(jdbcTypeId)) {
0716: throw dataTypeConversion(parameterIndex, "java.io.Reader");
0717: }
0718: }
0719:
0720: /**
0721: * Check general preconditions for setAsciiStream methods.
0722: *
0723: * @param parameterIndex 1-based index of the parameter.
0724: */
0725: private final void checkAsciiStreamConditions(int parameterIndex)
0726: throws SQLException {
0727: checkStatus();
0728: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0729: if (!DataTypeDescriptor.isAsciiStreamAssignable(jdbcTypeId)) {
0730: throw dataTypeConversion(parameterIndex,
0731: "java.io.InputStream(ASCII)");
0732: }
0733: }
0734:
0735: /**
0736: * Set the given character stream for the specified parameter.
0737: *
0738: * If <code>lengthLess</code> is <code>true</code>, the following
0739: * conditions are either not checked or verified at the execution time
0740: * of the prepared statement:
0741: * <ol><li>If the stream length is negative.
0742: * <li>If the stream's actual length equals the specified length.</ol>
0743: * The <code>lengthLess</code> variable was added to differentiate between
0744: * streams with invalid lengths and streams without known lengths.
0745: *
0746: * @param parameterIndex the 1-based index of the parameter to set.
0747: * @param reader the data.
0748: * @param lengthLess tells whether we know the length of the data or not.
0749: * @param length the length of the data. Ignored if <code>lengthLess</code>
0750: * is <code>true</code>.
0751: */
0752: private void setCharacterStreamInternal(int parameterIndex,
0753: Reader reader, final boolean lengthLess, long length)
0754: throws SQLException {
0755: // Check for negative length if length is specified.
0756: if (!lengthLess && length < 0)
0757: throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH);
0758:
0759: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0760:
0761: if (reader == null) {
0762: setNull(parameterIndex, jdbcTypeId);
0763: return;
0764: }
0765:
0766: /*
0767: The value stored should not exceed the maximum value that can be
0768: stored in an integer
0769: This checking needs to be done because currently derby does not
0770: support Clob sizes greater than 2G-1
0771: */
0772: if (!lengthLess && length > Integer.MAX_VALUE)
0773: throw newSQLException(
0774: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
0775: getParameterSQLType(parameterIndex));
0776:
0777: try {
0778: ReaderToUTF8Stream utfIn;
0779: ParameterValueSet pvs = getParms();
0780: // Need column width to figure out if truncation is needed
0781: DataTypeDescriptor dtd[] = preparedStatement
0782: .getParameterTypes();
0783: int colWidth = dtd[parameterIndex - 1].getMaximumWidth();
0784: // Default to max column width. This will be used to limit the
0785: // amount of data read when operating on "lengthless" streams.
0786: int usableLength = colWidth;
0787:
0788: if (!lengthLess) {
0789: // We cast the length from long to int. This wouldn't be
0790: // appropriate if the limit of 2G-1 is decided to be increased
0791: // at a later stage.
0792: int intLength = (int) length;
0793: int truncationLength = 0;
0794:
0795: usableLength = intLength;
0796:
0797: // Currently long varchar does not allow for truncation of
0798: // trailing blanks.
0799: // For char and varchar types, current mechanism of
0800: // materializing when using streams seems fine given their max
0801: // limits.
0802: // This change is fix for DERBY-352: Insert of clobs using
0803: // streams should not materialize the entire stream into memory
0804: // In case of clobs, the truncation of trailing blanks is
0805: // factored in when reading from the stream without
0806: // materializing the entire stream, and so the special casing
0807: // for clob below.
0808: if (jdbcTypeId == Types.CLOB) {
0809:
0810: // It is possible that the length of the stream passed in
0811: // is greater than the column width, in which case the data
0812: // from the stream needs to be truncated.
0813: // usableLength is the length of the data from stream that
0814: // can be inserted which is min(colWidth,length) provided
0815: // length - colWidth has trailing blanks only
0816: // we have used intLength into which the length variable had
0817: // been cast to an int and stored
0818: if (intLength > colWidth) {
0819: usableLength = colWidth;
0820: truncationLength = intLength - usableLength;
0821: }
0822: }
0823: // Create a stream with truncation.
0824: utfIn = new ReaderToUTF8Stream(reader, usableLength,
0825: truncationLength,
0826: getParameterSQLType(parameterIndex));
0827: } else {
0828: // Create a stream without exactness checks,
0829: // but with a maximum limit.
0830: utfIn = new ReaderToUTF8Stream(reader, colWidth,
0831: getParameterSQLType(parameterIndex));
0832: }
0833:
0834: // JDBC is one-based, DBMS is zero-based.
0835: // Note that for lengthless stream, usableLength will be
0836: // the maximum length for the column.
0837: // This is okay, based on the observation that
0838: // setValue does not use the value for anything at all.
0839: pvs.getParameterForSet(parameterIndex - 1).setValue(utfIn,
0840: usableLength);
0841:
0842: } catch (StandardException t) {
0843: throw EmbedResultSet.noStateChangeException(t);
0844: }
0845: }
0846:
0847: /**
0848: * Sets the designated parameter to the given input stream.
0849: * When a very large binary value is input to a <code>LONGVARBINARY</code>
0850: * parameter, it may be more practical to send it via a
0851: * <code>java.io.InputStream</code> object. The data will be read from the
0852: * stream as needed until end-of-file is reached.
0853: *
0854: * <em>Note:</em> This stream object can either be a standard Java stream
0855: * object or your own subclass that implements the standard interface.
0856: *
0857: * @param parameterIndex the first parameter is 1, the second is 2, ...
0858: * @param x the java input stream which contains the binary parameter value
0859: * @throws SQLException if a database access error occurs or this method is
0860: * called on a closed <code>PreparedStatement</code>
0861: */
0862: public void setBinaryStream(int parameterIndex, InputStream x)
0863: throws SQLException {
0864: checkBinaryStreamConditions(parameterIndex);
0865: setBinaryStreamInternal(parameterIndex, x, true, -1);
0866: }
0867:
0868: /**
0869: * sets the parameter to the Binary stream
0870: *
0871: * @param parameterIndex the first parameter is 1, the second is 2, ...
0872: * @param x the java input stream which contains the binary parameter value
0873: * @param length the number of bytes in the stream
0874: * @exception SQLException thrown on failure.
0875: */
0876: public final void setBinaryStream(int parameterIndex,
0877: InputStream x, long length) throws SQLException {
0878: checkBinaryStreamConditions(parameterIndex);
0879: setBinaryStreamInternal(parameterIndex, x, false, length);
0880: }
0881:
0882: /**
0883: * sets the parameter to the binary stream
0884: *
0885: * @param parameterIndex the first parameter is 1, the second is 2, ...
0886: * @param x the java input stream which contains the binary parameter value
0887: * @param length the number of bytes in the stream
0888: * @exception SQLException thrown on failure.
0889: */
0890: public final void setBinaryStream(int parameterIndex,
0891: InputStream x, int length) throws SQLException {
0892: setBinaryStream(parameterIndex, x, (long) length);
0893: }
0894:
0895: /**
0896: * Set the given stream for the specified parameter.
0897: *
0898: * If <code>lengthLess</code> is <code>true</code>, the following
0899: * conditions are either not checked or verified at the execution time
0900: * of the prepared statement:
0901: * <ol><li>If the stream length is negative.
0902: * <li>If the stream's actual length equals the specified length.</ol>
0903: * The <code>lengthLess</code> variable was added to differentiate between
0904: * streams with invalid lengths and streams without known lengths.
0905: *
0906: * @param parameterIndex the 1-based index of the parameter to set.
0907: * @param x the data.
0908: * @param lengthLess tells whether we know the length of the data or not.
0909: * @param length the length of the data. Ignored if <code>lengthLess</code>
0910: * is <code>true</code>.
0911: */
0912: private void setBinaryStreamInternal(int parameterIndex,
0913: InputStream x, final boolean lengthLess, long length)
0914: throws SQLException {
0915:
0916: if (!lengthLess && length < 0)
0917: throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH);
0918:
0919: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0920: if (x == null) {
0921: setNull(parameterIndex, jdbcTypeId);
0922: return;
0923: }
0924:
0925: // max number of bytes that can be set to be inserted
0926: // in Derby is 2Gb-1 (ie Integer.MAX_VALUE).
0927: // (e.g into a blob column).
0928: // For now, we cast the length from long to int as a result.
0929: // If we ever decide to increase these limits for lets say blobs,
0930: // in that case the cast to int would not be appropriate.
0931: if (!lengthLess && length > Integer.MAX_VALUE) {
0932: throw newSQLException(
0933: SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE,
0934: getEmbedParameterSetMetaData()
0935: .getParameterTypeName(parameterIndex));
0936: }
0937:
0938: try {
0939: RawToBinaryFormatStream rawStream;
0940: if (lengthLess) {
0941: // Force length to -1 for good measure.
0942: length = -1;
0943: DataTypeDescriptor dtd[] = preparedStatement
0944: .getParameterTypes();
0945: rawStream = new RawToBinaryFormatStream(x,
0946: dtd[parameterIndex - 1].getMaximumWidth(),
0947: dtd[parameterIndex - 1].getTypeName());
0948: } else {
0949: rawStream = new RawToBinaryFormatStream(x, (int) length);
0950: }
0951: getParms().getParameterForSet(parameterIndex - 1).setValue(
0952: rawStream, (int) length);
0953:
0954: } catch (StandardException t) {
0955: throw EmbedResultSet.noStateChangeException(t);
0956: }
0957: }
0958:
0959: /**
0960: * Check general preconditions for setBinaryStream methods.
0961: *
0962: * @param parameterIndex 1-based index of the parameter.
0963: */
0964: private final void checkBinaryStreamConditions(int parameterIndex)
0965: throws SQLException {
0966: checkStatus();
0967: int jdbcTypeId = getParameterJDBCType(parameterIndex);
0968: if (!DataTypeDescriptor.isBinaryStreamAssignable(jdbcTypeId)) {
0969: throw dataTypeConversion(parameterIndex,
0970: "java.io.InputStream");
0971: }
0972: }
0973:
0974: /////////////////////////////////////////////////////////////////////////
0975: //
0976: // JDBC 2.0 - New public methods
0977: //
0978: /////////////////////////////////////////////////////////////////////////
0979:
0980: /**
0981: *
0982: * JDBC 2.0
0983: *
0984: * Sets the designated parameter to SQL <code>NULL</code>.
0985: * This version of the method <code>setNull</code> should
0986: * be used for user-defined types and REF type parameters. Examples
0987: * of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and
0988: * named array types.
0989: *
0990: * @param paramIndex the first parameter is 1, the second is 2, ...
0991: * @param sqlType a value from <code>java.sql.Types</code>
0992: * @param typeName the fully-qualified name of an SQL user-defined type;
0993: * ignored if the parameter is not a user-defined type or REF
0994: * @exception SQLException if a database access error occurs or
0995: * this method is called on a closed <code>PreparedStatement</code>
0996: * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
0997: * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
0998: * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
0999: * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
1000: * <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
1001: * or <code>STRUCT</code> data type and the JDBC driver does not support
1002: * this data type or if the JDBC driver does not support this method
1003: *
1004: */
1005: public void setNull(int paramIndex, int sqlType, String typeName)
1006: throws SQLException {
1007: setNull(paramIndex, sqlType);
1008: }
1009:
1010: /**
1011: * JDBC 2.0
1012: *
1013: * Add a set of parameters to the batch.
1014: *
1015: * @exception SQLException if a database-access error occurs.
1016: */
1017: public void addBatch() throws SQLException {
1018: checkStatus();
1019:
1020: // need to synchronized to ensure that two threads
1021: // don't both create a Vector at the same time. This
1022: // would lead to one of the set of parameters being thrown
1023: // away
1024: synchronized (getConnectionSynchronization()) {
1025: if (batchStatements == null)
1026: batchStatements = new Vector();
1027:
1028: //get a clone of the parameterValueSet and save it in the vector
1029: //which will be used later on at the time of batch execution.
1030: //This way we will get a copy of the current statement's parameter
1031: //values rather than a pointer to the statement's parameter value
1032: //set which will change with every new statement in the batch.
1033: batchStatements.addElement(getParms().getClone());
1034: clearParameters();
1035: }
1036: }
1037:
1038: boolean executeBatchElement(Object batchElement)
1039: throws SQLException, StandardException {
1040:
1041: ParameterValueSet temp = (ParameterValueSet) batchElement;
1042:
1043: int numberOfParameters = temp.getParameterCount();
1044:
1045: for (int j = 0; j < numberOfParameters; j++) {
1046: temp.getParameter(j).setInto(this , j + 1);
1047: }
1048:
1049: return super .executeStatement(activation, false, true);
1050: }
1051:
1052: /**
1053: * <P>In general, parameter values remain in force for repeated use of a
1054: * Statement. Setting a parameter value automatically clears its
1055: * previous value. However, in some cases it is useful to immediately
1056: * release the resources used by the current parameter values; this can
1057: * be done by calling clearParameters.
1058: * @exception SQLException thrown on failure.
1059: */
1060: public void clearParameters() throws SQLException {
1061: checkStatus();
1062:
1063: ParameterValueSet pvs = getParms();
1064: if (pvs != null)
1065: pvs.clearParameters();
1066: }
1067:
1068: /**
1069: * JDBC 2.0
1070: *
1071: * The number, types and properties of a ResultSet's columns
1072: * are provided by the getMetaData method.
1073: *
1074: * @return the description of a ResultSet's columns
1075: * @exception SQLException Feature not implemented for now.
1076: */
1077: public java.sql.ResultSetMetaData getMetaData() throws SQLException {
1078: checkExecStatus();
1079: synchronized (getConnectionSynchronization()) {
1080: //reason for casting is getActivationClass is not available on PreparedStatement
1081: ExecPreparedStatement execp = (ExecPreparedStatement) preparedStatement;
1082:
1083: setupContextStack(); // make sure there's context
1084:
1085: try {
1086: //bug 4579 - if the statement is invalid, regenerate the metadata info
1087: if (preparedStatement.isValid() == false) {
1088: //need to revalidate the statement here, otherwise getResultDescription would
1089: //still have info from previous valid statement
1090: preparedStatement.rePrepare(lcc);
1091: rMetaData = null;
1092: }
1093: //bug 4579 - gcDuringGetMetaData will be null if this is the first time
1094: //getMetaData call is made.
1095: //Second check - if the statement was revalidated since last getMetaData call,
1096: //then gcDuringGetMetaData wouldn't match with current generated class name
1097: if (gcDuringGetMetaData == null
1098: || gcDuringGetMetaData.equals(execp
1099: .getActivationClass().getName()) == false) {
1100: rMetaData = null;
1101: gcDuringGetMetaData = execp.getActivationClass()
1102: .getName();
1103: }
1104: if (rMetaData == null) {
1105: ResultDescription resd = preparedStatement
1106: .getResultDescription();
1107: if (resd != null) {
1108: // Internally, the result description has information
1109: // which is used for insert, update and delete statements
1110: // Externally, we decided that statements which don't
1111: // produce result sets such as insert, update and delete
1112: // should not return ResultSetMetaData. This is enforced
1113: // here
1114: String statementType = resd.getStatementType();
1115: if (statementType.equals("INSERT")
1116: || statementType.equals("UPDATE")
1117: || statementType.equals("DELETE"))
1118: rMetaData = null;
1119: else
1120: rMetaData = newEmbedResultSetMetaData(resd);
1121: }
1122: }
1123: } catch (Throwable t) {
1124: throw handleException(t);
1125: } finally {
1126: restoreContextStack();
1127: }
1128: }
1129: return rMetaData;
1130: }
1131:
1132: //----------------------------------------------------------------------
1133: // Advanced features:
1134:
1135: /**
1136: * The interface says that the type of the Object parameter must
1137: * be compatible with the type of the targetSqlType. We check that,
1138: * and if it flies, we expect the underlying engine to do the
1139: * required conversion once we pass in the value using its type.
1140: * So, an Integer converting to a CHAR is done via setInteger()
1141: * support on the underlying CHAR type.
1142: *
1143: * <p>If x is null, it won't tell us its type, so we pass it on to setNull
1144: *
1145: * @param parameterIndex The first parameter is 1, the second is 2, ...
1146: * @param x The object containing the input parameter value
1147: * @param targetSqlType The SQL type (as defined in java.sql.Types) to be
1148: * sent to the database. The scale argument may further qualify this type.
1149: * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
1150: * this is the number of digits after the decimal. For all other
1151: * types this value will be ignored,
1152: * @exception SQLException thrown on failure.
1153: */
1154: public final void setObject(int parameterIndex, Object x,
1155: int targetSqlType, int scale) throws SQLException {
1156:
1157: if (x == null) {
1158: setNull(parameterIndex, targetSqlType);
1159: return;
1160: }
1161:
1162: checkForSupportedDataType(targetSqlType);
1163:
1164: int paramJDBCType = getParameterJDBCType(parameterIndex);
1165:
1166: if (paramJDBCType != java.sql.Types.JAVA_OBJECT) {
1167: if (!DataTypeDescriptor.isJDBCTypeEquivalent(paramJDBCType,
1168: targetSqlType)) {
1169: throw dataTypeConversion(parameterIndex, Util
1170: .typeName(targetSqlType));
1171: }
1172: }
1173:
1174: setObject(parameterIndex, x);
1175:
1176: /*
1177: * If the parameter type is DECIMAL or NUMERIC, then
1178: * we need to set the correct scale or set it
1179: * to the default which is zero for setObject.
1180: */
1181: if ((paramJDBCType == Types.DECIMAL)
1182: || (paramJDBCType == Types.NUMERIC)) {
1183: setScale(parameterIndex, scale);
1184: }
1185: }
1186:
1187: /**
1188: * This method is like setObject above, but assumes a scale of zero.
1189: * @exception SQLException thrown on failure.
1190: */
1191: public final void setObject(int parameterIndex, Object x,
1192: int targetSqlType) throws SQLException {
1193: setObject(parameterIndex, x, targetSqlType, 0);
1194: }
1195:
1196: /**
1197: * <p>Set the value of a parameter using an object; use the
1198: * java.lang equivalent objects for integral values.
1199: *
1200: * <p>The JDBC specification specifies a standard mapping from
1201: * Java Object types to SQL types. The given argument java object
1202: * will be converted to the corresponding SQL type before being
1203: * sent to the database.
1204: *
1205: * <p>Note that this method may be used to pass datatabase
1206: * specific abstract data types, by using a Driver specific Java
1207: * type.
1208: *
1209: * @param parameterIndex The first parameter is 1, the second is 2, ...
1210: * @param x The object containing the input parameter value
1211: * @exception SQLException thrown on failure.
1212: */
1213: public final void setObject(int parameterIndex, Object x)
1214: throws SQLException {
1215: checkStatus();
1216:
1217: int colType = getParameterJDBCType(parameterIndex);
1218:
1219: // JDBC Tutorial and Reference books states in the PreparedStatement
1220: // overview, that passing a untyped null into setObject() is not allowed.
1221: // JCC disallows this, basically SQL can not handle a untyped NULL.
1222: // Section 25.1.6 (Third edition), 24.1.5 (Second Edition)
1223:
1224: if (x == null) {
1225: //setNull(parameterIndex, colType);
1226: //return;
1227: throw dataTypeConversion(parameterIndex, "null");
1228: }
1229:
1230: if (colType == org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT) {
1231: try {
1232: /* JDBC is one-based, DBMS is zero-based */
1233: getParms().setParameterAsObject(parameterIndex - 1, x);
1234: return;
1235:
1236: } catch (Throwable t) {
1237: throw EmbedResultSet.noStateChangeException(t);
1238: }
1239: }
1240:
1241: // Need to do instanceof checks here so that the behaviour
1242: // for these calls is consistent with the matching setXXX() value.
1243:
1244: // These are the supported setObject conversions from JDBC 3.0 table B5
1245: // Byte and Short were added to the table in JDBC 4.0.
1246:
1247: if (x instanceof String) {
1248: setString(parameterIndex, (String) x);
1249: return;
1250: }
1251:
1252: if (x instanceof Boolean) {
1253: setBoolean(parameterIndex, ((Boolean) x).booleanValue());
1254: return;
1255: }
1256: if (x instanceof Byte) {
1257: setByte(parameterIndex, ((Byte) x).byteValue());
1258: return;
1259: }
1260: if (x instanceof Short) {
1261: setShort(parameterIndex, ((Short) x).shortValue());
1262: return;
1263: }
1264: if (x instanceof Integer) {
1265: setInt(parameterIndex, ((Integer) x).intValue());
1266: return;
1267: }
1268: if (x instanceof Long) {
1269: setLong(parameterIndex, ((Long) x).longValue());
1270: return;
1271: }
1272:
1273: if (x instanceof Float) {
1274: setFloat(parameterIndex, ((Float) x).floatValue());
1275: return;
1276: }
1277: if (x instanceof Double) {
1278: setDouble(parameterIndex, ((Double) x).doubleValue());
1279: return;
1280: }
1281:
1282: if (x instanceof byte[]) {
1283: setBytes(parameterIndex, (byte[]) x);
1284: return;
1285: }
1286:
1287: if (x instanceof Date) {
1288: setDate(parameterIndex, (Date) x);
1289: return;
1290: }
1291: if (x instanceof Time) {
1292: setTime(parameterIndex, (Time) x);
1293: return;
1294: }
1295: if (x instanceof Timestamp) {
1296: setTimestamp(parameterIndex, (Timestamp) x);
1297: return;
1298: }
1299:
1300: if (x instanceof Blob) {
1301: setBlob(parameterIndex, (Blob) x);
1302: return;
1303: }
1304: if (x instanceof Clob) {
1305: setClob(parameterIndex, (Clob) x);
1306: return;
1307: }
1308:
1309: if (setObjectConvert(parameterIndex, x))
1310: return;
1311:
1312: throw dataTypeConversion(parameterIndex, x.getClass().getName());
1313:
1314: }
1315:
1316: /**
1317: Allow explict setObject conversions by sub-classes for classes
1318: not supported by this variant. E.g. BigDecimal
1319: This top-level implementation always returns false.
1320:
1321: @return true if the object was set successfully, false if no valid
1322: conversion exists.
1323:
1324: @exception SQLException value could not be set.
1325: */
1326: boolean setObjectConvert(int parameterIndex, Object x)
1327: throws SQLException {
1328: return false;
1329: }
1330:
1331: /**
1332: * @see java.sql.Statement#execute
1333: * @exception SQLException thrown on failure.
1334: */
1335: public final boolean execute() throws SQLException {
1336: boolean ret = false;
1337: try {
1338: ret = executeStatement(activation, false, false);
1339: } catch (SQLException sqle) {
1340: checkStatementValidity(sqle);
1341: }
1342: return ret;
1343: }
1344:
1345: /**
1346: * Set a parameter to a java.sql.Date value. The driver converts this
1347: * to a SQL DATE value when it sends it to the database.
1348: *
1349: * @param parameterIndex the first parameter is 1, the second is 2, ...
1350: * @param x the parameter value
1351: * @exception SQLException Feature not implemented for now.
1352: */
1353: public final void setDate(int parameterIndex, java.sql.Date x,
1354: Calendar cal) throws SQLException {
1355: checkStatus();
1356: try {
1357: /* JDBC is one-based, DBMS is zero-based */
1358: getParms().getParameterForSet(parameterIndex - 1).setValue(
1359: x, cal);
1360:
1361: } catch (Throwable t) {
1362: throw EmbedResultSet.noStateChangeException(t);
1363: }
1364: }
1365:
1366: /**
1367: * Set a parameter to a java.sql.Time value. The driver converts this
1368: * to a SQL TIME value when it sends it to the database.
1369: *
1370: * @param parameterIndex the first parameter is 1, the second is 2, ...
1371: * @param x the parameter value
1372: * @exception SQLException Feature not implemented for now.
1373: */
1374: public final void setTime(int parameterIndex, java.sql.Time x,
1375: Calendar cal) throws SQLException {
1376: checkStatus();
1377: try {
1378: /* JDBC is one-based, DBMS is zero-based */
1379: getParms().getParameterForSet(parameterIndex - 1).setValue(
1380: x, cal);
1381:
1382: } catch (Throwable t) {
1383: throw EmbedResultSet.noStateChangeException(t);
1384: }
1385: }
1386:
1387: /**
1388: * Set a parameter to a java.sql.Timestamp value. The driver
1389: * converts this to a SQL TIMESTAMP value when it sends it to the
1390: * database.
1391: *
1392: * @param parameterIndex the first parameter is 1, the second is 2, ...
1393: * @param x the parameter value
1394: * @exception SQLException Feature not implemented for now.
1395: */
1396: public final void setTimestamp(int parameterIndex,
1397: java.sql.Timestamp x, Calendar cal) throws SQLException {
1398: checkStatus();
1399: try {
1400: /* JDBC is one-based, DBMS is zero-based */
1401: getParms().getParameterForSet(parameterIndex - 1).setValue(
1402: x, cal);
1403:
1404: } catch (StandardException t) {
1405: throw EmbedResultSet.noStateChangeException(t);
1406: }
1407: }
1408:
1409: /**
1410: * JDBC 2.0
1411: *
1412: * Set a BLOB parameter.
1413: *
1414: * @param i the first parameter is 1, the second is 2, ...
1415: * @param x an object representing a BLOB
1416: */
1417: public void setBlob(int i, Blob x) throws SQLException {
1418: checkBlobConditions(i);
1419: if (x == null)
1420: setNull(i, Types.BLOB);
1421: else {
1422: // Note, x.length() needs to be called before retrieving the
1423: // stream using x.getBinaryStream() because EmbedBlob.length()
1424: // will read from the stream and drain some part of the stream
1425: // Hence the need to declare this local variable - streamLength
1426: long streamLength = x.length();
1427: setBinaryStreamInternal(i, x.getBinaryStream(), false,
1428: streamLength);
1429: }
1430: }
1431:
1432: /**
1433: * Check general (pre)conditions for setClob methods.
1434: *
1435: * @param parameterIndex 1-based index of the parameter.
1436: */
1437: private final void checkClobConditions(int parameterIndex)
1438: throws SQLException {
1439: checkStatus();
1440: if (getParameterJDBCType(parameterIndex) != Types.CLOB) {
1441: throw dataTypeConversion(parameterIndex, "java.sql.Clob");
1442: }
1443: }
1444:
1445: /**
1446: * JDBC 2.0
1447: *
1448: * Set a CLOB parameter.
1449: *
1450: * @param i the first parameter is 1, the second is 2, ...
1451: * @param x an object representing a CLOB
1452: */
1453: public void setClob(int i, Clob x) throws SQLException {
1454: checkClobConditions(i);
1455: if (x == null)
1456: setNull(i, Types.CLOB);
1457: else {
1458: // 1. max number of characters that can be inserted into a clob column
1459: // is 2Gb-1 which is Integer.MAX_INT.
1460: // This means that we do not allow any inserts of clobs where
1461: // clob.length() > Integer.MAX_INT. For now, we cast the x.length()
1462: // to int as a result. This will work ok for valid clob values that
1463: // derby supports. If we ever decide to increase these limits for clobs, in that
1464: // case the cast of x.Length() to int would not be appropriate.
1465: // 2. Note, x.length() needs to be called before retrieving the
1466: // stream using x.getCharacterStream() because EmbedClob.length()
1467: // will read from the stream and drain the stream.
1468: // Hence the need to declare this local variable - streamLength
1469: long streamLength = x.length();
1470:
1471: setCharacterStreamInternal(i, x.getCharacterStream(),
1472: false, streamLength);
1473: }
1474:
1475: }
1476:
1477: /**
1478: * Get the ParameterValueSet from the activation
1479: *
1480: *
1481: * @return The ParameterValueSet for the activation
1482: *
1483: */
1484: public final ParameterValueSet getParms() {
1485:
1486: return activation.getParameterValueSet();
1487: }
1488:
1489: /**
1490: Check the parameterINdex is in range and return the
1491: array of type descriptors.
1492:
1493: @exception SQLException parameter is out of range
1494: */
1495: protected final DataTypeDescriptor[] getTypes(int parameterIndex)
1496: throws SQLException {
1497:
1498: DataTypeDescriptor[] types = preparedStatement
1499: .getParameterTypes();
1500:
1501: if (types == null) {
1502: throw newSQLException(SQLState.NO_INPUT_PARAMETERS);
1503: }
1504:
1505: /* Check that the parameterIndex is in range. */
1506: if (parameterIndex < 1 || parameterIndex > types.length) {
1507:
1508: /* This message matches the one used by the DBMS */
1509: throw newSQLException(SQLState.LANG_INVALID_PARAM_POSITION,
1510: new Integer(parameterIndex), new Integer(
1511: types.length));
1512: }
1513: return types;
1514: }
1515:
1516: /**
1517: Get the target JDBC type for a parameter. Will throw exceptions
1518: if the parameter index is out of range
1519:
1520: @exception SQLException parameter is out of range
1521: */
1522: protected int getParameterJDBCType(int parameterIndex)
1523: throws SQLException {
1524:
1525: DataTypeDescriptor[] types = getTypes(parameterIndex);
1526:
1527: int type = types[parameterIndex - 1] == null ? Types.OTHER
1528: : types[parameterIndex - 1].getTypeId().getJDBCTypeId();
1529:
1530: if (SanityManager.DEBUG) {
1531: //int pmType = getEmbedParameterSetMetaData().getParameterType(parameterIndex);
1532: //if (type != pmType) {
1533: //SanityManager.THROWASSERT("MISMATCH PARAMETER META DATA param " + parameterIndex + " types " + type + " != " + pmType + "\n" + SQLText);
1534: //}
1535: }
1536:
1537: return type;
1538: }
1539:
1540: /**
1541: * Return the SQL type name for the parameter.
1542: *
1543: * @param parameterIndex the 1-based index of the parameter
1544: * @return SQL name of the parameter
1545: * @throws SQLException if parameter is out of range
1546: */
1547: protected final String getParameterSQLType(int parameterIndex)
1548: throws SQLException {
1549: DataTypeDescriptor[] pTypes = getTypes(parameterIndex);
1550: return pTypes[parameterIndex - 1].getTypeName();
1551: }
1552:
1553: /**
1554: * Set the scale of a parameter.
1555: *
1556: * @param parameterIndex The first parameter is 1, the second is 2, ...
1557: * @param scale The scale
1558: * @exception SQLException thrown on failure.
1559: */
1560: private void setScale(int parameterIndex, int scale)
1561: throws SQLException {
1562: checkStatus();
1563:
1564: if (scale < 0)
1565: throw newSQLException(SQLState.BAD_SCALE_VALUE,
1566: new Integer(scale));
1567:
1568: try {
1569:
1570: ParameterValueSet pvs = getParms();
1571:
1572: /* JDBC is one-based, DBMS is zero-based */
1573: DataValueDescriptor value = pvs
1574: .getParameter(parameterIndex - 1);
1575:
1576: int origvaluelen = value.getLength();
1577: ((VariableSizeDataValue) value).setWidth(
1578: VariableSizeDataValue.IGNORE_PRECISION, scale,
1579: false);
1580:
1581: if (value.getLength() < origvaluelen) {
1582: activation.addWarning(StandardException.newWarning(
1583: SQLState.LANG_VALUE_TRUNCATED, value
1584: .getString()));
1585: }
1586:
1587: } catch (StandardException t) {
1588: throw EmbedResultSet.noStateChangeException(t);
1589: }
1590: }
1591:
1592: /**
1593: * Immitate the function in JDBC 3.0
1594: *
1595: * Retrieves the number, types and properties of this PreparedStatement
1596: * object's parameters.
1597: *
1598: * @return a EngineParameterMetaData object that contains information about the
1599: * number, types and properties of this PreparedStatement object's parameters.
1600: * @exception SQLException if a database access error occurs
1601: */
1602: public EngineParameterMetaData getEmbedParameterSetMetaData()
1603: throws SQLException {
1604: checkExecStatus();
1605: return new EmbedParameterSetMetaData(getParms(),
1606: preparedStatement.getParameterTypes());
1607:
1608: }
1609:
1610: /**
1611: * JDBC 3.0
1612: *
1613: * Sets the designated parameter to the given java.net.URL value. The driver
1614: * converts this to an SQL DATALINK value when it sends it to the database.
1615: *
1616: * @param parameterIndex - the first parameter is 1, the second is 2, ...
1617: * @param x - the java.net.URL object to be set
1618: * @exception SQLException Feature not implemented for now.
1619: */
1620: public final void setURL(int parameterIndex, java.net.URL x)
1621: throws SQLException {
1622: throw Util.notImplemented();
1623: }
1624:
1625: //
1626: // methods to be overridden in subimplementations
1627: // that want to stay within their subimplementation.
1628: //
1629: protected EmbedResultSetMetaData newEmbedResultSetMetaData(
1630: ResultDescription resultDesc) {
1631:
1632: return factory.newEmbedResultSetMetaData(resultDesc
1633: .getColumnInfo());
1634: }
1635:
1636: public String toString() {
1637:
1638: if (activation != null)
1639: return activation.getPreparedStatement().getObjectName();
1640: return super .toString();
1641: }
1642:
1643: /*
1644: **
1645: */
1646: public void transferParameters(EmbedPreparedStatement newStatement)
1647: throws SQLException {
1648:
1649: try {
1650: newStatement.activation.setParameters(getParms(),
1651: preparedStatement.getParameterTypes());
1652: } catch (StandardException se) {
1653: throw EmbedResultSet.noStateChangeException(se);
1654: }
1655: }
1656:
1657: boolean executeStatement(Activation a, boolean executeQuery,
1658: boolean executeUpdate) throws SQLException {
1659:
1660: checkExecStatus();
1661: checkIfInMiddleOfBatch();
1662: clearResultSets();
1663: return super .executeStatement(a, executeQuery, executeUpdate);
1664: }
1665:
1666: final SQLException dataTypeConversion(int column, String sourceType)
1667: throws SQLException {
1668: SQLException se = newSQLException(
1669: SQLState.LANG_DATA_TYPE_GET_MISMATCH,
1670: getEmbedParameterSetMetaData().getParameterTypeName(
1671: column), sourceType);
1672: return se;
1673: }
1674:
1675: /*
1676: * This method is used to initialize the BrokeredConnectionControl
1677: * variable with its implementation. This method will be called in the
1678: * BrokeredConnectionControl class
1679: *
1680: * @param control used to call the onStatementClose and
1681: * onStatementErrorOccurred methods that have logic to
1682: * raise StatementEvents for the close and error events
1683: * on the PreparedStatement
1684: *
1685: */
1686: public void setBrokeredConnectionControl(
1687: BrokeredConnectionControl control) {
1688: bcc = control;
1689: }
1690:
1691: /*
1692: * Method calls onStatementError occurred on the
1693: * BrokeredConnectionControl class after checking the
1694: * SQLState of the SQLException thrown.
1695: *
1696: * In the case that a XAConnection is involved in the creation of this
1697: * PreparedStatement for e.g in the following case
1698: *
1699: * <code>
1700: * XAConnection xaconn = xadatasource.getXAConnection();//where xadatasource is an object of XADataSource
1701: * Connection conn = xaconnection.getConnection();
1702: * PreparedStatement ps = conn.preparedStatement("values 1");
1703: * </code>
1704: *
1705: * In the above case the PreparedStatement will actually be a
1706: * BrokeredPreparedStatement40 object. Hence when we call
1707: * bcc.onStatementClose and pass the PreparedStatement that caused it
1708: * applicationStatement will be the appropriate choice since it will
1709: * contain the appropriate instance of PreparedStatement in each case
1710: *
1711: */
1712:
1713: private void checkStatementValidity(SQLException sqle)
1714: throws SQLException {
1715: /*
1716: * Check if the exception has occurred because the connection
1717: * associated with the PreparedStatement has been closed
1718: */
1719: if (bcc != null && isClosed()) {
1720: //call the BrokeredConnectionControl interface method
1721: //onStatementErrorOccurred
1722: bcc.onStatementErrorOccurred(
1723: (java.sql.PreparedStatement) applicationStatement,
1724: sqle);
1725: }
1726: throw sqle;
1727: }
1728:
1729: /**
1730: * Checks whether a data type is supported for
1731: * <code>setObject(int, Object, int)</code> and
1732: * <code>setObject(int, Object, int, int)</code>.
1733: *
1734: * @param dataType the data type to check
1735: * @exception SQLException if the type is not supported
1736: */
1737: private void checkForSupportedDataType(int dataType)
1738: throws SQLException {
1739:
1740: // JDBC 4.0 javadoc for setObject() says:
1741: //
1742: // Throws: (...) SQLFeatureNotSupportedException - if
1743: // targetSqlType is a ARRAY, BLOB, CLOB, DATALINK,
1744: // JAVA_OBJECT, NCHAR, NCLOB, NVARCHAR, LONGNVARCHAR, REF,
1745: // ROWID, SQLXML or STRUCT data type and the JDBC driver does
1746: // not support this data type
1747: //
1748: // Of these types, we only support BLOB, CLOB and
1749: // (sort of) JAVA_OBJECT.
1750:
1751: switch (dataType) {
1752: case Types.ARRAY:
1753: case JDBC30Translation.DATALINK:
1754: case JDBC40Translation.NCHAR:
1755: case JDBC40Translation.NCLOB:
1756: case JDBC40Translation.NVARCHAR:
1757: case JDBC40Translation.LONGNVARCHAR:
1758: case Types.REF:
1759: case JDBC40Translation.ROWID:
1760: case JDBC40Translation.SQLXML:
1761: case Types.STRUCT:
1762: throw newSQLException(SQLState.DATA_TYPE_NOT_SUPPORTED,
1763: Util.typeName(dataType));
1764: }
1765: }
1766:
1767: //jdbc 4.0 methods
1768:
1769: /**
1770: * Sets the designated parameter to the given input stream.
1771: * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
1772: * parameter, it may be more practical to send it via a
1773: * <code>java.io.InputStream</code>. Data will be read from the stream as
1774: * needed until end-of-file is reached. The JDBC driver will do any
1775: * necessary conversion from ASCII to the database char format.
1776: *
1777: * <em>Note:</em> This stream object can either be a standard Java stream
1778: * object or your own subclass that implements the standard interface.
1779: *
1780: * @param parameterIndex the first parameter is 1, the second is 2, ...
1781: * @param x the Java input stream that contains the ASCII parameter value
1782: * @throws SQLException if a database access error occurs or this method is
1783: * called on a closed <code>PreparedStatement</code>
1784: */
1785: public void setAsciiStream(int parameterIndex, InputStream x)
1786: throws SQLException {
1787: checkAsciiStreamConditions(parameterIndex);
1788: java.io.Reader asciiStream = null;
1789:
1790: if (x != null) {
1791: // Use ISO-8859-1 and not US-ASCII as JDBC seems to define
1792: // ASCII as 8 bits. US-ASCII is 7.
1793: try {
1794: asciiStream = new java.io.InputStreamReader(x,
1795: "ISO-8859-1");
1796: } catch (java.io.UnsupportedEncodingException uee) {
1797: throw new SQLException(uee.getMessage());
1798: }
1799: }
1800:
1801: setCharacterStreamInternal(parameterIndex, asciiStream, true,
1802: -1);
1803: }
1804:
1805: /**
1806: * Sets the designated parameter to the given <code>Reader</code> object.
1807: * When a very large UNICODE value is input to a LONGVARCHAR parameter, it
1808: * may be more practical to send it via a <code>java.io.Reader</code>
1809: * object. The data will be read from the stream as needed until
1810: * end-of-file is reached. The JDBC driver will do any necessary conversion
1811: * from UNICODE to the database char format.
1812: *
1813: * <em>Note:</em> This stream object can either be a standard Java stream
1814: * object or your own subclass that implements the standard interface.
1815: *
1816: * Using this lengthless overload is not less effective than using one
1817: * where the stream length is specified, but since there is no length
1818: * specified, the exact length check will not be performed.
1819: *
1820: * @param parameterIndex the first parameter is 1, the second is 2, ...
1821: * @param reader the <code>java.io.Reader</code> object that contains the
1822: * Unicode data
1823: * @throws SQLException if a database access error occurs or this method is
1824: * called on a closed <code>PreparedStatement</code>
1825: */
1826: public void setCharacterStream(int parameterIndex, Reader reader)
1827: throws SQLException {
1828: checkCharacterStreamConditions(parameterIndex);
1829: setCharacterStreamInternal(parameterIndex, reader, true, -1);
1830: }
1831:
1832: /**
1833: * Sets the designated parameter to a <code>Reader</code> object.
1834: * This method differs from the <code>setCharacterStream(int,Reader)</code>
1835: * method because it informs the driver that the parameter value should be
1836: * sent to the server as a <code>CLOB</code>. When the
1837: * <code>setCharacterStream</code> method is used, the driver may have to
1838: * do extra work to determine whether the parameter data should be sent to
1839: * the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>.
1840: *
1841: * @param parameterIndex index of the first parameter is 1, the second is
1842: * 2, ...
1843: * @param reader an object that contains the data to set the parameter
1844: * value to.
1845: * @throws SQLException if a database access error occurs, this method is
1846: * called on a closed PreparedStatementor if parameterIndex does not
1847: * correspond to a parameter marker in the SQL statement
1848: */
1849: public void setClob(int parameterIndex, Reader reader)
1850: throws SQLException {
1851: checkClobConditions(parameterIndex);
1852: setCharacterStreamInternal(parameterIndex, reader, true, -1);
1853: }
1854:
1855: /**
1856: * Sets the designated parameter to a Reader object.
1857: *
1858: * @param parameterIndex index of the first parameter is 1, the second is 2, ...
1859: * @param reader An object that contains the data to set the parameter value to.
1860: * @param length the number of characters in the parameter data.
1861: * @throws SQLException if parameterIndex does not correspond to a parameter
1862: * marker in the SQL statement, or if the length specified is less than zero.
1863: *
1864: */
1865:
1866: public void setClob(int parameterIndex, Reader reader, long length)
1867: throws SQLException {
1868: checkClobConditions(parameterIndex);
1869: setCharacterStreamInternal(parameterIndex, reader, false,
1870: length);
1871: }
1872:
1873: /**
1874: * Sets the designated parameter to a <code>InputStream</code> object.
1875: * This method differs from the <code>setBinaryStream(int, InputStream)
1876: * </code> method because it informs the driver that the parameter value
1877: * should be sent to the server as a <code>BLOB</code>. When the
1878: * <code>setBinaryStream</code> method is used, the driver may have to do
1879: * extra work to determine whether the parameter data should be sent to the
1880: * server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
1881: *
1882: * @param parameterIndex index of the first parameter is 1, the second is
1883: * 2, ...
1884: * @param inputStream an object that contains the data to set the parameter
1885: * value to.
1886: * @throws SQLException if a database access error occurs, this method is
1887: * called on a closed <code>PreparedStatement</code> or if
1888: * <code>parameterIndex</code> does not correspond to a parameter
1889: * marker in the SQL statement
1890: */
1891: public void setBlob(int parameterIndex, InputStream inputStream)
1892: throws SQLException {
1893: checkBlobConditions(parameterIndex);
1894: setBinaryStreamInternal(parameterIndex, inputStream, true, -1);
1895: }
1896:
1897: /**
1898: * Sets the designated parameter to a InputStream object.
1899: *
1900: * @param parameterIndex index of the first parameter is 1,
1901: * the second is 2, ...
1902: * @param inputStream An object that contains the data to set the parameter
1903: * value to.
1904: * @param length the number of bytes in the parameter data.
1905: * @throws SQLException if parameterIndex does not correspond
1906: * to a parameter marker in the SQL statement, if the length specified
1907: * is less than zero or if the number of bytes in the inputstream does not match
1908: * the specfied length.
1909: */
1910:
1911: public void setBlob(int parameterIndex, InputStream inputStream,
1912: long length) throws SQLException {
1913: checkBlobConditions(parameterIndex);
1914: setBinaryStreamInternal(parameterIndex, inputStream, false,
1915: length);
1916: }
1917:
1918: /**
1919: * Check general (pre)conditions for setBlob methods.
1920: *
1921: * @param parameterIndex 1-based index of the parameter.
1922: */
1923: private final void checkBlobConditions(int parameterIndex)
1924: throws SQLException {
1925: checkStatus();
1926: if (getParameterJDBCType(parameterIndex) != Types.BLOB) {
1927: throw dataTypeConversion(parameterIndex, "java.sql.Blob");
1928: }
1929: }
1930: }
|