mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-17 01:26:25 +00:00
509 lines
12 KiB
Java
509 lines
12 KiB
Java
|
package SQLite.JDBC0;
|
||
|
|
||
|
import java.sql.*;
|
||
|
import java.util.*;
|
||
|
|
||
|
public class JDBCConnection
|
||
|
implements java.sql.Connection, SQLite.BusyHandler {
|
||
|
|
||
|
/**
|
||
|
* Open database.
|
||
|
*/
|
||
|
protected DatabaseX db;
|
||
|
|
||
|
/**
|
||
|
* Database URL.
|
||
|
*/
|
||
|
protected String url;
|
||
|
|
||
|
/**
|
||
|
* Character encoding.
|
||
|
*/
|
||
|
protected String enc;
|
||
|
|
||
|
/**
|
||
|
* SQLite 3 VFS to use.
|
||
|
*/
|
||
|
protected String vfs;
|
||
|
|
||
|
/**
|
||
|
* Autocommit flag, true means autocommit.
|
||
|
*/
|
||
|
protected boolean autocommit = true;
|
||
|
|
||
|
/**
|
||
|
* In-transaction flag.
|
||
|
* Can be true only when autocommit false.
|
||
|
*/
|
||
|
protected boolean intrans = false;
|
||
|
|
||
|
/**
|
||
|
* Timeout for Database.exec()
|
||
|
*/
|
||
|
protected int timeout = 1000000;
|
||
|
|
||
|
/**
|
||
|
* Use double/julian date representation.
|
||
|
*/
|
||
|
protected boolean useJulian = false;
|
||
|
|
||
|
/**
|
||
|
* File name of database.
|
||
|
*/
|
||
|
private String dbfile = null;
|
||
|
|
||
|
/**
|
||
|
* Reference to meta data or null.
|
||
|
*/
|
||
|
private JDBCDatabaseMetaData meta = null;
|
||
|
|
||
|
/**
|
||
|
* Base time value for timeout handling.
|
||
|
*/
|
||
|
private long t0;
|
||
|
|
||
|
/**
|
||
|
* Database in readonly mode.
|
||
|
*/
|
||
|
private boolean readonly = false;
|
||
|
|
||
|
/**
|
||
|
* Transaction isolation mode.
|
||
|
*/
|
||
|
private int trmode = TRANSACTION_SERIALIZABLE;
|
||
|
|
||
|
private boolean busy0(DatabaseX db, int count) {
|
||
|
if (count <= 1) {
|
||
|
t0 = System.currentTimeMillis();
|
||
|
}
|
||
|
if (db != null) {
|
||
|
long t1 = System.currentTimeMillis();
|
||
|
if (t1 - t0 > timeout) {
|
||
|
return false;
|
||
|
}
|
||
|
db.wait(100);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean busy(String table, int count) {
|
||
|
return busy0(db, count);
|
||
|
}
|
||
|
|
||
|
protected boolean busy3(DatabaseX db, int count) {
|
||
|
if (count <= 1) {
|
||
|
t0 = System.currentTimeMillis();
|
||
|
}
|
||
|
if (db != null) {
|
||
|
long t1 = System.currentTimeMillis();
|
||
|
if (t1 - t0 > timeout) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private DatabaseX open(boolean readonly) throws SQLException {
|
||
|
DatabaseX dbx = null;
|
||
|
try {
|
||
|
dbx = new DatabaseX();
|
||
|
dbx.open(dbfile, readonly ? SQLite.Constants.SQLITE_OPEN_READONLY :
|
||
|
(SQLite.Constants.SQLITE_OPEN_READWRITE |
|
||
|
SQLite.Constants.SQLITE_OPEN_CREATE), vfs);
|
||
|
dbx.set_encoding(enc);
|
||
|
} catch (SQLite.Exception e) {
|
||
|
throw new SQLException(e.toString());
|
||
|
}
|
||
|
int loop = 0;
|
||
|
while (true) {
|
||
|
try {
|
||
|
dbx.exec("PRAGMA short_column_names = off;", null);
|
||
|
dbx.exec("PRAGMA full_column_names = on;", null);
|
||
|
dbx.exec("PRAGMA empty_result_callbacks = on;", null);
|
||
|
if (SQLite.Database.version().compareTo("2.6.0") >= 0) {
|
||
|
dbx.exec("PRAGMA show_datatypes = on;", null);
|
||
|
}
|
||
|
} catch (SQLite.Exception e) {
|
||
|
if (dbx.last_error() != SQLite.Constants.SQLITE_BUSY ||
|
||
|
!busy0(dbx, ++loop)) {
|
||
|
try {
|
||
|
dbx.close();
|
||
|
} catch (SQLite.Exception ee) {
|
||
|
}
|
||
|
throw new SQLException(e.toString());
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return dbx;
|
||
|
}
|
||
|
|
||
|
public JDBCConnection(String url, String enc, String pwd, String drep,
|
||
|
String vfs)
|
||
|
throws SQLException {
|
||
|
if (url.startsWith("sqlite:/")) {
|
||
|
dbfile = url.substring(8);
|
||
|
} else if (url.startsWith("jdbc:sqlite:/")) {
|
||
|
dbfile = url.substring(13);
|
||
|
} else {
|
||
|
throw new SQLException("unsupported url");
|
||
|
}
|
||
|
this.url = url;
|
||
|
this.enc = enc;
|
||
|
this.vfs = vfs;
|
||
|
try {
|
||
|
db = open(readonly);
|
||
|
try {
|
||
|
if (pwd != null && pwd.length() > 0) {
|
||
|
db.key(pwd);
|
||
|
}
|
||
|
} catch (SQLite.Exception se) {
|
||
|
throw new SQLException("error while setting key");
|
||
|
}
|
||
|
db.busy_handler(this);
|
||
|
} catch (SQLException e) {
|
||
|
if (db != null) {
|
||
|
try {
|
||
|
db.close();
|
||
|
} catch (SQLite.Exception ee) {
|
||
|
}
|
||
|
}
|
||
|
throw e;
|
||
|
}
|
||
|
useJulian = drep != null &&
|
||
|
(drep.startsWith("j") || drep.startsWith("J"));
|
||
|
}
|
||
|
|
||
|
/* non-standard */
|
||
|
public SQLite.Database getSQLiteDatabase() {
|
||
|
return (SQLite.Database) db;
|
||
|
}
|
||
|
|
||
|
public Statement createStatement() {
|
||
|
JDBCStatement s = new JDBCStatement(this);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
public Statement createStatement(int resultSetType,
|
||
|
int resultSetConcurrency)
|
||
|
throws SQLException {
|
||
|
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
|
||
|
resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
|
||
|
resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
|
||
|
throw new SQLException("unsupported result set type");
|
||
|
}
|
||
|
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
|
||
|
resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
|
||
|
throw new SQLException("unsupported result set concurrency");
|
||
|
}
|
||
|
JDBCStatement s = new JDBCStatement(this);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
public DatabaseMetaData getMetaData() throws SQLException {
|
||
|
if (meta == null) {
|
||
|
meta = new JDBCDatabaseMetaData(this);
|
||
|
}
|
||
|
return meta;
|
||
|
}
|
||
|
|
||
|
public void close() throws SQLException {
|
||
|
try {
|
||
|
rollback();
|
||
|
} catch (SQLException e) {
|
||
|
/* ignored */
|
||
|
}
|
||
|
intrans = false;
|
||
|
if (db != null) {
|
||
|
try {
|
||
|
db.close();
|
||
|
db = null;
|
||
|
} catch (SQLite.Exception e) {
|
||
|
throw new SQLException(e.toString());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean isClosed() throws SQLException {
|
||
|
return db == null;
|
||
|
}
|
||
|
|
||
|
public boolean isReadOnly() throws SQLException {
|
||
|
return readonly;
|
||
|
}
|
||
|
|
||
|
public void clearWarnings() throws SQLException {
|
||
|
}
|
||
|
|
||
|
public void commit() throws SQLException {
|
||
|
if (db == null) {
|
||
|
throw new SQLException("stale connection");
|
||
|
}
|
||
|
if (!intrans) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
db.exec("COMMIT", null);
|
||
|
intrans = false;
|
||
|
} catch (SQLite.Exception e) {
|
||
|
throw new SQLException(e.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean getAutoCommit() throws SQLException {
|
||
|
return autocommit;
|
||
|
}
|
||
|
|
||
|
public String getCatalog() throws SQLException {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public int getTransactionIsolation() throws SQLException {
|
||
|
return trmode;
|
||
|
}
|
||
|
|
||
|
public SQLWarning getWarnings() throws SQLException {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public String nativeSQL(String sql) throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public CallableStatement prepareCall(String sql) throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public CallableStatement prepareCall(String sql, int x, int y)
|
||
|
throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql) throws SQLException {
|
||
|
JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql, int resultSetType,
|
||
|
int resultSetConcurrency)
|
||
|
throws SQLException {
|
||
|
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY &&
|
||
|
resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE &&
|
||
|
resultSetType != ResultSet.TYPE_SCROLL_SENSITIVE) {
|
||
|
throw new SQLException("unsupported result set type");
|
||
|
}
|
||
|
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY &&
|
||
|
resultSetConcurrency != ResultSet.CONCUR_UPDATABLE) {
|
||
|
throw new SQLException("unsupported result set concurrency");
|
||
|
}
|
||
|
JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
public void rollback() throws SQLException {
|
||
|
if (db == null) {
|
||
|
throw new SQLException("stale connection");
|
||
|
}
|
||
|
if (!intrans) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
db.exec("ROLLBACK", null);
|
||
|
intrans = false;
|
||
|
} catch (SQLite.Exception e) {
|
||
|
throw new SQLException(e.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setAutoCommit(boolean ac) throws SQLException {
|
||
|
if (ac && intrans && db != null) {
|
||
|
try {
|
||
|
db.exec("ROLLBACK", null);
|
||
|
} catch (SQLite.Exception e) {
|
||
|
throw new SQLException(e.toString());
|
||
|
} finally {
|
||
|
intrans = false;
|
||
|
}
|
||
|
}
|
||
|
autocommit = ac;
|
||
|
}
|
||
|
|
||
|
public void setCatalog(String catalog) throws SQLException {
|
||
|
}
|
||
|
|
||
|
public void setReadOnly(boolean ro) throws SQLException {
|
||
|
if (intrans) {
|
||
|
throw new SQLException("incomplete transaction");
|
||
|
}
|
||
|
if (ro != readonly) {
|
||
|
DatabaseX dbx = null;
|
||
|
try {
|
||
|
dbx = open(ro);
|
||
|
db.close();
|
||
|
db = dbx;
|
||
|
dbx = null;
|
||
|
readonly = ro;
|
||
|
} catch (SQLException e) {
|
||
|
throw e;
|
||
|
} catch (SQLite.Exception ee) {
|
||
|
if (dbx != null) {
|
||
|
try {
|
||
|
dbx.close();
|
||
|
} catch (SQLite.Exception eee) {
|
||
|
}
|
||
|
}
|
||
|
throw new SQLException(ee.toString());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setTransactionIsolation(int level) throws SQLException {
|
||
|
if (db.is3() && SQLite.JDBC.sharedCache) {
|
||
|
String flag = null;
|
||
|
if (level == TRANSACTION_READ_UNCOMMITTED &&
|
||
|
trmode != TRANSACTION_READ_UNCOMMITTED) {
|
||
|
flag = "on";
|
||
|
} else if (level == TRANSACTION_SERIALIZABLE &&
|
||
|
trmode != TRANSACTION_SERIALIZABLE) {
|
||
|
flag = "off";
|
||
|
}
|
||
|
if (flag != null) {
|
||
|
try {
|
||
|
db.exec("PRAGMA read_uncommitted = " + flag + ";", null);
|
||
|
trmode = level;
|
||
|
} catch (java.lang.Exception e) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (level != trmode) {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int getHoldability() throws SQLException {
|
||
|
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
|
||
|
}
|
||
|
|
||
|
public void setHoldability(int holdability) throws SQLException {
|
||
|
if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
||
|
return;
|
||
|
}
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public Savepoint setSavepoint() throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public Savepoint setSavepoint(String name) throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public void rollback(Savepoint x) throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public void releaseSavepoint(Savepoint x) throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public Statement createStatement(int resultSetType,
|
||
|
int resultSetConcurrency,
|
||
|
int resultSetHoldability)
|
||
|
throws SQLException {
|
||
|
if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
return createStatement(resultSetType, resultSetConcurrency);
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql, int resultSetType,
|
||
|
int resultSetConcurrency,
|
||
|
int resultSetHoldability)
|
||
|
throws SQLException {
|
||
|
if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
return prepareStatement(sql, resultSetType, resultSetConcurrency);
|
||
|
}
|
||
|
|
||
|
public CallableStatement prepareCall(String sql, int x, int y, int z)
|
||
|
throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql, int autokeys)
|
||
|
throws SQLException {
|
||
|
if (autokeys != Statement.NO_GENERATED_KEYS) {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
return prepareStatement(sql);
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql, int colIndexes[])
|
||
|
throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
public PreparedStatement prepareStatement(String sql, String columns[])
|
||
|
throws SQLException {
|
||
|
throw new SQLException("not supported");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
class DatabaseX extends SQLite.Database {
|
||
|
|
||
|
static Object lock = new Object();
|
||
|
|
||
|
public DatabaseX() {
|
||
|
super();
|
||
|
}
|
||
|
|
||
|
void wait(int ms) {
|
||
|
try {
|
||
|
synchronized (lock) {
|
||
|
lock.wait(ms);
|
||
|
}
|
||
|
} catch (java.lang.Exception e) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void exec(String sql, SQLite.Callback cb)
|
||
|
throws SQLite.Exception {
|
||
|
super.exec(sql, cb);
|
||
|
synchronized (lock) {
|
||
|
lock.notifyAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void exec(String sql, SQLite.Callback cb, String args[])
|
||
|
throws SQLite.Exception {
|
||
|
super.exec(sql, cb, args);
|
||
|
synchronized (lock) {
|
||
|
lock.notifyAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public SQLite.TableResult get_table(String sql, String args[])
|
||
|
throws SQLite.Exception {
|
||
|
SQLite.TableResult ret = super.get_table(sql, args);
|
||
|
synchronized (lock) {
|
||
|
lock.notifyAll();
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
public void get_table(String sql, String args[], SQLite.TableResult tbl)
|
||
|
throws SQLite.Exception {
|
||
|
super.get_table(sql, args, tbl);
|
||
|
synchronized (lock) {
|
||
|
lock.notifyAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|