1 | /* |
2 | |
3 | Derby - Class org.apache.derby.jdbc.XAStatementControl |
4 | |
5 | Copyright 2003, 2005 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.jdbc; |
22 | |
23 | import org.apache.derby.iapi.jdbc.BrokeredConnection; |
24 | import org.apache.derby.iapi.jdbc.BrokeredStatementControl; |
25 | import org.apache.derby.iapi.jdbc.BrokeredStatement; |
26 | import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement; |
27 | import org.apache.derby.iapi.jdbc.BrokeredCallableStatement; |
28 | import org.apache.derby.iapi.jdbc.EngineStatement; |
29 | import org.apache.derby.impl.jdbc.EmbedConnection; |
30 | import org.apache.derby.impl.jdbc.EmbedResultSet; |
31 | import org.apache.derby.impl.jdbc.EmbedStatement; |
32 | import org.apache.derby.impl.jdbc.EmbedPreparedStatement; |
33 | |
34 | import java.sql.*; |
35 | |
36 | /** |
37 | The Statement returned by an Connection returned by a XAConnection |
38 | needs to float across the underlying real connections. We do this by implementing |
39 | a wrapper statement. |
40 | */ |
41 | final class XAStatementControl implements BrokeredStatementControl { |
42 | |
43 | /** |
44 | */ |
45 | private final EmbedXAConnection xaConnection; |
46 | private final BrokeredConnection applicationConnection; |
47 | BrokeredStatement applicationStatement; |
48 | private EmbedConnection realConnection; |
49 | private Statement realStatement; |
50 | private PreparedStatement realPreparedStatement; |
51 | private CallableStatement realCallableStatement; |
52 | |
53 | private XAStatementControl(EmbedXAConnection xaConnection) { |
54 | this.xaConnection = xaConnection; |
55 | this.realConnection = xaConnection.realConnection; |
56 | this.applicationConnection = xaConnection.currentConnectionHandle; |
57 | } |
58 | |
59 | XAStatementControl(EmbedXAConnection xaConnection, |
60 | Statement realStatement) throws SQLException { |
61 | this(xaConnection); |
62 | this.realStatement = realStatement; |
63 | this.applicationStatement = applicationConnection.newBrokeredStatement(this); |
64 | |
65 | ((EmbedStatement) realStatement).setApplicationStatement( |
66 | applicationStatement); |
67 | } |
68 | XAStatementControl(EmbedXAConnection xaConnection, |
69 | PreparedStatement realPreparedStatement, |
70 | String sql, Object generatedKeys) throws SQLException { |
71 | this(xaConnection); |
72 | this.realPreparedStatement = realPreparedStatement; |
73 | this.applicationStatement = applicationConnection.newBrokeredStatement(this, sql, generatedKeys); |
74 | ((EmbedStatement) realPreparedStatement).setApplicationStatement( |
75 | applicationStatement); |
76 | } |
77 | XAStatementControl(EmbedXAConnection xaConnection, |
78 | CallableStatement realCallableStatement, |
79 | String sql) throws SQLException { |
80 | this(xaConnection); |
81 | this.realCallableStatement = realCallableStatement; |
82 | this.applicationStatement = applicationConnection.newBrokeredStatement(this, sql); |
83 | ((EmbedStatement) realCallableStatement).setApplicationStatement( |
84 | applicationStatement); |
85 | } |
86 | |
87 | public Statement getRealStatement() throws SQLException { |
88 | |
89 | // |
90 | if (applicationConnection == xaConnection.currentConnectionHandle) { |
91 | |
92 | // Application connection is the same. |
93 | if (realConnection == xaConnection.realConnection) |
94 | return realStatement; |
95 | |
96 | // If we switched back to a local connection, and the first access is through |
97 | // a non-connection object (e.g. statement then realConnection will be null) |
98 | if (xaConnection.realConnection == null) { |
99 | // force the connection |
100 | xaConnection.getRealConnection(); |
101 | } |
102 | |
103 | // underlying connection has changed. |
104 | // create new Statement |
105 | Statement newStatement = applicationStatement.createDuplicateStatement(xaConnection.realConnection, realStatement); |
106 | ((EmbedStatement) realStatement).transferBatch((EmbedStatement) newStatement); |
107 | |
108 | try { |
109 | realStatement.close(); |
110 | } catch (SQLException sqle) { |
111 | } |
112 | |
113 | realStatement = newStatement; |
114 | realConnection = xaConnection.realConnection; |
115 | ((EmbedStatement) realStatement).setApplicationStatement( |
116 | applicationStatement); |
117 | } |
118 | else { |
119 | // application connection is different, therefore the outer application |
120 | // statement is closed, so just return the realStatement. It should be |
121 | // closed by virtue of its application connection being closed. |
122 | } |
123 | return realStatement; |
124 | } |
125 | |
126 | public PreparedStatement getRealPreparedStatement() throws SQLException { |
127 | // |
128 | if (applicationConnection == xaConnection.currentConnectionHandle) { |
129 | // Application connection is the same. |
130 | if (realConnection == xaConnection.realConnection) |
131 | return realPreparedStatement; |
132 | |
133 | // If we switched back to a local connection, and the first access is through |
134 | // a non-connection object (e.g. statement then realConnection will be null) |
135 | if (xaConnection.realConnection == null) { |
136 | // force the connection |
137 | xaConnection.getRealConnection(); |
138 | } |
139 | |
140 | // underlying connection has changed. |
141 | // create new PreparedStatement |
142 | PreparedStatement newPreparedStatement = |
143 | ((BrokeredPreparedStatement) applicationStatement).createDuplicateStatement(xaConnection.realConnection, realPreparedStatement); |
144 | |
145 | |
146 | // ((EmbedStatement) realPreparedStatement).transferBatch((EmbedStatement) newPreparedStatement); |
147 | ((EmbedPreparedStatement) realPreparedStatement).transferParameters((EmbedPreparedStatement) newPreparedStatement); |
148 | |
149 | try { |
150 | realPreparedStatement.close(); |
151 | } catch (SQLException sqle) { |
152 | } |
153 | |
154 | realPreparedStatement = newPreparedStatement; |
155 | realConnection = xaConnection.realConnection; |
156 | ((EmbedStatement) realPreparedStatement).setApplicationStatement( |
157 | applicationStatement); |
158 | } |
159 | else { |
160 | // application connection is different, therefore the outer application |
161 | // statement is closed, so just return the realStatement. It should be |
162 | // closed by virtue of its application connection being closed. |
163 | } |
164 | return realPreparedStatement; |
165 | } |
166 | |
167 | public CallableStatement getRealCallableStatement() throws SQLException { |
168 | if (applicationConnection == xaConnection.currentConnectionHandle) { |
169 | // Application connection is the same. |
170 | if (realConnection == xaConnection.realConnection) |
171 | return realCallableStatement; |
172 | |
173 | // If we switched back to a local connection, and the first access is through |
174 | // a non-connection object (e.g. statement then realConnection will be null) |
175 | if (xaConnection.realConnection == null) { |
176 | // force the connection |
177 | xaConnection.getRealConnection(); |
178 | } |
179 | |
180 | // underlying connection has changed. |
181 | // create new PreparedStatement |
182 | CallableStatement newCallableStatement = |
183 | ((BrokeredCallableStatement) applicationStatement).createDuplicateStatement(xaConnection.realConnection, realCallableStatement); |
184 | |
185 | ((EmbedStatement) realCallableStatement).transferBatch((EmbedStatement) newCallableStatement); |
186 | |
187 | try { |
188 | realCallableStatement.close(); |
189 | } catch (SQLException sqle) { |
190 | } |
191 | |
192 | realCallableStatement = newCallableStatement; |
193 | realConnection = xaConnection.realConnection; |
194 | ((EmbedStatement) realCallableStatement).setApplicationStatement( |
195 | applicationStatement); |
196 | } |
197 | else { |
198 | // application connection is different, therefore the outer application |
199 | // statement is closed, so just return the realStatement. It should be |
200 | // closed by virtue of its application connection being closed. |
201 | } |
202 | return realCallableStatement; |
203 | } |
204 | |
205 | /** |
206 | * Don't need to wrap the ResultSet but do need to update its |
207 | * application Statement reference to be the one the application |
208 | * used to create the ResultSet. |
209 | */ |
210 | public ResultSet wrapResultSet(Statement s, ResultSet rs) { |
211 | if (rs != null) |
212 | ((EmbedResultSet) rs).setApplicationStatement(s); |
213 | return rs; |
214 | } |
215 | |
216 | /** |
217 | Can cursors be held across commits. |
218 | */ |
219 | public int checkHoldCursors(int holdability) throws SQLException { |
220 | return xaConnection.checkHoldCursors(holdability, true); |
221 | } |
222 | } |