0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.jdbc.EmbedStatement
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.reference.JDBC20Translation;
0025: import org.apache.derby.iapi.reference.JDBC30Translation;
0026: import org.apache.derby.iapi.reference.SQLState;
0027:
0028: import org.apache.derby.iapi.services.sanity.SanityManager;
0029:
0030: import org.apache.derby.iapi.sql.Activation;
0031: import org.apache.derby.iapi.sql.PreparedStatement;
0032: import org.apache.derby.iapi.sql.ResultSet;
0033: import org.apache.derby.iapi.sql.ParameterValueSet;
0034: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0035: import org.apache.derby.iapi.error.StandardException;
0036: import org.apache.derby.iapi.jdbc.EngineStatement;
0037:
0038: import java.sql.SQLException;
0039: import java.sql.SQLWarning;
0040: import java.util.Vector;
0041:
0042: /*
0043: We would import these, but have name-overlap
0044: import java.sql.Statement;
0045: import java.sql.ResultSet;
0046: */
0047:
0048: /**
0049: *
0050: * EmbedStatement is a local JDBC statement.
0051: *
0052: <P><B>Supports</B>
0053: <UL>
0054: <LI> JSR169 - no subsetting for java.sql.Statement
0055: <LI> JDBC 2.0
0056: <LI> JDBC 3.0 - no new dependencies on new JDBC 3.0 or JDK 1.4 classes,
0057: new methods can safely be added into implementation.
0058: </UL>
0059:
0060: * @author ames
0061: */
0062: public class EmbedStatement extends ConnectionChild implements
0063: EngineStatement {
0064:
0065: private final java.sql.Connection applicationConnection;
0066:
0067: /**
0068: * Statement reference the application is using to execute
0069: * this Statement. Normally set to this, but if this was
0070: * created by a Connection from an XAConnection then this
0071: * will be a reference to the BrokeredStatement.
0072: *
0073: * Making it protected to allow access from EmbedPreparedStatement40
0074: * to be used for StatementEvents
0075: *
0076: */
0077: protected EngineStatement applicationStatement;
0078:
0079: int updateCount = -1;
0080: java.sql.ResultSet results;
0081: //for jdbc3.0 feature, where you can get a resultset of rows inserted
0082: //for auto generated columns after an insert
0083: private java.sql.ResultSet autoGeneratedKeysResultSet;
0084: private String cursorName;
0085:
0086: private final boolean forMetaData;
0087: final int resultSetType;
0088: private final int resultSetConcurrency;
0089: private final int resultSetHoldability;
0090: final LanguageConnectionContext lcc;
0091:
0092: private SQLWarning warnings;
0093: String SQLText;
0094:
0095: private int fetchSize = 1;
0096: private int fetchDirection = JDBC20Translation.FETCH_FORWARD;
0097: int MaxFieldSize;
0098: private int timeoutSeconds;
0099:
0100: //the state of this statement, set to false when close() is called
0101: private boolean active = true;
0102:
0103: //in case of batch update, save the individual statements in the batch in this vector
0104: //this is only used by JDBC 2.0
0105: Vector batchStatements;
0106:
0107: // The maximum # of rows to return per result set.
0108: // (0 means no limit.)
0109: int maxRows;
0110:
0111: private ParameterValueSet pvs;
0112:
0113: // An EmbedStatement is NOT poolable by default. The constructor for
0114: // PreparedStatement overrides this.
0115: protected boolean isPoolable = false;
0116:
0117: //
0118: // constructor
0119: //
0120: public EmbedStatement(EmbedConnection connection,
0121: boolean forMetaData, int resultSetType,
0122: int resultSetConcurrency, int resultSetHoldability) {
0123: super (connection);
0124: this .forMetaData = forMetaData;
0125: this .resultSetType = resultSetType;
0126: this .resultSetConcurrency = resultSetConcurrency;
0127: this .resultSetHoldability = resultSetHoldability;
0128:
0129: lcc = getEmbedConnection().getLanguageConnection();
0130: applicationConnection = getEmbedConnection()
0131: .getApplicationConnection();
0132: applicationStatement = this ;
0133:
0134: // By default, no statements time out.
0135: // Timeout is set explicitly with setQueryTimeout().
0136: timeoutSeconds = 0;
0137: }
0138:
0139: //
0140: // java.sql.Statement interface
0141: // the comments are those from the JDBC interface,
0142: // so we know what we're supposed to to.
0143:
0144: /**
0145: * Execute a SQL statement that returns a single ResultSet.
0146: *
0147: * @param sql typically this is a static SQL SELECT statement
0148: * @return a ResultSet that contains the data produced by the
0149: * query; never null
0150: * @exception SQLException thrown on failure.
0151: */
0152: public java.sql.ResultSet executeQuery(String sql)
0153: throws SQLException {
0154: execute(sql, true, false, JDBC30Translation.NO_GENERATED_KEYS,
0155: null, null);
0156:
0157: if (SanityManager.DEBUG) {
0158: if (results == null)
0159: SanityManager
0160: .THROWASSERT("no results returned on executeQuery()");
0161: }
0162:
0163: return results;
0164: }
0165:
0166: /**
0167: * Execute a SQL INSERT, UPDATE or DELETE statement. In addition,
0168: * SQL statements that return nothing such as SQL DDL statements
0169: * can be executed.
0170: *
0171: * @param sql a SQL INSERT, UPDATE or DELETE statement or a SQL
0172: * statement that returns nothing
0173: * @return either the row count for INSERT, UPDATE or DELETE; or 0
0174: * for SQL statements that return nothing
0175: * @exception SQLException thrown on failure.
0176: */
0177: public int executeUpdate(String sql) throws SQLException {
0178: execute(sql, false, true, JDBC30Translation.NO_GENERATED_KEYS,
0179: null, null);
0180: return updateCount;
0181: }
0182:
0183: /**
0184: * JDBC 3.0
0185: *
0186: * Execute the given SQL statement and signals the driver with the given flag
0187: * about whether the auto-generated keys produced by this Statement object
0188: * should be made available for retrieval.
0189: *
0190: * @param sql a SQL INSERT, UPDATE or DELETE statement or a SQL
0191: * statement that returns nothing
0192: * @param autoGeneratedKeys - a flag indicating whether auto-generated keys
0193: * should be made available for retrieval; one of the following constants:
0194: * Statement.RETURN_GENERATED_KEYS Statement.NO_GENERATED_KEYS
0195: * @return either the row count for INSERT, UPDATE or DELETE; or 0
0196: * for SQL statements that return nothing
0197: * @exception SQLException if a database access error occurs
0198: */
0199: public int executeUpdate(String sql, int autoGeneratedKeys)
0200: throws SQLException {
0201: execute(sql, false, true, autoGeneratedKeys, null, null);
0202: return updateCount;
0203: }
0204:
0205: /**
0206: * JDBC 3.0
0207: *
0208: * Executes the given SQL statement and signals the driver that the
0209: * auto-generated keys indicated in the given array should be made
0210: * available for retrieval. The driver will ignore the array if the SQL
0211: * statement is not an INSERT statement
0212: *
0213: * @param sql a SQL INSERT, UPDATE or DELETE statement or a SQL
0214: * statement that returns nothing
0215: * @param columnIndexes - an array of column indexes indicating the
0216: * columns that should be returned from the inserted row
0217: * @return either the row count for INSERT, UPDATE or DELETE; or 0
0218: * for SQL statements that return nothing
0219: * @exception SQLException if a database access error occurs
0220: */
0221: public int executeUpdate(String sql, int[] columnIndexes)
0222: throws SQLException {
0223: throw Util.notImplemented("executeUpdate(String, int[])");
0224: }
0225:
0226: /**
0227: * JDBC 3.0
0228: *
0229: * Executes the given SQL statement and signals the driver that the
0230: * auto-generated keys indicated in the given array should be made
0231: * available for retrieval. The driver will ignore the array if the SQL
0232: * statement is not an INSERT statement
0233: *
0234: * @param sql a SQL INSERT, UPDATE or DELETE statement or a SQL
0235: * statement that returns nothing
0236: * @param columnNames - an array of the names of the columns
0237: * that should be returned from the inserted row
0238: * @return either the row count for INSERT, UPDATE or DELETE; or 0
0239: * for SQL statements that return nothing
0240: * @exception SQLException if a database access error occurs
0241: */
0242: public int executeUpdate(String sql, String[] columnNames)
0243: throws SQLException {
0244: throw Util.notImplemented("executeUpdate(String, String[])");
0245: }
0246:
0247: final void checkIfInMiddleOfBatch() throws SQLException {
0248: /* If batchStatements is not null then we are in the middle
0249: * of a batch. That's an invalid state. We need to finish the
0250: * batch either by clearing the batch or executing the batch.
0251: * executeUpdate is not allowed inside the batch.
0252: */
0253: if (batchStatements != null)
0254: throw newSQLException(SQLState.MIDDLE_OF_BATCH);
0255: }
0256:
0257: /**
0258: * Tell whether this statment has been closed or not.
0259: *
0260: * @return <code>true</code> is closed, <code>false</code> otherwise.
0261: * @exception SQLException if a database access error occurs.
0262: */
0263: public boolean isClosed() throws SQLException {
0264: // If active, verify state by consulting parent connection.
0265: if (active) {
0266: try {
0267: checkExecStatus();
0268: } catch (SQLException sqle) {
0269: }
0270: }
0271: return !active;
0272: }
0273:
0274: /**
0275: * In many cases, it is desirable to immediately release a
0276: * Statements's database and JDBC resources instead of waiting for
0277: * this to happen when it is automatically closed; the close
0278: * method provides this immediate release.
0279: *
0280: * <P><B>Note:</B> A Statement is automatically closed when it is
0281: * garbage collected. When a Statement is closed its current
0282: * ResultSet, if one exists, is also closed.
0283: * @exception SQLException thrown on failure.
0284: */
0285: public final void close() throws SQLException {
0286:
0287: /* The close() method is the only method
0288: * that is allowed to be called on a closed
0289: * Statement, as per Jon Ellis.
0290: */
0291: if (!active) {
0292: return;
0293: }
0294:
0295: synchronized (getConnectionSynchronization()) {
0296:
0297: closeActions();
0298:
0299: //we first set the status
0300: active = false;
0301:
0302: //first, clear the resutl set
0303: clearResultSets();
0304:
0305: //next, release other resource
0306: cursorName = null;
0307: warnings = null;
0308: SQLText = null;
0309: batchStatements = null;
0310: }
0311: }
0312:
0313: // allow sub-classes to execute additional close
0314: // logic while holding the synchronization.
0315: void closeActions() throws SQLException {
0316: }
0317:
0318: //----------------------------------------------------------------------
0319:
0320: /**
0321: * The maxFieldSize limit (in bytes) is the maximum amount of data
0322: * returned for any column value; it only applies to BINARY,
0323: * VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR
0324: * columns. If the limit is exceeded, the excess data is silently
0325: * discarded.
0326: *
0327: * @return the current max column size limit; zero means unlimited
0328: * @exception SQLException thrown on failure.
0329: */
0330: public int getMaxFieldSize() throws SQLException {
0331: checkStatus();
0332:
0333: return MaxFieldSize;
0334: }
0335:
0336: /**
0337: * The maxFieldSize limit (in bytes) is set to limit the size of
0338: * data that can be returned for any column value; it only applies
0339: * to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and
0340: * LONGVARCHAR fields. If the limit is exceeded, the excess data
0341: * is silently discarded.
0342: *
0343: * @param max the new max column size limit; zero means unlimited
0344: * @exception SQLException thrown on failure.
0345: */
0346: public void setMaxFieldSize(int max) throws SQLException {
0347: checkStatus();
0348:
0349: if (max < 0) {
0350: throw newSQLException(SQLState.INVALID_MAXFIELD_SIZE,
0351: new Integer(max));
0352: }
0353: this .MaxFieldSize = max;
0354: }
0355:
0356: /**
0357: * The maxRows limit is the maximum number of rows that a
0358: * ResultSet can contain. If the limit is exceeded, the excess
0359: * rows are silently dropped.
0360: *
0361: * @return the current max row limit; zero means unlimited
0362: * @exception SQLException thrown on failure.
0363: */
0364: public int getMaxRows() throws SQLException {
0365: checkStatus();
0366: return maxRows;
0367: }
0368:
0369: /**
0370: * The maxRows limit is set to limit the number of rows that any
0371: * ResultSet can contain. If the limit is exceeded, the excess
0372: * rows are silently dropped.
0373: *
0374: * @param max the new max rows limit; zero means unlimited
0375: * @exception SQLException thrown on failure.
0376: */
0377: public void setMaxRows(int max) throws SQLException {
0378: checkStatus();
0379: if (max < 0) {
0380: throw newSQLException(SQLState.INVALID_MAX_ROWS_VALUE,
0381: new Integer(max));
0382: }
0383: this .maxRows = max;
0384: }
0385:
0386: /**
0387: * If escape scanning is on (the default) the driver will do
0388: * escape substitution before sending the SQL to the database.
0389: *
0390: * @param enable true to enable; false to disable
0391: * @exception SQLException thrown on failure.
0392: */
0393: public void setEscapeProcessing(boolean enable) throws SQLException {
0394: checkStatus();
0395: // Nothing to do in our server , just ignore it.
0396:
0397: }
0398:
0399: /**
0400: * The queryTimeout limit is the number of seconds the driver will
0401: * wait for a Statement to execute. If the limit is exceeded a
0402: * SQLException is thrown.
0403: *
0404: * @return the current query timeout limit in seconds; zero means unlimited
0405: * @exception SQLException thrown on failure.
0406: */
0407: public final int getQueryTimeout() throws SQLException {
0408: checkStatus();
0409: return timeoutSeconds;
0410: }
0411:
0412: /**
0413: * The queryTimeout limit is the number of seconds the driver will
0414: * wait for a Statement to execute. If the limit is exceeded a
0415: * SQLException is thrown.
0416: *
0417: * @param seconds the new query timeout limit in seconds; zero means unlimited
0418: * @exception SQLException thrown on failure.
0419: */
0420: public final void setQueryTimeout(int seconds) throws SQLException {
0421: checkStatus();
0422: if (seconds < 0) {
0423: throw newSQLException(SQLState.INVALID_QUERYTIMEOUT_VALUE,
0424: new Integer(seconds));
0425: }
0426: timeoutSeconds = seconds;
0427: }
0428:
0429: /**
0430: * Cancel can be used by one thread to cancel a statement that
0431: * is being executed by another thread.
0432: * @exception SQLException thrown on failure.
0433: */
0434: public void cancel() throws SQLException {
0435: throw Util.notImplemented("cancel");
0436: }
0437:
0438: /**
0439: * The first warning reported by calls on this Statement is
0440: * returned. A Statment's execute methods clear its SQLWarning
0441: * chain. Subsequent Statement warnings will be chained to this
0442: * SQLWarning.
0443: *
0444: * <p>The warning chain is automatically cleared each time
0445: * a statement is (re)executed.
0446: *
0447: * <P><B>Note:</B> If you are processing a ResultSet then any
0448: * warnings associated with ResultSet reads will be chained on the
0449: * ResultSet object.
0450: *
0451: * @return the first SQLWarning or null
0452: * @exception SQLException thrown on failure.
0453: */
0454: public SQLWarning getWarnings() throws SQLException {
0455: checkStatus();
0456: return warnings;
0457: }
0458:
0459: /**
0460: * After this call getWarnings returns null until a new warning is
0461: * reported for this Statement.
0462: * @exception SQLException thrown on failure.
0463: */
0464: public void clearWarnings() throws SQLException {
0465: checkStatus();
0466: warnings = null;
0467: }
0468:
0469: /**
0470: * setCursorName defines the SQL cursor name that will be used by
0471: * subsequent Statement execute methods. This name can then be
0472: * used in SQL positioned update/delete statements to identify the
0473: * current row in the ResultSet generated by this statement. If
0474: * the database doesn't support positioned update/delete, this
0475: * method is a noop.
0476: *
0477: * <P><B>Note:</B> By definition, positioned update/delete
0478: * execution must be done by a different Statement than the one
0479: * which generated the ResultSet being used for positioning. Also,
0480: * cursor names must be unique within a Connection.
0481: *
0482: * @param name the new cursor name.
0483: */
0484: public void setCursorName(String name) throws SQLException {
0485: checkStatus();
0486: cursorName = name;
0487: }
0488:
0489: //----------------------- Multiple Results --------------------------
0490:
0491: /**
0492: * Execute a SQL statement that may return multiple results.
0493: * Under some (uncommon) situations a single SQL statement may return
0494: * multiple result sets and/or update counts. Normally you can ignore
0495: * this, unless you're executing a stored procedure that you know may
0496: * return multiple results, or unless you're dynamically executing an
0497: * unknown SQL string. The "execute", "getMoreResults", "getResultSet"
0498: * and "getUpdateCount" methods let you navigate through multiple results.
0499: *
0500: * The "execute" method executes a SQL statement and indicates the
0501: * form of the first result. You can then use getResultSet or
0502: * getUpdateCount to retrieve the result, and getMoreResults to
0503: * move to any subsequent result(s).
0504: *
0505: * @param sql any SQL statement
0506: *
0507: * @return true if the first result is a ResultSet; false if it is an integer
0508: * @see #getResultSet
0509: * @see #getUpdateCount
0510: * @see #getMoreResults
0511: * @exception SQLException thrown on failure
0512: */
0513: public boolean execute(String sql) throws SQLException {
0514: return execute(sql, false, false,
0515: JDBC30Translation.NO_GENERATED_KEYS, null, null);
0516: }
0517:
0518: /**
0519: * Execute a SQL statement that may return multiple results.
0520: * Under some (uncommon) situations a single SQL statement may return
0521: * multiple result sets and/or update counts. Normally you can ignore
0522: * this, unless you're executing a stored procedure that you know may
0523: * return multiple results, or unless you're dynamically executing an
0524: * unknown SQL string. The "execute", "getMoreResults", "getResultSet"
0525: * and "getUpdateCount" methods let you navigate through multiple results.
0526: *
0527: * The "execute" method executes a SQL statement and indicates the
0528: * form of the first result. You can then use getResultSet or
0529: * getUpdateCount to retrieve the result, and getMoreResults to
0530: * move to any subsequent result(s).
0531: *
0532: * @param sql any SQL statement
0533: * @param executeQuery caller is executeQuery()
0534: * @param executeUpdate caller is executeUpdate()
0535: * @param autoGeneratedKeys
0536: * @param columnIndexes
0537: * @param columnNames
0538: *
0539: * @return true if the first result is a ResultSet; false if it is an integer
0540: * @see #getResultSet
0541: * @see #getUpdateCount
0542: * @see #getMoreResults
0543: * @exception SQLException thrown on failure
0544: */
0545: private boolean execute(String sql, boolean executeQuery,
0546: boolean executeUpdate, int autoGeneratedKeys,
0547: int[] columnIndexes, String[] columnNames)
0548: throws SQLException {
0549: synchronized (getConnectionSynchronization()) {
0550:
0551: checkExecStatus();
0552: if (sql == null) {
0553: throw newSQLException(SQLState.NULL_SQL_TEXT);
0554: }
0555: checkIfInMiddleOfBatch();
0556: clearResultSets(); // release the last statement executed, if any.
0557:
0558: setupContextStack(); // make sure there's context
0559:
0560: // try to remember the SQL statement in case anybody asks for it
0561: SQLText = sql;
0562:
0563: try {
0564: Activation activation;
0565: try {
0566: PreparedStatement preparedStatement = lcc
0567: .prepareInternalStatement(
0568: lcc.getDefaultSchema(),
0569: sql,
0570: resultSetConcurrency == JDBC20Translation.CONCUR_READ_ONLY,
0571: false);
0572: activation = preparedStatement
0573: .getActivation(
0574: lcc,
0575: resultSetType == JDBC20Translation.TYPE_SCROLL_INSENSITIVE);
0576: checkRequiresCallableStatement(activation);
0577: } catch (Throwable t) {
0578: throw handleException(t);
0579: }
0580:
0581: // this is for a Statement execution
0582: activation.setSingleExecution();
0583:
0584: //bug 4838 - save the auto-generated key information in activation. keeping this
0585: //information in lcc will not work work it can be tampered by a nested trasaction
0586: if (autoGeneratedKeys == JDBC30Translation.RETURN_GENERATED_KEYS)
0587: activation.setAutoGeneratedKeysResultsetInfo(
0588: columnIndexes, columnNames);
0589: return executeStatement(activation, executeQuery,
0590: executeUpdate);
0591: } finally {
0592: restoreContextStack();
0593: }
0594: }
0595: }
0596:
0597: /**
0598: * JDBC 3.0
0599: *
0600: * Executes the given SQL statement, which may return multiple
0601: * results, and signals the driver that any auto-generated keys
0602: * should be made available for retrieval. The driver will ignore
0603: * this signal if the SQL statement is not an INSERT statement.
0604: *
0605: * @param sql any SQL statement
0606: * @param autoGeneratedKeys - a constant indicating whether
0607: * auto-generated keys should be made available for retrieval using
0608: * the method getGeneratedKeys; one of the following constants:
0609: * Statement.RETURN_GENERATED_KEYS or Statement.NO_GENERATED_KEYS
0610: * @return rue if the first result is a ResultSet object; false if
0611: * it is an update count or there are no results
0612: * @exception SQLException if a database access error occurs
0613: */
0614: public boolean execute(String sql, int autoGeneratedKeys)
0615: throws SQLException {
0616: return execute(sql, false, false, autoGeneratedKeys, null, null);
0617: }
0618:
0619: /**
0620: * JDBC 3.0
0621: *
0622: * Executes the given SQL statement, which may return multiple
0623: * results, and signals the driver that the auto-generated keys
0624: * indicated in the given array should be made available for retrieval.
0625: * This array contains the indexes of the columns in the target table
0626: * that contain the auto-generated keys that should be made available.
0627: * The driver will ignore the array if the given SQL statement is not an
0628: * INSERT statement.
0629: *
0630: * @param sql any SQL statement
0631: * @param columnIndexes - an array of the indexes of the columns in the
0632: * inserted row that should be made available for retrieval by a call to
0633: * the method getGeneratedKeys
0634: * @return rue if the first result is a ResultSet object; false if
0635: * it is an update count or there are no results
0636: * @exception SQLException if a database access error occurs
0637: */
0638: public boolean execute(String sql, int[] columnIndexes)
0639: throws SQLException {
0640: throw Util.notImplemented("execute(String, int[])");
0641: }
0642:
0643: /**
0644: * JDBC 3.0
0645: *
0646: * Executes the given SQL statement, which may return multiple
0647: * results, and signals the driver that the auto-generated keys
0648: * indicated in the given array should be made available for retrieval.
0649: * This array contains the names of the columns in the target table
0650: * that contain the auto-generated keys that should be made available.
0651: * The driver will ignore the array if the given SQL statement is not an
0652: * INSERT statement.
0653: *
0654: * @param sql any SQL statement
0655: * @param columnNames - an array of the names of the columns in the
0656: * inserted row that should be made available for retrieval by a call to
0657: * the method getGeneratedKeys
0658: * @return rue if the first result is a ResultSet object; false if
0659: * it is an update count or there are no results
0660: * @exception SQLException if a database access error occurs
0661: */
0662: public boolean execute(String sql, String[] columnNames)
0663: throws SQLException {
0664: throw Util.notImplemented("execute(String, String[])");
0665: }
0666:
0667: /**
0668: * getResultSet returns the current result as a ResultSet. It
0669: * should only be called once per result.
0670: *
0671: * @return the current result as a ResultSet; null if the result
0672: * is an update count or there are no more results or the statement
0673: * was closed.
0674: * @see #execute
0675: */
0676: public final java.sql.ResultSet getResultSet() throws SQLException {
0677: checkStatus();
0678:
0679: return results;
0680: }
0681:
0682: /**
0683: * getUpdateCount returns the current result as an update count;
0684: * if the result is a ResultSet or there are no more results -1
0685: * is returned. It should only be called once per result.
0686: *
0687: * <P>The only way to tell for sure that the result is an update
0688: * count is to first test to see if it is a ResultSet. If it is
0689: * not a ResultSet it is either an update count or there are no
0690: * more results.
0691: *
0692: * @return the current result as an update count; -1 if it is a
0693: * ResultSet or there are no more results
0694: * @see #execute
0695: */
0696: public final int getUpdateCount() throws SQLException {
0697: checkStatus();
0698: return updateCount;
0699: }
0700:
0701: /**
0702: * getMoreResults moves to a Statement's next result. It returns true if
0703: * this result is a ResultSet. getMoreResults also implicitly
0704: * closes any current ResultSet obtained with getResultSet.
0705: *
0706: * There are no more results when (!getMoreResults() &&
0707: * (getUpdateCount() == -1)
0708: *
0709: * @return true if the next result is a ResultSet; false if it is
0710: * an update count or there are no more results
0711: * @see #execute
0712: * @exception SQLException thrown on failure.
0713: */
0714: public final boolean getMoreResults() throws SQLException {
0715: return getMoreResults(JDBC30Translation.CLOSE_ALL_RESULTS);
0716: }
0717:
0718: /////////////////////////////////////////////////////////////////////////
0719: //
0720: // JDBC 2.0 methods that are implemented here because EmbedPreparedStatement
0721: // and EmbedCallableStatement in Local20 need access to them, and those
0722: // classes extend their peer classes in Local, instead of EmbedStatement
0723: // in Local20
0724: //
0725: // We do the same of JDBC 3.0 methods.
0726: /////////////////////////////////////////////////////////////////////////
0727:
0728: /**
0729: * JDBC 2.0
0730: *
0731: * Determine the result set type.
0732: *
0733: * @exception SQLException Feature not implemented for now.
0734: */
0735: public final int getResultSetType() throws SQLException {
0736: checkStatus();
0737: return resultSetType;
0738: }
0739:
0740: /**
0741: * JDBC 2.0
0742: *
0743: * Give a hint as to the direction in which the rows in a result set
0744: * will be processed. The hint applies only to result sets created
0745: * using this Statement object. The default value is
0746: * ResultSet.FETCH_FORWARD.
0747: *
0748: * @param direction the initial direction for processing rows
0749: * @exception SQLException if a database-access error occurs or direction
0750: * is not one of ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, or
0751: * ResultSet.FETCH_UNKNOWN
0752: */
0753: public void setFetchDirection(int direction) throws SQLException {
0754:
0755: checkStatus();
0756: /* fetch direction is meaningless to us. we just save
0757: * it off if it is valid and return the current value if asked.
0758: */
0759: if (direction == JDBC20Translation.FETCH_FORWARD
0760: || direction == JDBC20Translation.FETCH_REVERSE
0761: || direction == JDBC20Translation.FETCH_UNKNOWN) {
0762: fetchDirection = direction;
0763: } else
0764: throw newSQLException(SQLState.INVALID_FETCH_DIRECTION,
0765: new Integer(direction));
0766: }
0767:
0768: /**
0769: * JDBC 2.0
0770: *
0771: * Determine the fetch direction.
0772: *
0773: * @return the default fetch direction
0774: * @exception SQLException if a database-access error occurs
0775: */
0776: public int getFetchDirection() throws SQLException {
0777: checkStatus();
0778: return fetchDirection;
0779: }
0780:
0781: /**
0782: * JDBC 2.0
0783: *
0784: * Give the JDBC driver a hint as to the number of rows that should
0785: * be fetched from the database when more rows are needed. The number
0786: * of rows specified only affects result sets created using this
0787: * statement. If the value specified is zero, then the hint is ignored.
0788: * The default value is zero.
0789: *
0790: * @param rows the number of rows to fetch
0791: * @exception SQLException if a database-access error occurs, or the
0792: * condition 0 <= rows <= this.getMaxRows() is not satisfied.
0793: */
0794: public void setFetchSize(int rows) throws SQLException {
0795: checkStatus();
0796: if (rows < 0
0797: || (this .getMaxRows() != 0 && rows > this .getMaxRows())) {
0798: throw newSQLException(SQLState.INVALID_ST_FETCH_SIZE,
0799: new Integer(rows));
0800: } else if (rows > 0) // ignore the call if the value is zero
0801: fetchSize = rows;
0802: }
0803:
0804: /**
0805: * JDBC 2.0
0806: *
0807: * Determine the default fetch size.
0808: * @exception SQLException if a database-access error occurs
0809: *
0810: */
0811: public int getFetchSize() throws SQLException {
0812: checkStatus();
0813: return fetchSize;
0814: }
0815:
0816: /**
0817: * JDBC 2.0
0818: *
0819: * Determine the result set concurrency.
0820: *
0821: * @exception SQLException Feature not implemented for now.
0822: */
0823: public int getResultSetConcurrency() throws SQLException {
0824: checkStatus();
0825: return resultSetConcurrency;
0826: }
0827:
0828: /**
0829: * JDBC 3.0
0830: *
0831: * Retrieves the result set holdability for ResultSet objects
0832: * generated by this Statement object.
0833: *
0834: * @return either ResultSet.HOLD_CURSORS_OVER_COMMIT or
0835: * ResultSet.CLOSE_CURSORS_AT_COMMIT
0836: * @exception SQLException Feature not implemented for now.
0837: */
0838: public final int getResultSetHoldability() throws SQLException {
0839: checkStatus();
0840: return resultSetHoldability;
0841: }
0842:
0843: /**
0844: * JDBC 2.0
0845: *
0846: * Adds a SQL command to the current batch of commmands for the statement.
0847: * This method is optional.
0848: *
0849: * @param sql typically this is a static SQL INSERT or UPDATE statement
0850: * @exception SQLException if a database-access error occurs, or the
0851: * driver does not support batch statements
0852: */
0853: public void addBatch(String sql) throws SQLException {
0854: checkStatus();
0855: synchronized (getConnectionSynchronization()) {
0856: if (batchStatements == null)
0857: batchStatements = new Vector();
0858: batchStatements.addElement(sql);
0859: }
0860: }
0861:
0862: /**
0863: * JDBC 2.0
0864: *
0865: * Make the set of commands in the current batch empty.
0866: * This method is optional.
0867: *
0868: * @exception SQLException if a database-access error occurs, or the
0869: * driver does not support batch statements
0870: */
0871: public final void clearBatch() throws SQLException {
0872: checkStatus();
0873: synchronized (getConnectionSynchronization()) {
0874: batchStatements = null;
0875: }
0876: }
0877:
0878: /**
0879: * JDBC 2.0
0880: *
0881: * Submit a batch of commands to the database for execution.
0882: * This method is optional.
0883: *
0884: * Moving jdbc2.0 batch related code in this class because
0885: * callableStatement in jdbc 20 needs this code too and it doesn't derive
0886: * from prepared statement in jdbc 20 in our implementation.
0887: * BatchUpdateException is the only new class from jdbc 20 which is being
0888: * referenced here and in order to avoid any jdk11x problems, using
0889: * reflection code to make an instance of that class.
0890: *
0891: * @return an array of update counts containing one element for each
0892: * command in the batch. The array is ordered according
0893: * to the order in which commands were inserted into the batch
0894: * @exception SQLException if a database-access error occurs, or the
0895: * driver does not support batch statements
0896: */
0897: public int[] executeBatch() throws SQLException {
0898: checkExecStatus();
0899: synchronized (getConnectionSynchronization()) {
0900: setupContextStack();
0901: int i = 0;
0902: // As per the jdbc 2.0 specs, close the statement object's current resultset
0903: // if one is open.
0904: // Are there results?
0905: // outside of the lower try/finally since results will
0906: // setup and restore themselves.
0907: clearResultSets();
0908:
0909: Vector stmts = batchStatements;
0910: batchStatements = null;
0911: int size;
0912: if (stmts == null)
0913: size = 0;
0914: else
0915: size = stmts.size();
0916:
0917: int[] returnUpdateCountForBatch = new int[size];
0918:
0919: SQLException sqle;
0920: try {
0921: for (; i < size; i++) {
0922: if (executeBatchElement(stmts.elementAt(i)))
0923: throw newSQLException(SQLState.RESULTSET_RETURN_NOT_ALLOWED);
0924: returnUpdateCountForBatch[i] = getUpdateCount();
0925: }
0926: return returnUpdateCountForBatch;
0927: } catch (StandardException se) {
0928:
0929: sqle = handleException(se);
0930: } catch (SQLException sqle2) {
0931: sqle = sqle2;
0932: } finally {
0933: restoreContextStack();
0934: }
0935:
0936: int successfulUpdateCount[] = new int[i];
0937: for (int j = 0; j < i; j++) {
0938: successfulUpdateCount[j] = returnUpdateCountForBatch[j];
0939: }
0940:
0941: SQLException batch = new java.sql.BatchUpdateException(sqle
0942: .getMessage(), sqle.getSQLState(), sqle
0943: .getErrorCode(), successfulUpdateCount);
0944:
0945: batch.setNextException(sqle);
0946: throw batch;
0947: }
0948: }
0949:
0950: /**
0951: Execute a single element of the batch. Overridden by EmbedPreparedStatement
0952: */
0953: boolean executeBatchElement(Object batchElement)
0954: throws SQLException, StandardException {
0955: return execute((String) batchElement, false, true,
0956: JDBC30Translation.NO_GENERATED_KEYS, null, null);
0957: }
0958:
0959: /**
0960: * JDBC 2.0
0961: *
0962: * Return the Connection that produced the Statement.
0963: *
0964: * @exception SQLException Exception if it cannot find the connection
0965: * associated to this statement.
0966: */
0967: public final java.sql.Connection getConnection()
0968: throws SQLException {
0969: checkStatus();
0970:
0971: java.sql.Connection appConn = getEmbedConnection()
0972: .getApplicationConnection();
0973: if ((appConn != applicationConnection) || (appConn == null)) {
0974:
0975: throw Util.noCurrentConnection();
0976: }
0977: return appConn;
0978: }
0979:
0980: /**
0981: * JDBC 3.0
0982: *
0983: * Moves to this Statement obect's next result, deals with any current ResultSet
0984: * object(s) according to the instructions specified by the given flag, and
0985: * returns true if the next result is a ResultSet object
0986: *
0987: * @param current - one of the following Statement constants indicating what
0988: * should happen to current ResultSet objects obtained using the method
0989: * getResultSetCLOSE_CURRENT_RESULT, KEEP_CURRENT_RESULT, or CLOSE_ALL_RESULTS
0990: * @return true if the next result is a ResultSet; false if it is
0991: * an update count or there are no more results
0992: * @see #execute
0993: * @exception SQLException thrown on failure.
0994: */
0995: public final boolean getMoreResults(int current)
0996: throws SQLException {
0997: checkExecStatus();
0998:
0999: synchronized (getConnectionSynchronization()) {
1000: if (dynamicResults == null) {
1001: // we only have the one resultset, so this is
1002: // simply a close for us.
1003: clearResultSets();
1004: return false;
1005: }
1006:
1007: int startingClose;
1008: switch (current) {
1009: default:
1010: case JDBC30Translation.CLOSE_ALL_RESULTS:
1011: startingClose = 0;
1012: break;
1013: case JDBC30Translation.CLOSE_CURRENT_RESULT:
1014: // just close the current result set.
1015: startingClose = currentDynamicResultSet;
1016: break;
1017: case JDBC30Translation.KEEP_CURRENT_RESULT:
1018: // make the close loop a no-op.
1019: startingClose = dynamicResults.length;
1020: break;
1021: }
1022:
1023: // Close loop.
1024: SQLException se = null;
1025: for (int i = startingClose; i <= currentDynamicResultSet
1026: && i < dynamicResults.length; i++) {
1027: EmbedResultSet lrs = dynamicResults[i];
1028: if (lrs == null)
1029: continue;
1030:
1031: try {
1032: lrs.close();
1033: } catch (SQLException sqle) {
1034: if (se == null)
1035: se = sqle;
1036: else
1037: se.setNextException(sqle);
1038: } finally {
1039: dynamicResults[i] = null;
1040: }
1041: }
1042:
1043: if (se != null) {
1044: // leave positioned on the current result set (?)
1045: throw se;
1046: }
1047:
1048: updateCount = -1;
1049:
1050: while (++currentDynamicResultSet < dynamicResults.length) {
1051:
1052: EmbedResultSet lrs = dynamicResults[currentDynamicResultSet];
1053: if (lrs != null) {
1054: if (lrs.isClosed) {
1055: dynamicResults[currentDynamicResultSet] = null;
1056: continue;
1057: }
1058:
1059: results = lrs;
1060:
1061: return true;
1062: }
1063: }
1064:
1065: results = null;
1066: return false;
1067: }
1068: }
1069:
1070: /**
1071: * JDBC 3.0
1072: *
1073: * Retrieves any auto-generated keys created as a result of executing this
1074: * Statement object. If this Statement is a non-insert statement,
1075: * a null ResultSet object is returned.
1076: *
1077: * @return a ResultSet object containing the auto-generated key(s) generated by
1078: * the execution of this Statement object
1079: * @exception SQLException if a database access error occurs
1080: */
1081: public final java.sql.ResultSet getGeneratedKeys()
1082: throws SQLException {
1083: checkStatus();
1084: if (autoGeneratedKeysResultSet == null)
1085: return null;
1086: else {
1087: execute("VALUES IDENTITY_VAL_LOCAL()", true, false,
1088: JDBC30Translation.NO_GENERATED_KEYS, null, null);
1089: return results;
1090: }
1091: }
1092:
1093: /////////////////////////////////////////////////////////////////////////
1094: //
1095: // Implementation specific methods
1096: //
1097: /////////////////////////////////////////////////////////////////////////
1098:
1099: /**
1100: Execute the current statement.
1101: @exception SQLException thrown on failure.
1102: */
1103: boolean executeStatement(Activation a, boolean executeQuery,
1104: boolean executeUpdate) throws SQLException {
1105:
1106: // we don't differentiate the update from the resultset case.
1107: // so, there could be a result set.
1108:
1109: // note: the statement interface will paste together
1110: // an activation and make sure the prepared statement
1111: // is still valid, so it is preferrable, for now,
1112: // to creating our own activation and stuffing it in
1113: // the prepared statement.
1114:
1115: synchronized (getConnectionSynchronization()) {
1116: setupContextStack(); // make sure there's context
1117: boolean retval;
1118:
1119: pvs = a.getParameterValueSet();
1120:
1121: try {
1122: // The following is from the javadoc for java.sql.Statement
1123: // Only one ResultSet per Statement can be open at any point in time.
1124: // Therefore, if the reading of one ResultSet is interleaved with the
1125: // reading of another, each must have been generated by different Statements.
1126: // All statement execute methods implicitly close a
1127: // statment's current ResultSet if an open one exists.
1128: if (results != null) {
1129: results.close();
1130: results = null;
1131: }
1132:
1133: clearWarnings();
1134:
1135: if (!forMetaData) {
1136: commitIfNeeded(); // commit the last statement if needed
1137: needCommit();
1138: } else {
1139:
1140: if (lcc.getActivationCount() > 1) {
1141: // we do not want to commit here as there seems to be other
1142: // statements/resultSets currently opened for this connection.
1143: } else {
1144: commitIfNeeded(); // we can legitimately commit
1145: needCommit();
1146: }
1147: }
1148:
1149: // if this was a prepared statement, this just
1150: // gets it for us, it won't recompile unless it is invalid.
1151: PreparedStatement ps = a.getPreparedStatement();
1152: ps.rePrepare(lcc);
1153: addWarning(ps.getCompileTimeWarnings());
1154:
1155: /*
1156: ** WARNING WARNING
1157: **
1158: ** Any state set in the activation before execution *must* be copied
1159: ** to the new activation in GenericActivationHolder.execute() when
1160: ** the statement has been recompiled. State such as
1161: ** singleExecution, cursorName, holdability, maxRows.
1162: */
1163:
1164: if (cursorName != null) {
1165: a.setCursorName(cursorName);
1166: }
1167:
1168: boolean executeHoldable = getExecuteHoldable();
1169:
1170: a.setResultSetHoldability(executeHoldable);
1171:
1172: //reset the activation to clear warnings
1173: //and clear existing result sets in case this has been cached
1174: a.reset();
1175: a.setMaxRows(maxRows);
1176: long timeoutMillis = (long) timeoutSeconds * 1000L;
1177: ResultSet resultsToWrap = ps.execute(a, false,
1178: timeoutMillis);
1179: addWarning(a.getWarnings());
1180:
1181: if (resultsToWrap.returnsRows()) {
1182:
1183: // The statement returns rows, so calling it with
1184: // executeUpdate() is not allowed.
1185: if (executeUpdate) {
1186: throw StandardException
1187: .newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE);
1188: }
1189:
1190: EmbedResultSet lresults = factory
1191: .newEmbedResultSet(getEmbedConnection(),
1192: resultsToWrap, forMetaData, this ,
1193: ps.isAtomic());
1194: results = lresults;
1195:
1196: // Set up the finalization of the ResultSet to
1197: // mark the activation as unused. It will be
1198: // closed sometime later by the connection
1199: // outside of finalization.
1200: if (a.isSingleExecution())
1201: lresults.singleUseActivation = a;
1202:
1203: updateCount = -1;
1204: retval = true;
1205: } else {
1206:
1207: // Only applipable for an insert statement, which does not return rows.
1208: //the auto-generated keys resultset will be null if used for non-insert statement
1209: if (a.getAutoGeneratedKeysResultsetMode()
1210: && (resultsToWrap
1211: .getAutoGeneratedKeysResultset() != null)) {
1212: resultsToWrap.getAutoGeneratedKeysResultset()
1213: .open();
1214: autoGeneratedKeysResultSet = factory
1215: .newEmbedResultSet(
1216: getEmbedConnection(),
1217: resultsToWrap
1218: .getAutoGeneratedKeysResultset(),
1219: false, this , ps.isAtomic());
1220: }
1221:
1222: updateCount = resultsToWrap.modifiedRowCount();
1223:
1224: resultsToWrap.finish(); // Don't need the result set any more
1225: results = null; // note that we have none.
1226:
1227: int dynamicResultCount = 0;
1228: if (a.getDynamicResults() != null) {
1229: dynamicResultCount = processDynamicResults(a
1230: .getDynamicResults(), a
1231: .getMaxDynamicResults());
1232: }
1233:
1234: // executeQuery() is not allowed if the statement
1235: // doesn't return exactly one ResultSet.
1236: if (executeQuery && dynamicResultCount != 1) {
1237: throw StandardException
1238: .newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_QUERY);
1239: }
1240:
1241: // executeUpdate() is not allowed if the statement
1242: // returns ResultSets.
1243: if (executeUpdate && dynamicResultCount > 0) {
1244: throw StandardException
1245: .newException(SQLState.LANG_INVALID_CALL_TO_EXECUTE_UPDATE);
1246: }
1247:
1248: if (dynamicResultCount == 0) {
1249: if (a.isSingleExecution()) {
1250: a.close();
1251: }
1252:
1253: if (!forMetaData)
1254: commitIfNeeded();
1255: else {
1256:
1257: if (lcc.getActivationCount() > 1) {
1258: // we do not want to commit here as there seems to be other
1259: // statements/resultSets currently opened for this connection.
1260: } else {
1261: commitIfNeeded(); // we can legitimately commit
1262: }
1263: }
1264: }
1265:
1266: retval = (dynamicResultCount > 0);
1267: }
1268: } catch (Throwable t) {
1269: if (a.isSingleExecution()) {
1270: try {
1271: a.close();
1272: } catch (Throwable tt) {
1273: ;
1274: }
1275: }
1276: throw handleException(t);
1277: } finally {
1278: restoreContextStack();
1279: }
1280: return retval;
1281: }
1282: }
1283:
1284: /**
1285: * Add a SQLWarning to this Statement object.
1286: * If the Statement already has a SQLWarning then it
1287: * is added to the end of the chain.
1288: *
1289: * @see #getWarnings()
1290: */
1291: final void addWarning(SQLWarning sw) {
1292: if (sw != null) {
1293: if (warnings == null)
1294: warnings = sw;
1295: else
1296: warnings.setNextException(sw);
1297: }
1298: }
1299:
1300: /* package */
1301: public String getSQLText() {
1302: // no need to synchronize - accessing a reference is atomic
1303: // synchronized (getConnectionSynchronization())
1304: return SQLText;
1305: }
1306:
1307: public ParameterValueSet getParameterValueSet() {
1308: return pvs;
1309: }
1310:
1311: /**
1312: * Throw an exception if this Statement has been closed explictly
1313: * or it has noticed it has been closed implicitly.
1314: * JDBC specifications require nearly all methods throw a SQLException
1315: * if the Statement has been closed, thus most methods call this
1316: * method or checkExecStatus first.
1317: *
1318: * @exception SQLException Thrown if the statement is marked as closed.
1319: *
1320: * @see #checkExecStatus()
1321: */
1322: final void checkStatus() throws SQLException {
1323: if (!active) {
1324: //
1325: // Check the status of the connection first
1326: //
1327: java.sql.Connection appConn = getEmbedConnection()
1328: .getApplicationConnection();
1329: if (appConn == null || appConn.isClosed()) {
1330: throw Util.noCurrentConnection();
1331: }
1332:
1333: throw newSQLException(SQLState.ALREADY_CLOSED, "Statement");
1334: }
1335: }
1336:
1337: /**
1338: A heavier weight version of checkStatus() that ensures the application's Connection
1339: object is still open. This is to stop errors or unexpected behaviour when a [Prepared]Statement
1340: object is used after the application has been closed. In particular to ensure that
1341: a Statement obtained from a PooledConnection cannot be used after the application has closed
1342: its connection (as the underlying Connection is still active).
1343: To avoid this heavier weight check on every method of [Prepared]Statement it is only used
1344: on those methods that would end up using the database's connection to read or modify data.
1345: E.g. execute*(), but not setXXX, etc.
1346: <BR>
1347: If this Statement's Connection is closed an exception will
1348: be thrown and the active field will be set to false,
1349: completely marking the Statement as closed.
1350: <BR>
1351: If the Statement is not currently connected to an active
1352: transaction, i.e. a suspended global transaction, then
1353: this method will throw a SQLException but the Statement
1354: will remain open. The Statement is open but unable to
1355: process any new requests until its global transaction
1356: is resumed.
1357: <BR>
1358: Upon return from the method, with or without a SQLException
1359: the field active will correctly represent the open state of
1360: the Statement.
1361:
1362: @exception SQLException Thrown if the statement is marked as closed
1363: or the Statement's transaction is suspended.
1364:
1365: @see #checkStatus()
1366: */
1367: final void checkExecStatus() throws SQLException {
1368: // getConnection() checks if the Statement is closed
1369: if (!getConnection().isClosed())
1370: return;
1371:
1372: // Now this connection is closed for all
1373: // future use.
1374: active = false;
1375:
1376: throw Util.noCurrentConnection();
1377: }
1378:
1379: /**
1380: Close and clear all result sets associated with this statement
1381: from the last execution.
1382: */
1383: void clearResultSets() throws SQLException {
1384:
1385: SQLException sqle = null;
1386:
1387: try {
1388: // Are there results?
1389: // outside of the lower try/finally since results will
1390: // setup and restore themselves.
1391: if (results != null) {
1392: results.close();
1393: results = null;
1394: }
1395: } catch (SQLException s1) {
1396: sqle = s1;
1397: }
1398:
1399: try {
1400: if (autoGeneratedKeysResultSet != null) {
1401: autoGeneratedKeysResultSet.close();
1402: autoGeneratedKeysResultSet = null;
1403: }
1404: } catch (SQLException sauto) {
1405: if (sqle == null)
1406: sqle = sauto;
1407: else
1408: sqle.setNextException(sauto);
1409: }
1410:
1411: // close all the dynamic result sets.
1412: if (dynamicResults != null) {
1413: for (int i = 0; i < dynamicResults.length; i++) {
1414: EmbedResultSet lrs = dynamicResults[i];
1415: if (lrs == null)
1416: continue;
1417:
1418: try {
1419: lrs.close();
1420: } catch (SQLException sdynamic) {
1421: if (sqle == null)
1422: sqle = sdynamic;
1423: else
1424: sqle.setNextException(sdynamic);
1425: }
1426: }
1427: dynamicResults = null;
1428: }
1429:
1430: /*
1431: We don't reset statement to null because PreparedStatement
1432: relies on it being there for subsequent (post-close) execution
1433: requests. There is no close method on database statement objects.
1434: */
1435:
1436: updateCount = -1; // reset field
1437:
1438: if (sqle != null)
1439: throw sqle;
1440: }
1441:
1442: /**
1443: Check to see if a statement requires to be executed via a callable statement.
1444: */
1445: void checkRequiresCallableStatement(Activation activation)
1446: throws SQLException {
1447:
1448: ParameterValueSet pvs = activation.getParameterValueSet();
1449:
1450: if (pvs == null)
1451: return;
1452:
1453: if (pvs.checkNoDeclaredOutputParameters()) {
1454: try {
1455: activation.close();
1456: } catch (StandardException se) {
1457: }
1458: throw newSQLException(SQLState.REQUIRES_CALLABLE_STATEMENT,
1459: SQLText);
1460: }
1461: }
1462:
1463: /**
1464: Transfer my batch of Statements to a newly created Statement.
1465: */
1466: public void transferBatch(EmbedStatement other) throws SQLException {
1467:
1468: synchronized (getConnectionSynchronization()) {
1469: other.batchStatements = batchStatements;
1470: batchStatements = null;
1471: }
1472: }
1473:
1474: /**
1475: * Set the application statement for this Statement.
1476: */
1477: public final void setApplicationStatement(EngineStatement s) {
1478: this .applicationStatement = s;
1479: }
1480:
1481: private EmbedResultSet[] dynamicResults;
1482: private int currentDynamicResultSet;
1483:
1484: /**
1485: * Go through a holder of dynamic result sets, remove those that
1486: * should not be returned, and sort the result sets according to
1487: * their creation.
1488: *
1489: * @param holder a holder of dynamic result sets
1490: * @param maxDynamicResultSets the maximum number of result sets
1491: * to be returned
1492: * @return the actual number of result sets
1493: * @exception SQLException if an error occurs
1494: */
1495: private int processDynamicResults(java.sql.ResultSet[][] holder,
1496: int maxDynamicResultSets) throws SQLException {
1497:
1498: EmbedResultSet[] sorted = new EmbedResultSet[holder.length];
1499:
1500: int actualCount = 0;
1501: for (int i = 0; i < holder.length; i++) {
1502:
1503: java.sql.ResultSet[] param = holder[i];
1504:
1505: if (param[0] == null)
1506: continue;
1507:
1508: java.sql.ResultSet rs = param[0];
1509: param[0] = null;
1510:
1511: // ignore non-cloudscape result sets or results sets from another connection
1512: if (!(rs instanceof EmbedResultSet))
1513: continue;
1514:
1515: EmbedResultSet lrs = (EmbedResultSet) rs;
1516:
1517: if (lrs.getEmbedConnection().rootConnection != getEmbedConnection().rootConnection)
1518: continue;
1519:
1520: // ignore closed result sets.
1521: if (lrs.isClosed)
1522: continue;
1523:
1524: lrs.setDynamicResultSet(this );
1525: sorted[actualCount++] = lrs;
1526: }
1527:
1528: if (actualCount != 0) {
1529:
1530: // results are defined to be ordered according to their creation
1531: if (actualCount != 1) {
1532: java.util.Arrays.sort(sorted, 0, actualCount);
1533: }
1534:
1535: dynamicResults = sorted;
1536:
1537: if (actualCount > maxDynamicResultSets) {
1538: addWarning(StandardException
1539: .newWarning(SQLState.LANG_TOO_MANY_DYNAMIC_RESULTS_RETURNED));
1540:
1541: for (int i = maxDynamicResultSets; i < actualCount; i++) {
1542: sorted[i].close();
1543: sorted[i] = null;
1544: }
1545:
1546: actualCount = maxDynamicResultSets;
1547: }
1548:
1549: updateCount = -1;
1550: results = sorted[0];
1551: currentDynamicResultSet = 0;
1552:
1553: // 0100C is not returned for procedures written in Java, from the SQL2003 spec.
1554: // getWarnings(StandardException.newWarning(SQLState.LANG_DYNAMIC_RESULTS_RETURNED));
1555: }
1556:
1557: return actualCount;
1558: }
1559:
1560: /**
1561: Callback on the statement when one of its result sets is closed.
1562: This allows the statement to control when it completes and hence
1563: when it commits in auto commit mode.
1564:
1565: Must have connection synchronization and setupContextStack(), this
1566: is required for the call to commitIfNeeded().
1567: */
1568: void resultSetClosing(EmbedResultSet closingLRS)
1569: throws SQLException {
1570:
1571: // If the Connection is not in auto commit then this statement completion
1572: // cannot cause a commit.
1573: if (!getEmbedConnection().autoCommit)
1574: return;
1575:
1576: // If we have dynamic results, see if there is another result set open.
1577: // If so, then no commit. The last result set to close will close the statement.
1578: if (dynamicResults != null) {
1579: for (int i = 0; i < dynamicResults.length; i++) {
1580: EmbedResultSet lrs = dynamicResults[i];
1581: if (lrs == null)
1582: continue;
1583: if (lrs.isClosed)
1584: continue;
1585: if (lrs == closingLRS)
1586: continue;
1587:
1588: // at least one still open so no commit now.
1589: return;
1590: }
1591: }
1592:
1593: // new Throwable("COMMIT ON " + SQLText).printStackTrace(System.out);
1594:
1595: // beetle 5383. Force a commit in autocommit always. Before this
1596: // change if client in autocommit opened a result set, did a commit,
1597: // then next then close a commit would not be forced on the close.
1598: commitIfAutoCommit();
1599: }
1600:
1601: /**
1602: * Get the execute time holdability for the Statement.
1603: * When in a global transaction holdabilty defaults to false.
1604: * @throws SQLException Error from getResultSetHoldability.
1605: */
1606: private boolean getExecuteHoldable() throws SQLException {
1607: if (resultSetHoldability == JDBC30Translation.CLOSE_CURSORS_AT_COMMIT)
1608: return false;
1609:
1610: // Simple non-XA case
1611: if (applicationStatement == this )
1612: return true;
1613:
1614: return applicationStatement.getResultSetHoldability() == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
1615: }
1616:
1617: /**
1618: * Returns the value of the EmbedStatement's poolable hint,
1619: * indicating whether pooling is requested.
1620: *
1621: * @return The value of the poolable hint.
1622: * @throws SQLException if the Statement has been closed.
1623: */
1624:
1625: public boolean isPoolable() throws SQLException {
1626: // Assert the statement is still active (not closed)
1627: checkStatus();
1628:
1629: return isPoolable;
1630: }
1631:
1632: /**
1633: * Requests that an EmbedStatement be pooled or not.
1634: *
1635: * @param poolable requests that the EmbedStatement be pooled if true
1636: * and not be pooled if false.
1637: * @throws SQLException if the EmbedStatement has been closed.
1638: */
1639:
1640: public void setPoolable(boolean poolable) throws SQLException {
1641: // Assert the statement is still active (not closed)
1642: checkStatus();
1643:
1644: isPoolable = poolable;
1645: }
1646: }
|