001: /*
002:
003: Derby - Class org.apache.derby.jdbc.XAStatementControl
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.jdbc;
023:
024: import org.apache.derby.iapi.jdbc.BrokeredConnection;
025: import org.apache.derby.iapi.jdbc.BrokeredStatementControl;
026: import org.apache.derby.iapi.jdbc.BrokeredStatement;
027: import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
028: import org.apache.derby.iapi.jdbc.BrokeredCallableStatement;
029: import org.apache.derby.iapi.jdbc.EngineStatement;
030: import org.apache.derby.impl.jdbc.EmbedConnection;
031: import org.apache.derby.impl.jdbc.EmbedResultSet;
032: import org.apache.derby.impl.jdbc.EmbedStatement;
033: import org.apache.derby.impl.jdbc.EmbedPreparedStatement;
034:
035: import java.sql.*;
036:
037: /**
038: The Statement returned by an Connection returned by a XAConnection
039: needs to float across the underlying real connections. We do this by implementing
040: a wrapper statement.
041: */
042: final class XAStatementControl implements BrokeredStatementControl {
043:
044: /**
045: */
046: private final EmbedXAConnection xaConnection;
047: private final BrokeredConnection applicationConnection;
048: BrokeredStatement applicationStatement;
049: private EmbedConnection realConnection;
050: private Statement realStatement;
051: private PreparedStatement realPreparedStatement;
052: private CallableStatement realCallableStatement;
053:
054: private XAStatementControl(EmbedXAConnection xaConnection) {
055: this .xaConnection = xaConnection;
056: this .realConnection = xaConnection.realConnection;
057: this .applicationConnection = xaConnection.currentConnectionHandle;
058: }
059:
060: XAStatementControl(EmbedXAConnection xaConnection,
061: Statement realStatement) throws SQLException {
062: this (xaConnection);
063: this .realStatement = realStatement;
064: this .applicationStatement = applicationConnection
065: .newBrokeredStatement(this );
066:
067: ((EmbedStatement) realStatement)
068: .setApplicationStatement(applicationStatement);
069: }
070:
071: XAStatementControl(EmbedXAConnection xaConnection,
072: PreparedStatement realPreparedStatement, String sql,
073: Object generatedKeys) throws SQLException {
074: this (xaConnection);
075: this .realPreparedStatement = realPreparedStatement;
076: this .applicationStatement = applicationConnection
077: .newBrokeredStatement(this , sql, generatedKeys);
078: ((EmbedStatement) realPreparedStatement)
079: .setApplicationStatement(applicationStatement);
080: }
081:
082: XAStatementControl(EmbedXAConnection xaConnection,
083: CallableStatement realCallableStatement, String sql)
084: throws SQLException {
085: this (xaConnection);
086: this .realCallableStatement = realCallableStatement;
087: this .applicationStatement = applicationConnection
088: .newBrokeredStatement(this , sql);
089: ((EmbedStatement) realCallableStatement)
090: .setApplicationStatement(applicationStatement);
091: }
092:
093: public Statement getRealStatement() throws SQLException {
094:
095: //
096: if (applicationConnection == xaConnection.currentConnectionHandle) {
097:
098: // Application connection is the same.
099: if (realConnection == xaConnection.realConnection)
100: return realStatement;
101:
102: // If we switched back to a local connection, and the first access is through
103: // a non-connection object (e.g. statement then realConnection will be null)
104: if (xaConnection.realConnection == null) {
105: // force the connection
106: xaConnection.getRealConnection();
107: }
108:
109: // underlying connection has changed.
110: // create new Statement
111: Statement newStatement = applicationStatement
112: .createDuplicateStatement(
113: xaConnection.realConnection, realStatement);
114: ((EmbedStatement) realStatement)
115: .transferBatch((EmbedStatement) newStatement);
116:
117: try {
118: realStatement.close();
119: } catch (SQLException sqle) {
120: }
121:
122: realStatement = newStatement;
123: realConnection = xaConnection.realConnection;
124: ((EmbedStatement) realStatement)
125: .setApplicationStatement(applicationStatement);
126: } else {
127: // application connection is different, therefore the outer application
128: // statement is closed, so just return the realStatement. It should be
129: // closed by virtue of its application connection being closed.
130: }
131: return realStatement;
132: }
133:
134: public PreparedStatement getRealPreparedStatement()
135: throws SQLException {
136: //
137: if (applicationConnection == xaConnection.currentConnectionHandle) {
138: // Application connection is the same.
139: if (realConnection == xaConnection.realConnection)
140: return realPreparedStatement;
141:
142: // If we switched back to a local connection, and the first access is through
143: // a non-connection object (e.g. statement then realConnection will be null)
144: if (xaConnection.realConnection == null) {
145: // force the connection
146: xaConnection.getRealConnection();
147: }
148:
149: // underlying connection has changed.
150: // create new PreparedStatement
151: PreparedStatement newPreparedStatement = ((BrokeredPreparedStatement) applicationStatement)
152: .createDuplicateStatement(
153: xaConnection.realConnection,
154: realPreparedStatement);
155:
156: // ((EmbedStatement) realPreparedStatement).transferBatch((EmbedStatement) newPreparedStatement);
157: ((EmbedPreparedStatement) realPreparedStatement)
158: .transferParameters((EmbedPreparedStatement) newPreparedStatement);
159:
160: try {
161: realPreparedStatement.close();
162: } catch (SQLException sqle) {
163: }
164:
165: realPreparedStatement = newPreparedStatement;
166: realConnection = xaConnection.realConnection;
167: ((EmbedStatement) realPreparedStatement)
168: .setApplicationStatement(applicationStatement);
169: } else {
170: // application connection is different, therefore the outer application
171: // statement is closed, so just return the realStatement. It should be
172: // closed by virtue of its application connection being closed.
173: }
174: return realPreparedStatement;
175: }
176:
177: public CallableStatement getRealCallableStatement()
178: throws SQLException {
179: if (applicationConnection == xaConnection.currentConnectionHandle) {
180: // Application connection is the same.
181: if (realConnection == xaConnection.realConnection)
182: return realCallableStatement;
183:
184: // If we switched back to a local connection, and the first access is through
185: // a non-connection object (e.g. statement then realConnection will be null)
186: if (xaConnection.realConnection == null) {
187: // force the connection
188: xaConnection.getRealConnection();
189: }
190:
191: // underlying connection has changed.
192: // create new PreparedStatement
193: CallableStatement newCallableStatement = ((BrokeredCallableStatement) applicationStatement)
194: .createDuplicateStatement(
195: xaConnection.realConnection,
196: realCallableStatement);
197:
198: ((EmbedStatement) realCallableStatement)
199: .transferBatch((EmbedStatement) newCallableStatement);
200:
201: try {
202: realCallableStatement.close();
203: } catch (SQLException sqle) {
204: }
205:
206: realCallableStatement = newCallableStatement;
207: realConnection = xaConnection.realConnection;
208: ((EmbedStatement) realCallableStatement)
209: .setApplicationStatement(applicationStatement);
210: } else {
211: // application connection is different, therefore the outer application
212: // statement is closed, so just return the realStatement. It should be
213: // closed by virtue of its application connection being closed.
214: }
215: return realCallableStatement;
216: }
217:
218: /**
219: * Don't need to wrap the ResultSet but do need to update its
220: * application Statement reference to be the one the application
221: * used to create the ResultSet.
222: */
223: public ResultSet wrapResultSet(Statement s, ResultSet rs) {
224: if (rs != null)
225: ((EmbedResultSet) rs).setApplicationStatement(s);
226: return rs;
227: }
228:
229: /**
230: Can cursors be held across commits.
231: */
232: public int checkHoldCursors(int holdability) throws SQLException {
233: return xaConnection.checkHoldCursors(holdability, true);
234: }
235: }
|