001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: // Copyright (C) 2004 The jTDS Project
003: //
004: // This library is free software; you can redistribute it and/or
005: // modify it under the terms of the GNU Lesser General Public
006: // License as published by the Free Software Foundation; either
007: // version 2.1 of the License, or (at your option) any later version.
008: //
009: // This library is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: // Lesser General Public License for more details.
013: //
014: // You should have received a copy of the GNU Lesser General Public
015: // License along with this library; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.jdbc;
019:
020: import java.util.*;
021: import java.sql.*;
022:
023: /**
024: * Implements JDBC 3.0 specific functionality. Separated from {@link
025: * ConnectionJDBC2} in order to allow the same classes to run under both J2SE 1.3
026: * (<code>ConnectionJDBC2</code>)and 1.4 (<code>ConnectionJDBC3</code>).
027: *
028: * @author Alin Sinpalean
029: * @author Brian Heineman
030: * @author Mike Hutchinson
031: * @created March 30, 2004
032: * @version $Id: ConnectionJDBC3.java,v 1.15 2005/10/27 13:22:33 alin_sinpalean Exp $
033: */
034: public class ConnectionJDBC3 extends ConnectionJDBC2 {
035: /** The list of savepoints. */
036: private ArrayList savepoints;
037: /** Maps each savepoint to a list of tmep procedures created since the savepoint */
038: private Map savepointProcInTran;
039: /** Counter for generating unique savepoint identifiers */
040: private int savepointId;
041:
042: /**
043: * Create a new database connection.
044: *
045: * @param url The connection URL starting jdbc:jtds:.
046: * @param props The additional connection properties.
047: * @throws SQLException
048: */
049: ConnectionJDBC3(String url, Properties props) throws SQLException {
050: super (url, props);
051: }
052:
053: /**
054: * Add a savepoint to the list maintained by this connection.
055: *
056: * @param savepoint The savepoint object to add.
057: * @throws SQLException
058: */
059: private void setSavepoint(SavepointImpl savepoint)
060: throws SQLException {
061: Statement statement = null;
062:
063: try {
064: statement = createStatement();
065: statement
066: .execute("IF @@TRANCOUNT=0 BEGIN TRAN SAVE TRAN jtds"
067: + savepoint.getId());
068: } finally {
069: if (statement != null) {
070: statement.close();
071: }
072: }
073:
074: synchronized (this ) {
075: if (savepoints == null) {
076: savepoints = new ArrayList();
077: }
078:
079: savepoints.add(savepoint);
080: }
081: }
082:
083: /**
084: * Releases all savepoints. Used internally when committing or rolling back
085: * a transaction.
086: */
087: synchronized void clearSavepoints() {
088: if (savepoints != null) {
089: savepoints.clear();
090: }
091:
092: if (savepointProcInTran != null) {
093: savepointProcInTran.clear();
094: }
095:
096: savepointId = 0;
097: }
098:
099: // ------------- Methods implementing java.sql.Connection -----------------
100:
101: public synchronized void releaseSavepoint(Savepoint savepoint)
102: throws SQLException {
103: checkOpen();
104:
105: if (savepoints == null) {
106: throw new SQLException(Messages
107: .get("error.connection.badsavep"), "25000");
108: }
109:
110: int index = savepoints.indexOf(savepoint);
111:
112: if (index == -1) {
113: throw new SQLException(Messages
114: .get("error.connection.badsavep"), "25000");
115: }
116:
117: Object tmpSavepoint = savepoints.remove(index);
118:
119: if (savepointProcInTran != null) {
120: if (index != 0) {
121: // If this wasn't the outermost savepoint, move all procedures
122: // to the "wrapping" savepoint's list; when and if that
123: // savepoint will be rolled back it will clear these procedures
124: // too
125: List keys = (List) savepointProcInTran.get(savepoint);
126:
127: if (keys != null) {
128: Savepoint wrapping = (Savepoint) savepoints
129: .get(index - 1);
130: List wrappingKeys = (List) savepointProcInTran
131: .get(wrapping);
132: if (wrappingKeys == null) {
133: wrappingKeys = new ArrayList();
134: }
135: wrappingKeys.addAll(keys);
136: savepointProcInTran.put(wrapping, wrappingKeys);
137: }
138: }
139:
140: // If this was the outermost savepoint, just drop references to
141: // all procedures; they will be managed by the connection
142: savepointProcInTran.remove(tmpSavepoint);
143: }
144: }
145:
146: public synchronized void rollback(Savepoint savepoint)
147: throws SQLException {
148: checkOpen();
149: checkLocal("rollback");
150:
151: if (savepoints == null) {
152: throw new SQLException(Messages
153: .get("error.connection.badsavep"), "25000");
154: }
155:
156: int index = savepoints.indexOf(savepoint);
157:
158: if (index == -1) {
159: throw new SQLException(Messages
160: .get("error.connection.badsavep"), "25000");
161: } else if (getAutoCommit()) {
162: throw new SQLException(Messages
163: .get("error.connection.savenorollback"), "25000");
164: }
165:
166: Statement statement = null;
167:
168: try {
169: statement = createStatement();
170: statement.execute("ROLLBACK TRAN jtds"
171: + ((SavepointImpl) savepoint).getId());
172: } finally {
173: if (statement != null) {
174: statement.close();
175: }
176: }
177:
178: int size = savepoints.size();
179:
180: for (int i = size - 1; i >= index; i--) {
181: Object tmpSavepoint = savepoints.remove(i);
182:
183: if (savepointProcInTran == null) {
184: continue;
185: }
186:
187: List keys = (List) savepointProcInTran.get(tmpSavepoint);
188:
189: if (keys == null) {
190: continue;
191: }
192:
193: for (Iterator iterator = keys.iterator(); iterator
194: .hasNext();) {
195: String key = (String) iterator.next();
196:
197: removeCachedProcedure(key);
198: }
199: }
200: }
201:
202: synchronized public Savepoint setSavepoint() throws SQLException {
203: checkOpen();
204: checkLocal("setSavepoint");
205:
206: if (getAutoCommit()) {
207: throw new SQLException(Messages
208: .get("error.connection.savenoset"), "25000");
209: }
210:
211: SavepointImpl savepoint = new SavepointImpl(
212: getNextSavepointId());
213:
214: setSavepoint(savepoint);
215:
216: return savepoint;
217: }
218:
219: synchronized public Savepoint setSavepoint(String name)
220: throws SQLException {
221: checkOpen();
222: checkLocal("setSavepoint");
223:
224: if (getAutoCommit()) {
225: throw new SQLException(Messages
226: .get("error.connection.savenoset"), "25000");
227: } else if (name == null) {
228: throw new SQLException(Messages.get(
229: "error.connection.savenullname", "savepoint"),
230: "25000");
231: }
232:
233: SavepointImpl savepoint = new SavepointImpl(
234: getNextSavepointId(), name);
235:
236: setSavepoint(savepoint);
237:
238: return savepoint;
239: }
240:
241: /**
242: * Returns the next savepoint identifier.
243: *
244: * @return the next savepoint identifier
245: */
246: private int getNextSavepointId() {
247: return ++savepointId;
248: }
249:
250: /**
251: * Add a stored procedure to the cache.
252: *
253: * @param key The signature of the procedure to cache.
254: * @param proc The stored procedure descriptor.
255: */
256: void addCachedProcedure(String key, ProcEntry proc) {
257: super .addCachedProcedure(key, proc);
258: if (getServerType() == Driver.SQLSERVER
259: && proc.getType() == ProcEntry.PROCEDURE) {
260: // Only need to track SQL Server temp stored procs
261: addCachedProcedure(key);
262: }
263: }
264:
265: /**
266: * Add a stored procedure to the savepoint cache.
267: *
268: * @param key The signature of the procedure to cache.
269: */
270: synchronized void addCachedProcedure(String key) {
271: if (savepoints == null || savepoints.size() == 0) {
272: return;
273: }
274:
275: if (savepointProcInTran == null) {
276: savepointProcInTran = new HashMap();
277: }
278:
279: // Retrieve the current savepoint
280: Object savepoint = savepoints.get(savepoints.size() - 1);
281:
282: List keys = (List) savepointProcInTran.get(savepoint);
283:
284: if (keys == null) {
285: keys = new ArrayList();
286: }
287:
288: keys.add(key);
289:
290: savepointProcInTran.put(savepoint, keys);
291: }
292: }
|