mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-04 00:44:19 +01:00
Merge branch 'main' into java-bindings-database-metadata
This commit is contained in:
@@ -1,75 +0,0 @@
|
||||
package org.github.tursodatabase.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Interface to Limbo. It provides some helper functions used by other parts of the driver. The goal
|
||||
* of the helper functions here are not only to provide functionality, but to handle contractual
|
||||
* differences between the JDBC specification and the Limbo API.
|
||||
*/
|
||||
public abstract class AbstractDB {
|
||||
protected final String url;
|
||||
protected final String filePath;
|
||||
private final AtomicBoolean closed = new AtomicBoolean(true);
|
||||
|
||||
public AbstractDB(String url, String filePath) {
|
||||
this.url = url;
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed.get();
|
||||
}
|
||||
|
||||
/** Aborts any pending operation and returns at its earliest opportunity. */
|
||||
public abstract void interrupt() throws SQLException;
|
||||
|
||||
/**
|
||||
* Creates an SQLite interface to a database for the given connection.
|
||||
*
|
||||
* @param openFlags Flags for opening the database.
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public final synchronized void open(int openFlags) throws SQLException {
|
||||
open0(filePath, openFlags);
|
||||
}
|
||||
|
||||
protected abstract void open0(String fileName, int openFlags) throws SQLException;
|
||||
|
||||
/**
|
||||
* Closes a database connection and finalizes any remaining statements before the closing
|
||||
* operation.
|
||||
*
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
public final synchronized void close() throws SQLException {
|
||||
// TODO: add implementation
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a database.
|
||||
*
|
||||
* @return Pointer to the connection.
|
||||
*/
|
||||
public abstract long connect() throws SQLException;
|
||||
|
||||
/**
|
||||
* Creates an SQLite interface to a database with the provided open flags.
|
||||
*
|
||||
* @param fileName The database to open.
|
||||
* @param openFlags Flags for opening the database.
|
||||
* @return pointer to database instance
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
protected abstract long openUtf8(byte[] fileName, int openFlags) throws SQLException;
|
||||
|
||||
/**
|
||||
* Closes the SQLite interface to a database.
|
||||
*
|
||||
* @throws SQLException if a database access error occurs.
|
||||
*/
|
||||
protected abstract void close0() throws SQLException;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class LimboConnection {
|
||||
|
||||
private final String url;
|
||||
private final long connectionPtr;
|
||||
private final AbstractDB database;
|
||||
private final LimboDB database;
|
||||
private boolean closed;
|
||||
|
||||
public LimboConnection(String url, String filePath) throws SQLException {
|
||||
@@ -34,7 +34,7 @@ public class LimboConnection {
|
||||
this.connectionPtr = this.database.connect();
|
||||
}
|
||||
|
||||
private static AbstractDB open(String url, String filePath, Properties properties)
|
||||
private static LimboDB open(String url, String filePath, Properties properties)
|
||||
throws SQLException {
|
||||
return LimboDBFactory.open(url, filePath, properties);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class LimboConnection {
|
||||
return closed;
|
||||
}
|
||||
|
||||
public AbstractDB getDatabase() {
|
||||
public LimboDB getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import org.github.tursodatabase.LimboErrorCode;
|
||||
import org.github.tursodatabase.annotations.NativeInvocation;
|
||||
import org.github.tursodatabase.annotations.VisibleForTesting;
|
||||
@@ -16,14 +15,15 @@ import org.github.tursodatabase.utils.Logger;
|
||||
import org.github.tursodatabase.utils.LoggerFactory;
|
||||
|
||||
/** This class provides a thin JNI layer over the SQLite3 C API. */
|
||||
public final class LimboDB extends AbstractDB {
|
||||
public final class LimboDB implements AutoCloseable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LimboDB.class);
|
||||
// Pointer to database instance
|
||||
private long dbPointer;
|
||||
private boolean isOpen;
|
||||
|
||||
private final String url;
|
||||
private final String filePath;
|
||||
private static boolean isLoaded;
|
||||
private ReentrantLock dbLock = new ReentrantLock();
|
||||
|
||||
static {
|
||||
if ("The Android Project".equals(System.getProperty("java.vm.vendor"))) {
|
||||
@@ -176,23 +176,26 @@ public final class LimboDB extends AbstractDB {
|
||||
|
||||
// TODO: receive config as argument
|
||||
private LimboDB(String url, String filePath) {
|
||||
super(url, filePath);
|
||||
this.url = url;
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
// TODO: add support for JNI
|
||||
@Override
|
||||
protected native long openUtf8(byte[] file, int openFlags) throws SQLException;
|
||||
|
||||
// TODO: add support for JNI
|
||||
@Override
|
||||
protected native void close0() throws SQLException;
|
||||
|
||||
// TODO: add support for JNI
|
||||
@Override
|
||||
public native void interrupt();
|
||||
|
||||
@Override
|
||||
protected void open0(String filePath, int openFlags) throws SQLException {
|
||||
public boolean isClosed() {
|
||||
return !this.isOpen;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return this.isOpen;
|
||||
}
|
||||
|
||||
public void open(int openFlags) throws SQLException {
|
||||
open0(filePath, openFlags);
|
||||
}
|
||||
|
||||
private void open0(String filePath, int openFlags) throws SQLException {
|
||||
if (isOpen) {
|
||||
throw LimboExceptionUtils.buildLimboException(
|
||||
LimboErrorCode.LIMBO_ETC.code, "Already opened");
|
||||
@@ -209,13 +212,24 @@ public final class LimboDB extends AbstractDB {
|
||||
isOpen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
private native long openUtf8(byte[] file, int openFlags) throws SQLException;
|
||||
|
||||
public long connect() throws SQLException {
|
||||
return connect0(dbPointer);
|
||||
}
|
||||
|
||||
private native long connect0(long databasePtr) throws SQLException;
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (!isOpen) return;
|
||||
|
||||
close0(dbPointer);
|
||||
isOpen = false;
|
||||
}
|
||||
|
||||
private native void close0(long databasePtr) throws SQLException;
|
||||
|
||||
@VisibleForTesting
|
||||
native void throwJavaException(int errorCode) throws SQLException;
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ public class JDBC4Connection implements Connection {
|
||||
|
||||
private final LimboConnection connection;
|
||||
|
||||
private Map<String, Class<?>> typeMap = new HashMap<>();
|
||||
|
||||
public JDBC4Connection(String url, String filePath) throws SQLException {
|
||||
this.connection = new LimboConnection(url, filePath);
|
||||
}
|
||||
@@ -47,22 +49,8 @@ public class JDBC4Connection implements Connection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql) throws SQLException {
|
||||
return new JDBC4PreparedStatement(this, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public String nativeSQL(String sql) throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,13 +103,10 @@ public class JDBC4Connection implements Connection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String catalog) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
public void setCatalog(String catalog) throws SQLException {}
|
||||
|
||||
@Override
|
||||
public String getCatalog() throws SQLException {
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -148,41 +133,30 @@ public class JDBC4Connection implements Connection {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getTypeMap() throws SQLException {
|
||||
// TODO
|
||||
return new HashMap<>();
|
||||
return this.typeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoldability(int holdability) throws SQLException {
|
||||
// TODO
|
||||
synchronized (this) {
|
||||
this.typeMap = map;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHoldability() throws SQLException {
|
||||
return 0;
|
||||
connection.checkOpen();
|
||||
return ResultSet.CLOSE_CURSORS_AT_COMMIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoldability(int holdability) throws SQLException {
|
||||
connection.checkOpen();
|
||||
if (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
|
||||
throw new SQLException("Limbo only supports CLOSE_CURSORS_AT_COMMIT");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,76 +184,95 @@ public class JDBC4Connection implements Connection {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(
|
||||
String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||
return prepareCall(
|
||||
sql,
|
||||
ResultSet.TYPE_FORWARD_ONLY,
|
||||
ResultSet.CONCUR_READ_ONLY,
|
||||
ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
return prepareCall(sql, resultSetType, resultSetConcurrency, ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public CallableStatement prepareCall(
|
||||
String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
throw new SQLException("Limbo does not support stored procedures");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql) throws SQLException {
|
||||
return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
return prepareStatement(
|
||||
sql, resultSetType, resultSetConcurrency, ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(
|
||||
String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
|
||||
throws SQLException {
|
||||
connection.checkOpen();
|
||||
connection.checkCursor(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
return new JDBC4PreparedStatement(this, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
// TODO: maybe we can enhance this functionality by using columnIndexes
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
// TODO: maybe we can enhance this functionality by using columnNames
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Clob createClob() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
throw new SQLFeatureNotSupportedException("createClob not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Blob createBlob() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
throw new SQLFeatureNotSupportedException("createBlob not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public NClob createNClob() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
throw new SQLFeatureNotSupportedException("createNClob not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public SQLXML createSQLXML() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
throw new SQLFeatureNotSupportedException("createSQLXML not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int timeout) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
if (isClosed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (Statement statement = createStatement()) {
|
||||
return statement.execute("select 1;");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -333,7 +326,11 @@ public class JDBC4Connection implements Connection {
|
||||
|
||||
@Override
|
||||
public void abort(Executor executor) throws SQLException {
|
||||
// TODO
|
||||
if (isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import org.github.tursodatabase.annotations.SkipNullableCheck;
|
||||
import org.github.tursodatabase.core.LimboResultSet;
|
||||
|
||||
public class JDBC4PreparedStatement extends JDBC4Statement implements PreparedStatement {
|
||||
|
||||
@@ -45,7 +46,11 @@ public class JDBC4PreparedStatement extends JDBC4Statement implements PreparedSt
|
||||
|
||||
@Override
|
||||
public int executeUpdate() throws SQLException {
|
||||
// TODO
|
||||
requireNonNull(this.statement);
|
||||
final LimboResultSet resultSet = statement.getResultSet();
|
||||
resultSet.consumeAll();
|
||||
|
||||
// TODO: return updated count
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,10 +252,8 @@ public class JDBC4Statement implements Statement {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Connection getConnection() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -273,32 +271,32 @@ public class JDBC4Statement implements Statement {
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
// TODO: enhance
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
// TODO: enhance
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
// TODO: enhance
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
// TODO: enhance
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
// TODO: enhance
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.github.tursodatabase.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import org.github.tursodatabase.LimboErrorCode;
|
||||
@@ -13,16 +14,27 @@ public class LimboDBTest {
|
||||
|
||||
@Test
|
||||
void db_should_open_normally() throws Exception {
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB.load();
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB db = LimboDB.create("jdbc:sqlite" + dbPath, dbPath);
|
||||
db.open(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_exception_when_opened_twice() throws Exception {
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
void db_should_close_normally() throws Exception {
|
||||
LimboDB.load();
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB db = LimboDB.create("jdbc:sqlite" + dbPath, dbPath);
|
||||
db.open(0);
|
||||
db.close();
|
||||
|
||||
assertFalse(db.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_exception_when_opened_twice() throws Exception {
|
||||
LimboDB.load();
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB db = LimboDB.create("jdbc:sqlite:" + dbPath, dbPath);
|
||||
db.open(0);
|
||||
|
||||
@@ -31,8 +43,8 @@ public class LimboDBTest {
|
||||
|
||||
@Test
|
||||
void throwJavaException_should_throw_appropriate_java_exception() throws Exception {
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB.load();
|
||||
String dbPath = TestUtils.createTempFile();
|
||||
LimboDB db = LimboDB.create("jdbc:sqlite:" + dbPath, dbPath);
|
||||
|
||||
final int limboExceptionCode = LimboErrorCode.LIMBO_ETC.code;
|
||||
|
||||
@@ -84,4 +84,15 @@ class JDBC4ConnectionTest {
|
||||
connection.createStatement(
|
||||
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isValid_should_return_true_on_open_connection() throws SQLException {
|
||||
assertTrue(connection.isValid(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isValid_should_return_false_on_closed_connection() throws SQLException {
|
||||
connection.close();
|
||||
assertFalse(connection.isValid(10));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user