1 | /* ============================================================= |
2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
3 | * ============================================================= |
4 | * |
5 | * (C) Copyright 2004-2006, by Volker Berlin. |
6 | * |
7 | * Project Info: http://www.smallsql.de/ |
8 | * |
9 | * This library is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU Lesser General Public License as published by |
11 | * the Free Software Foundation; either version 2.1 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
17 | * License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
22 | * USA. |
23 | * |
24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
25 | * in the United States and other countries.] |
26 | * |
27 | * --------------- |
28 | * SSConnection.java |
29 | * --------------- |
30 | * Author: Volker Berlin |
31 | * |
32 | */ |
33 | package smallsql.database; |
34 | |
35 | import java.io.RandomAccessFile; |
36 | import java.sql.*; |
37 | import java.util.Map; |
38 | import java.util.List; |
39 | import java.util.ArrayList; |
40 | import java.util.Properties; |
41 | |
42 | |
43 | public class SSConnection implements Connection { |
44 | |
45 | private Database database; |
46 | private boolean autoCommit = true; |
47 | int isolationLevel = TRANSACTION_READ_COMMITTED; // see also getDefaultTransactionIsolation |
48 | int serializeCount; |
49 | private List commitPages = new ArrayList(); |
50 | /** The time on which a transaction is starting. */ |
51 | private long transactionTime; |
52 | private SSDatabaseMetaData metadata; |
53 | private int holdability; |
54 | final Logger log = new Logger(); |
55 | |
56 | SSConnection( Properties props ) throws SQLException{ |
57 | String name = props.getProperty("dbpath"); |
58 | boolean create = "true".equals(props.getProperty("create")); |
59 | database = Database.getDatabase(name, this, create); |
60 | metadata = new SSDatabaseMetaData(this); |
61 | } |
62 | |
63 | |
64 | /** |
65 | * @param returnNull If null is a valid return value for the case of not connected to a database. |
66 | * @throws SQLException If not connected and returnNull is false. |
67 | */ |
68 | Database getDatabase(boolean returnNull) throws SQLException{ |
69 | if(!returnNull && database == null) throw Utils.createSQLException("You are not connected with a Database."); |
70 | return database; |
71 | } |
72 | |
73 | public Statement createStatement() throws SQLException { |
74 | return new SSStatement(this); |
75 | } |
76 | public PreparedStatement prepareStatement(String sql) throws SQLException { |
77 | return new SSPreparedStatement( this, sql); |
78 | } |
79 | public CallableStatement prepareCall(String sql) throws SQLException { |
80 | return new SSCallableStatement( this, sql); |
81 | } |
82 | public String nativeSQL(String sql) throws SQLException { |
83 | return sql; |
84 | } |
85 | |
86 | |
87 | public void setAutoCommit(boolean autoCommit) throws SQLException { |
88 | if(log.isLogging()) log.println("AutoCommit:"+autoCommit); |
89 | if(this.autoCommit != autoCommit){ |
90 | commit(); |
91 | this.autoCommit = autoCommit; |
92 | } |
93 | } |
94 | |
95 | |
96 | public boolean getAutoCommit() throws SQLException { |
97 | return autoCommit; |
98 | } |
99 | |
100 | |
101 | /** |
102 | * Add a page for later commit or rollback. |
103 | */ |
104 | void add(StorePage storePage) throws SQLException{ |
105 | testClosedConnection(); |
106 | commitPages.add(storePage); |
107 | } |
108 | |
109 | |
110 | public void commit() throws SQLException { |
111 | try{ |
112 | log.println("Commit"); |
113 | testClosedConnection(); |
114 | synchronized(commitPages){ |
115 | int count = commitPages.size(); |
116 | for(int i=0; i<count; i++){ |
117 | StorePage page = (StorePage)commitPages.get(i); |
118 | page.commit(); |
119 | } |
120 | for(int i=0; i<count; i++){ |
121 | StorePage page = (StorePage)commitPages.get(i); |
122 | page.freeLock(); |
123 | } |
124 | commitPages.clear(); |
125 | transactionTime = System.currentTimeMillis(); |
126 | } |
127 | }catch(Throwable e){ |
128 | rollback(); |
129 | throw Utils.createSQLException(e); |
130 | } |
131 | } |
132 | |
133 | |
134 | /** |
135 | * Discard all changes of a file because it was deleted. |
136 | */ |
137 | void rollbackFile(RandomAccessFile raFile) throws SQLException{ |
138 | testClosedConnection(); |
139 | // remove the all commits that point to this table |
140 | for(int i=commitPages.size()-1; i>=0; i--){ |
141 | StorePage page = (StorePage)commitPages.get(i); |
142 | if(page.raFile == raFile){ |
143 | page.rollback(); |
144 | page.freeLock(); |
145 | } |
146 | } |
147 | } |
148 | |
149 | |
150 | void rollback(int savepoint) throws SQLException{ |
151 | testClosedConnection(); |
152 | for(int i = commitPages.size()-1; i>=savepoint; i--){ |
153 | StorePage page = (StorePage)commitPages.remove(i); |
154 | page.rollback(); |
155 | page.freeLock(); |
156 | } |
157 | } |
158 | |
159 | |
160 | public void rollback() throws SQLException { |
161 | log.println("Rollback"); |
162 | testClosedConnection(); |
163 | synchronized(commitPages){ |
164 | int count = commitPages.size(); |
165 | for(int i=0; i<count; i++){ |
166 | StorePage page = (StorePage)commitPages.get(i); |
167 | page.rollback(); |
168 | page.freeLock(); |
169 | } |
170 | commitPages.clear(); |
171 | transactionTime = System.currentTimeMillis(); |
172 | } |
173 | } |
174 | |
175 | |
176 | public void close() throws SQLException { |
177 | rollback(); |
178 | database = null; |
179 | commitPages = null; |
180 | Database.closeConnection(this); |
181 | } |
182 | |
183 | |
184 | final void testClosedConnection() throws SQLException{ |
185 | if(isClosed()) throw Utils.createSQLException("Connection was closed."); |
186 | } |
187 | |
188 | public boolean isClosed() throws SQLException { |
189 | return (commitPages == null); |
190 | } |
191 | |
192 | |
193 | public DatabaseMetaData getMetaData() throws SQLException { |
194 | return metadata; |
195 | } |
196 | |
197 | |
198 | public void setReadOnly(boolean readOnly) throws SQLException { |
199 | } |
200 | |
201 | |
202 | public boolean isReadOnly() throws SQLException { |
203 | return false; |
204 | } |
205 | |
206 | |
207 | public void setCatalog(String catalog) throws SQLException { |
208 | if(isClosed()) throw Utils.createSQLException("Connection is allready closed"); |
209 | database = Database.getDatabase(catalog, this, false); |
210 | } |
211 | |
212 | |
213 | public String getCatalog() throws SQLException { |
214 | if(database == null) |
215 | return ""; |
216 | return database.getName(); |
217 | } |
218 | |
219 | |
220 | public void setTransactionIsolation(int level) throws SQLException { |
221 | if(!metadata.supportsTransactionIsolationLevel(level)) |
222 | throw Utils.createSQLException("Unknow Transaction Isolation Level:"+level); |
223 | isolationLevel = level; |
224 | } |
225 | |
226 | |
227 | public int getTransactionIsolation() throws SQLException { |
228 | return isolationLevel; |
229 | } |
230 | |
231 | |
232 | public SQLWarning getWarnings() throws SQLException { |
233 | return null; |
234 | } |
235 | |
236 | |
237 | public void clearWarnings() throws SQLException { |
238 | } |
239 | |
240 | |
241 | public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { |
242 | return new SSStatement( this, resultSetType, resultSetConcurrency); |
243 | } |
244 | |
245 | |
246 | public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { |
247 | return new SSPreparedStatement( this, sql, resultSetType, resultSetConcurrency); |
248 | } |
249 | |
250 | |
251 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { |
252 | return new SSCallableStatement( this, sql, resultSetType, resultSetConcurrency); |
253 | } |
254 | |
255 | |
256 | public Map getTypeMap() throws SQLException { |
257 | return null; |
258 | } |
259 | |
260 | |
261 | public void setTypeMap(Map map) throws SQLException { |
262 | } |
263 | |
264 | |
265 | public void setHoldability(int holdability) throws SQLException { |
266 | this.holdability = holdability; |
267 | } |
268 | |
269 | |
270 | public int getHoldability() throws SQLException { |
271 | return holdability; |
272 | } |
273 | |
274 | |
275 | int getSavepoint() throws SQLException{ |
276 | testClosedConnection(); |
277 | return commitPages.size(); |
278 | } |
279 | |
280 | |
281 | public Savepoint setSavepoint() throws SQLException { |
282 | return new SSSavepoint(getSavepoint(), null, transactionTime); |
283 | } |
284 | |
285 | |
286 | public Savepoint setSavepoint(String name) throws SQLException { |
287 | return new SSSavepoint(getSavepoint(), name, transactionTime); |
288 | } |
289 | |
290 | |
291 | public void rollback(Savepoint savepoint) throws SQLException { |
292 | if(savepoint instanceof SSSavepoint){ |
293 | if(((SSSavepoint)savepoint).transactionTime != transactionTime){ |
294 | throw Utils.createSQLException("Savepoint is not valid for this transaction."); |
295 | } |
296 | rollback( savepoint.getSavepointId() ); |
297 | return; |
298 | } |
299 | throw Utils.createSQLException("Savepoint is not valid for this driver."+savepoint); |
300 | } |
301 | |
302 | |
303 | public void releaseSavepoint(Savepoint savepoint) throws SQLException { |
304 | if(savepoint instanceof SSSavepoint){ |
305 | ((SSSavepoint)savepoint).transactionTime = 0; |
306 | return; |
307 | } |
308 | throw Utils.createSQLException("Savepoint is not valid for this driver."+savepoint); |
309 | } |
310 | |
311 | |
312 | public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { |
313 | //TODO resultSetHoldability |
314 | return new SSStatement( this, resultSetType, resultSetConcurrency); |
315 | } |
316 | public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { |
317 | //TODO resultSetHoldability |
318 | return new SSPreparedStatement( this, sql); |
319 | } |
320 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { |
321 | //TODO resultSetHoldability |
322 | return new SSCallableStatement( this, sql, resultSetType, resultSetConcurrency); |
323 | } |
324 | public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { |
325 | //TODO autoGeneratedKeys |
326 | return new SSPreparedStatement( this, sql); |
327 | } |
328 | public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { |
329 | //TODO autoGeneratedKeys |
330 | return new SSPreparedStatement( this, sql); |
331 | } |
332 | public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { |
333 | //TODO autoGeneratedKeys |
334 | return new SSPreparedStatement( this, sql); |
335 | } |
336 | } |