• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package SQLite.JDBC2z;
2 
3 import java.sql.*;
4 import java.util.*;
5 
6 public class JDBCConnection
7     implements java.sql.Connection, SQLite.BusyHandler {
8 
9     /**
10      * Open database.
11      */
12     protected DatabaseX db;
13 
14     /**
15      * Database URL.
16      */
17     protected String url;
18 
19     /**
20      * Character encoding.
21      */
22     protected String enc;
23 
24     /**
25      * SQLite 3 VFS to use.
26      */
27     protected String vfs;
28 
29     /**
30      * Autocommit flag, true means autocommit.
31      */
32     protected boolean autocommit = true;
33 
34     /**
35      * In-transaction flag.
36      * Can be true only when autocommit false.
37      */
38     protected boolean intrans = false;
39 
40     /**
41      * Timeout for Database.exec()
42      */
43     protected int timeout = 1000000;
44 
45     /**
46      * Use double/julian date representation.
47      */
48     protected boolean useJulian = false;
49 
50     /**
51      * File name of database.
52      */
53     private String dbfile = null;
54 
55     /**
56      * Reference to meta data or null.
57      */
58     private JDBCDatabaseMetaData meta = null;
59 
60     /**
61      * Base time value for timeout handling.
62      */
63     private long t0;
64 
65     /**
66      * Database in readonly mode.
67      */
68     private boolean readonly = false;
69 
70     /**
71      * Transaction isolation mode.
72      */
73     private int trmode = TRANSACTION_SERIALIZABLE;
74 
busy0(DatabaseX db, int count)75     private boolean busy0(DatabaseX db, int count) {
76 	if (count <= 1) {
77 	    t0 = System.currentTimeMillis();
78 	}
79 	if (db != null) {
80 	    long t1 = System.currentTimeMillis();
81 	    if (t1 - t0 > timeout) {
82 		return false;
83 	    }
84 	    db.wait(100);
85 	    return true;
86 	}
87 	return false;
88     }
89 
busy(String table, int count)90     public boolean busy(String table, int count) {
91 	return busy0(db, count);
92     }
93 
busy3(DatabaseX db, int count)94     protected boolean busy3(DatabaseX db, int count) {
95 	if (count <= 1) {
96 	    t0 = System.currentTimeMillis();
97 	}
98 	if (db != null) {
99 	    long t1 = System.currentTimeMillis();
100 	    if (t1 - t0 > timeout) {
101 		return false;
102 	    }
103 	    return true;
104 	}
105 	return false;
106     }
107 
open(boolean readonly)108     private DatabaseX open(boolean readonly) throws SQLException {
109 	DatabaseX dbx = null;
110 	try {
111 	    dbx = new DatabaseX();
112 	    dbx.open(dbfile, readonly ? SQLite.Constants.SQLITE_OPEN_READONLY :
113 		     (SQLite.Constants.SQLITE_OPEN_READWRITE |
114 		      SQLite.Constants.SQLITE_OPEN_CREATE), vfs);
115 	    dbx.set_encoding(enc);
116 	} catch (SQLite.Exception e) {
117 	    throw new SQLException(e.toString());
118 	}
119 	int loop = 0;
120 	while (true) {
121 	    try {
122 		dbx.exec("PRAGMA short_column_names = off;", null);
123 		dbx.exec("PRAGMA full_column_names = on;", null);
124 		dbx.exec("PRAGMA empty_result_callbacks = on;", null);
125 		if (SQLite.Database.version().compareTo("2.6.0") >= 0) {
126 		    dbx.exec("PRAGMA show_datatypes = on;", null);
127 		}
128 	    } catch (SQLite.Exception e) {
129 		if (dbx.last_error() != SQLite.Constants.SQLITE_BUSY ||
130 		    !busy0(dbx, ++loop)) {
131 		    try {
132 			dbx.close();
133 		    } catch (SQLite.Exception ee) {
134 		    }
135 		    throw new SQLException(e.toString());
136 		}
137 		continue;
138 	    }
139 	    break;
140 	}
141 	return dbx;
142     }
143 
JDBCConnection(String url, String enc, String pwd, String drep, String vfs)144     public JDBCConnection(String url, String enc, String pwd, String drep,
145 			  String vfs)
146 	throws SQLException {
147 	if (url.startsWith("sqlite:/")) {
148 	    dbfile = url.substring(8);
149 	} else if (url.startsWith("jdbc:sqlite:/")) {
150 	    dbfile = url.substring(13);
151 	} else {
152 	    throw new SQLException("unsupported url");
153 	}
154 	this.url = url;
155 	this.enc = enc;
156 	this.vfs = vfs;
157 	try {
158 	    db = open(readonly);
159 	    try {
160 		if (pwd != null && pwd.length() > 0) {
161 		    db.key(pwd);
162 		}
163 	    } catch (SQLite.Exception se) {
164 		throw new SQLException("error while setting key");
165 	    }
166 	    db.busy_handler(this);
167 	} catch (SQLException e) {
168 	    if (db != null) {
169 		try {
170 		    db.close();
171 		} catch (SQLite.Exception ee) {
172 		}
173 	    }
174 	    throw e;
175 	}
176 	useJulian = drep != null &&
177 	    (drep.startsWith("j") || drep.startsWith("J"));
178     }
179 
180     /* non-standard */
getSQLiteDatabase()181     public SQLite.Database getSQLiteDatabase() {
182 	return (SQLite.Database) db;
183     }
184 
createStatement()185     public Statement createStatement() {
186 	JDBCStatement s = new JDBCStatement(this);
187 	return s;
188     }
189 
createStatement(int resultSetType, int resultSetConcurrency)190     public Statement createStatement(int resultSetType,
191 				     int resultSetConcurrency)
192 	throws SQLException {
193 	if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
194 	    resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
195 	    resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
196 	    throw new SQLFeatureNotSupportedException("unsupported result set type");
197 	}
198 	if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
199 	    resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
200 	    throw new SQLFeatureNotSupportedException("unsupported result set concurrency");
201 	}
202 	JDBCStatement s = new JDBCStatement(this);
203 	return s;
204     }
205 
getMetaData()206     public DatabaseMetaData getMetaData() throws SQLException {
207 	if (meta == null) {
208 	    meta = new JDBCDatabaseMetaData(this);
209 	}
210 	return meta;
211     }
212 
close()213     public void close() throws SQLException {
214 	try {
215 	    rollback();
216 	} catch (SQLException e) {
217 	    /* ignored */
218 	}
219 	intrans = false;
220 	if (db != null) {
221 	    try {
222 		db.close();
223 		db = null;
224 	    } catch (SQLite.Exception e) {
225 		throw new SQLException(e.toString());
226 	    }
227 	}
228     }
229 
isClosed()230     public boolean isClosed() throws SQLException {
231 	return db == null;
232     }
233 
isReadOnly()234     public boolean isReadOnly() throws SQLException {
235 	return readonly;
236     }
237 
clearWarnings()238     public void clearWarnings() throws SQLException {
239     }
240 
commit()241     public void commit() throws SQLException {
242 	if (db == null) {
243 	    throw new SQLException("stale connection");
244 	}
245 	if (!intrans) {
246 	    return;
247 	}
248 	try {
249 	    db.exec("COMMIT", null);
250 	    intrans = false;
251 	} catch (SQLite.Exception e) {
252 	    throw new SQLException(e.toString());
253 	}
254     }
255 
getAutoCommit()256     public boolean getAutoCommit() throws SQLException {
257 	return autocommit;
258     }
259 
getCatalog()260     public String getCatalog() throws SQLException {
261 	return null;
262     }
263 
getTransactionIsolation()264     public int getTransactionIsolation() throws SQLException {
265 	return trmode;
266     }
267 
getWarnings()268     public SQLWarning getWarnings() throws SQLException {
269 	return null;
270     }
271 
nativeSQL(String sql)272     public String nativeSQL(String sql) throws SQLException {
273 	throw new SQLException("not supported");
274     }
275 
prepareCall(String sql)276     public CallableStatement prepareCall(String sql) throws SQLException {
277 	throw new SQLException("not supported");
278     }
279 
prepareCall(String sql, int x, int y)280     public CallableStatement prepareCall(String sql, int x, int y)
281 	throws SQLException {
282 	throw new SQLFeatureNotSupportedException();
283     }
284 
prepareStatement(String sql)285     public PreparedStatement prepareStatement(String sql) throws SQLException {
286 	JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
287 	return s;
288     }
289 
prepareStatement(String sql, int resultSetType, int resultSetConcurrency)290     public PreparedStatement prepareStatement(String sql, int resultSetType,
291 					      int resultSetConcurrency)
292 	throws SQLException {
293 	if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
294 	    resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
295 	    resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
296 	    throw new SQLFeatureNotSupportedException("unsupported result set type");
297 	}
298 	if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
299 	    resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
300 	    throw new SQLFeatureNotSupportedException("unsupported result set concurrency");
301 	}
302 	JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
303 	return s;
304     }
305 
rollback()306     public void rollback() throws SQLException {
307 	if (db == null) {
308 	    throw new SQLException("stale connection");
309 	}
310 	if (!intrans) {
311 	    return;
312 	}
313 	try {
314 	    db.exec("ROLLBACK", null);
315 	    intrans = false;
316 	} catch (SQLite.Exception e) {
317 	    throw new SQLException(e.toString());
318 	}
319     }
320 
setAutoCommit(boolean ac)321     public void setAutoCommit(boolean ac) throws SQLException {
322 	if (ac && intrans && db != null) {
323 	    try {
324 		db.exec("ROLLBACK", null);
325 	    } catch (SQLite.Exception e) {
326 		throw new SQLException(e.toString());
327 	    } finally {
328 		intrans = false;
329 	    }
330 	}
331 	autocommit = ac;
332     }
333 
setCatalog(String catalog)334     public void setCatalog(String catalog) throws SQLException {
335     }
336 
setReadOnly(boolean ro)337     public void setReadOnly(boolean ro) throws SQLException {
338 	if (intrans) {
339 	    throw new SQLException("incomplete transaction");
340 	}
341 	if (ro != readonly) {
342 	    DatabaseX dbx = null;
343 	    try {
344 		dbx = open(ro);
345 		db.close();
346 		db = dbx;
347 		dbx = null;
348 		readonly = ro;
349 	    } catch (SQLException e) {
350 		throw e;
351 	    } catch (SQLite.Exception ee) {
352 		if (dbx != null) {
353 		    try {
354 			dbx.close();
355 		    } catch (SQLite.Exception eee) {
356 		    }
357 		}
358 		throw new SQLException(ee.toString());
359 	    }
360 	}
361     }
362 
setTransactionIsolation(int level)363     public void setTransactionIsolation(int level) throws SQLException {
364 	if (db.is3() && SQLite.JDBCDriver.sharedCache) {
365 	    String flag = null;
366 	    if (level == TRANSACTION_READ_UNCOMMITTED &&
367 		trmode != TRANSACTION_READ_UNCOMMITTED) {
368 		flag = "on";
369 	    } else if (level == TRANSACTION_SERIALIZABLE &&
370 		       trmode != TRANSACTION_SERIALIZABLE) {
371 		flag = "off";
372 	    }
373 	    if (flag != null) {
374 		try {
375 		    db.exec("PRAGMA read_uncommitted = " + flag + ";", null);
376 		    trmode = level;
377 		} catch (java.lang.Exception e) {
378 		}
379 	    }
380 	}
381 	if (level != trmode) {
382 	    throw new SQLException("not supported");
383 	}
384     }
385 
getTypeMap()386     public java.util.Map<String, Class<?>> getTypeMap() throws SQLException {
387 	throw new SQLFeatureNotSupportedException();
388     }
389 
setTypeMap(java.util.Map map)390     public void setTypeMap(java.util.Map map) throws SQLException {
391 	throw new SQLFeatureNotSupportedException();
392     }
393 
getHoldability()394     public int getHoldability() throws SQLException {
395 	return ResultSet.HOLD_CURSORS_OVER_COMMIT;
396     }
397 
setHoldability(int holdability)398     public void setHoldability(int holdability) throws SQLException {
399 	if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
400 	    return;
401 	}
402 	throw new SQLFeatureNotSupportedException("unsupported holdability");
403     }
404 
setSavepoint()405     public Savepoint setSavepoint() throws SQLException {
406 	throw new SQLFeatureNotSupportedException();
407     }
408 
setSavepoint(String name)409     public Savepoint setSavepoint(String name) throws SQLException {
410 	throw new SQLFeatureNotSupportedException();
411     }
412 
rollback(Savepoint x)413     public void rollback(Savepoint x) throws SQLException {
414 	throw new SQLFeatureNotSupportedException();
415     }
416 
releaseSavepoint(Savepoint x)417     public void releaseSavepoint(Savepoint x) throws SQLException {
418 	throw new SQLFeatureNotSupportedException();
419     }
420 
createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)421     public Statement createStatement(int resultSetType,
422 				     int resultSetConcurrency,
423 				     int resultSetHoldability)
424 	throws SQLException {
425 	if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
426 	    throw new SQLFeatureNotSupportedException("unsupported holdability");
427 	}
428 	return createStatement(resultSetType, resultSetConcurrency);
429     }
430 
prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)431     public PreparedStatement prepareStatement(String sql, int resultSetType,
432 					      int resultSetConcurrency,
433 					      int resultSetHoldability)
434 	throws SQLException {
435 	if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
436 	    throw new SQLFeatureNotSupportedException("unsupported holdability");
437 	}
438 	return prepareStatement(sql, resultSetType, resultSetConcurrency);
439     }
440 
prepareCall(String sql, int x, int y, int z)441     public CallableStatement prepareCall(String sql, int x, int y, int z)
442 	throws SQLException {
443 	throw new SQLFeatureNotSupportedException();
444     }
445 
prepareStatement(String sql, int autokeys)446     public PreparedStatement prepareStatement(String sql, int autokeys)
447 	throws SQLException {
448 	if (autokeys != Statement.NO_GENERATED_KEYS) {
449 	    throw new SQLFeatureNotSupportedException("generated keys not supported");
450 	}
451 	return prepareStatement(sql);
452     }
453 
prepareStatement(String sql, int colIndexes[])454     public PreparedStatement prepareStatement(String sql, int colIndexes[])
455 	throws SQLException {
456 	throw new SQLFeatureNotSupportedException();
457     }
458 
prepareStatement(String sql, String columns[])459     public PreparedStatement prepareStatement(String sql, String columns[])
460 	throws SQLException {
461 	throw new SQLFeatureNotSupportedException();
462     }
463 
createClob()464     public Clob createClob() throws SQLException {
465 	throw new SQLFeatureNotSupportedException();
466     }
467 
createBlob()468     public Blob createBlob() throws SQLException {
469 	throw new SQLFeatureNotSupportedException();
470     }
471 
createNClob()472     public NClob createNClob() throws SQLException {
473 	throw new SQLFeatureNotSupportedException();
474     }
475 
createSQLXML()476     public SQLXML createSQLXML() throws SQLException {
477 	throw new SQLFeatureNotSupportedException();
478     }
479 
isValid(int timeout)480     public boolean isValid(int timeout) throws SQLException {
481         return true;
482     }
483 
setClientInfo(String name, String value)484     public void setClientInfo(String name, String value)
485 	throws SQLClientInfoException {
486 	throw new SQLClientInfoException();
487     }
488 
setClientInfo(Properties prop)489     public void setClientInfo(Properties prop) throws SQLClientInfoException {
490 	throw new SQLClientInfoException();
491     }
492 
getClientInfo(String name)493     public String getClientInfo(String name) throws SQLException {
494 	throw new SQLException("unsupported");
495     }
496 
getClientInfo()497     public Properties getClientInfo() throws SQLException {
498         return new Properties();
499     }
500 
createArrayOf(String type, Object[] elems)501     public Array createArrayOf(String type, Object[] elems)
502  	throws SQLException {
503 	throw new SQLFeatureNotSupportedException();
504     }
505 
createStruct(String type, Object[] attrs)506     public Struct createStruct(String type, Object[] attrs)
507 	throws SQLException {
508 	throw new SQLFeatureNotSupportedException();
509     }
510 
unwrap(java.lang.Class<T> iface)511     public <T> T unwrap(java.lang.Class<T> iface) throws SQLException {
512 	throw new SQLException("unsupported");
513     }
514 
isWrapperFor(java.lang.Class iface)515     public boolean isWrapperFor(java.lang.Class iface) throws SQLException {
516 	return false;
517     }
518 
519 }
520 
521 class DatabaseX extends SQLite.Database {
522 
523     static Object lock = new Object();
524 
DatabaseX()525     public DatabaseX() {
526 	super();
527     }
528 
wait(int ms)529     void wait(int ms) {
530 	try {
531 	    synchronized (lock) {
532 		lock.wait(ms);
533 	    }
534 	} catch (java.lang.Exception e) {
535 	}
536     }
537 
exec(String sql, SQLite.Callback cb)538     public void exec(String sql, SQLite.Callback cb)
539 	throws SQLite.Exception {
540 	super.exec(sql, cb);
541 	synchronized (lock) {
542 	    lock.notifyAll();
543 	}
544     }
545 
exec(String sql, SQLite.Callback cb, String args[])546     public void exec(String sql, SQLite.Callback cb, String args[])
547 	throws SQLite.Exception {
548 	super.exec(sql, cb, args);
549 	synchronized (lock) {
550 	    lock.notifyAll();
551 	}
552     }
553 
get_table(String sql, String args[])554     public SQLite.TableResult get_table(String sql, String args[])
555 	throws SQLite.Exception {
556 	SQLite.TableResult ret = super.get_table(sql, args);
557 	synchronized (lock) {
558 	    lock.notifyAll();
559 	}
560 	return ret;
561     }
562 
get_table(String sql, String args[], SQLite.TableResult tbl)563     public void get_table(String sql, String args[], SQLite.TableResult tbl)
564 	throws SQLite.Exception {
565 	super.get_table(sql, args, tbl);
566 	synchronized (lock) {
567 	    lock.notifyAll();
568 	}
569     }
570 
571 }
572