Merge 'bindings/java: Implement LimboConnection close() ' from Kim Seon Woo

## Purpose of thie PR
- Implement `close()` method for `LimboConnection` and `JDBC4Connection`
## Changes
- Instead of closing the database when closing connections, close the
connection instead
## References
- https://github.com/tursodatabase/limbo/issues/615

Closes #797
This commit is contained in:
Pekka Enberg
2025-01-27 14:51:04 +02:00
4 changed files with 47 additions and 29 deletions

View File

@@ -12,7 +12,6 @@ use std::rc::Rc;
use std::sync::Arc;
#[derive(Clone)]
#[allow(dead_code)]
pub struct LimboConnection {
// Because java's LimboConnection is 1:1 mapped to limbo connection, we can use Rc
pub(crate) conn: Rc<Connection>,
@@ -29,7 +28,6 @@ impl LimboConnection {
Box::into_raw(Box::new(self)) as jlong
}
#[allow(dead_code)]
pub fn drop(ptr: jlong) {
let _boxed = unsafe { Box::from_raw(ptr as *mut LimboConnection) };
}
@@ -43,6 +41,15 @@ pub fn to_limbo_connection(ptr: jlong) -> Result<&'static mut LimboConnection> {
}
}
#[no_mangle]
pub extern "system" fn Java_org_github_tursodatabase_core_LimboConnection__1close<'local>(
_env: JNIEnv<'local>,
_obj: JObject<'local>,
connection_ptr: jlong,
) {
LimboConnection::drop(connection_ptr);
}
#[no_mangle]
pub extern "system" fn Java_org_github_tursodatabase_core_LimboConnection_prepareUtf8<'local>(
mut env: JNIEnv<'local>,

View File

@@ -16,6 +16,7 @@ public abstract class LimboConnection implements Connection {
private final long connectionPtr;
private final AbstractDB database;
private boolean closed;
public LimboConnection(String url, String filePath) throws SQLException {
this(url, filePath, new Properties());
@@ -28,24 +29,8 @@ public abstract class LimboConnection implements Connection {
* @param filePath path to file
*/
public LimboConnection(String url, String filePath, Properties properties) throws SQLException {
AbstractDB db = null;
try {
db = open(url, filePath, properties);
} catch (Throwable t) {
try {
if (db != null) {
db.close();
}
} catch (Throwable t2) {
t.addSuppressed(t2);
}
throw t;
}
this.database = db;
this.connectionPtr = db.connect();
this.database = open(url, filePath, properties);
this.connectionPtr = this.database.connect();
}
private static AbstractDB open(String url, String filePath, Properties properties)
@@ -59,13 +44,18 @@ public abstract class LimboConnection implements Connection {
@Override
public void close() throws SQLException {
if (isClosed()) return;
database.close();
if (isClosed()) {
return;
}
this._close(this.connectionPtr);
this.closed = true;
}
private native void _close(long connectionPtr);
@Override
public boolean isClosed() throws SQLException {
return database.isClosed();
return closed;
}
public AbstractDB getDatabase() {
@@ -114,12 +104,15 @@ public abstract class LimboConnection implements Connection {
*/
protected void checkCursor(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) {
throw new SQLException("SQLite only supports TYPE_FORWARD_ONLY cursors");
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
}
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) {
throw new SQLException("SQLite only supports CONCUR_READ_ONLY cursors");
if (resultSetHoldability != ResultSet.CLOSE_CURSORS_AT_COMMIT)
}
if (resultSetHoldability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
throw new SQLException("SQLite only supports closing cursors at commit");
}
}
public void setBusyTimeout(int busyTimeout) {

View File

@@ -83,13 +83,12 @@ public class JDBC4Connection extends LimboConnection {
@Override
public void close() throws SQLException {
// TODO
super.close();
}
@Override
public boolean isClosed() throws SQLException {
// TODO
return false;
return super.isClosed();
}
@Override

View File

@@ -65,4 +65,23 @@ class JDBC4ConnectionTest {
void prepare_simple_create_table() throws Exception {
connection.prepare("CREATE TABLE users (id INT PRIMARY KEY, username TEXT)");
}
@Test
void calling_close_multiple_times_throws_no_exception() throws Exception {
assertFalse(connection.isClosed());
connection.close();
assertTrue(connection.isClosed());
connection.close();
}
@Test
void calling_methods_on_closed_connection_should_throw_exception() throws Exception {
connection.close();
assertTrue(connection.isClosed());
assertThrows(
SQLException.class,
() ->
connection.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, -1));
}
}