Merge 'Add skeleton code for implementing java bindings in jdbc style ' from Kim Seon Woo

## Purpose of the PR
- Add minimal template code that provides Limbo features.
## Changes
- Added `DB` which is an interface to DB.
- Added 'LimboDB` which is a thin wrapper around native methods provided
using jni.
## TODO
- Incrementally update the code to support jdbc. Refer to [sqlite-
jdbc](https://github.com/xerial/sqlite-jdbc).
## Reference
- https://github.com/tursodatabase/limbo/issues/615

Closes #619
This commit is contained in:
Pekka Enberg
2025-01-05 20:12:31 +02:00
9 changed files with 289 additions and 0 deletions

View File

@@ -4,6 +4,9 @@ import org.github.tursodatabase.limbo.Connection;
import org.github.tursodatabase.limbo.Cursor;
import org.github.tursodatabase.limbo.Limbo;
/**
* TODO: Remove Main class. We can use test code to verify behaviors.
*/
public class Main {
public static void main(String[] args) throws Exception {
Limbo limbo = Limbo.create();

View File

@@ -0,0 +1,5 @@
package org.github.tursodatabase.core;
// TODO: add fields and methods
public class CoreStatement {
}

View File

@@ -0,0 +1,176 @@
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 DB {
private final String url;
private final String fileName;
private final AtomicBoolean closed = new AtomicBoolean(true);
public DB(String url, String fileName) throws SQLException {
this.url = url;
this.fileName = fileName;
}
public String getUrl() {
return url;
}
public boolean isClosed() {
return closed.get();
}
/**
* Aborts any pending operation and returns at its earliest opportunity.
*/
public abstract void interrupt() throws SQLException;
/**
* Executes an SQL statement.
*
* @param sql SQL statement to be executed.
* @param autoCommit Whether to auto-commit the transaction.
* @throws SQLException if a database access error occurs.
*/
public final synchronized void exec(String sql, boolean autoCommit) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
/**
* Creates an SQLite interface to a database for the given connection.
* @see <a href="https://www.sqlite.org/c3ref/c_open_autoproxy.html">SQLite Open Flags</a>
*
* @param fileName The database.
* @param openFlags Flags for opening the database.
* @throws SQLException if a database access error occurs.
*/
public final synchronized void open(String fileName, int openFlags) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
/**
* 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();
}
/**
* Compiles an SQL statement.
*
* @param stmt The SQL statement to compile.
* @throws SQLException if a database access error occurs.
*/
public final synchronized void prepare(CoreStatement stmt) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
/**
* Destroys a statement.
*
* @param safePtr the pointer wrapper to remove from internal structures.
* @param ptr the raw pointer to free.
* @return <a href="https://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @throws SQLException if a database access error occurs.
*/
public synchronized int finalize(SafeStmtPtr safePtr, long ptr) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
/**
* Creates an SQLite interface to a database with the provided open flags.
* @see <a href="https://www.sqlite.org/c3ref/c_open_autoproxy.html">SQLite Open Flags</a>
*
* @param filename The database to open.
* @param openFlags Flags for opening the database.
* @throws SQLException if a database access error occurs.
*/
protected abstract void _open(String filename, int openFlags) throws SQLException;
/**
* Closes the SQLite interface to a database.
*
* @throws SQLException if a database access error occurs.
*/
protected abstract void _close() throws SQLException;
/**
* Compiles, evaluates, executes and commits an SQL statement.
*
* @param sql An SQL statement.
* @return Result code.
* @throws SQLException if a database access error occurs.
*/
public abstract int _exec(String sql) throws SQLException;
/**
* Compiles an SQL statement.
*
* @param sql An SQL statement.
* @return A SafeStmtPtr object.
* @throws SQLException if a database access error occurs.
*/
protected abstract SafeStmtPtr prepare(String sql) throws SQLException;
/**
* Destroys a prepared statement.
*
* @param stmt Pointer to the statement pointer.
* @return Result code.
* @throws SQLException if a database access error occurs.
*/
protected abstract int finalize(long stmt) throws SQLException;
/**
* Evaluates a statement.
*
* @param stmt Pointer to the statement.
* @return Result code.
* @throws SQLException if a database access error occurs.
*/
public abstract int step(long stmt) throws SQLException;
/**
* Executes a statement with the provided parameters.
*
* @param stmt Stmt object.
* @param vals Array of parameter values.
* @return True if a row of ResultSet is ready; false otherwise.
* @throws SQLException if a database access error occurs.
* @see <a href="https://www.sqlite.org/c_interface.html#sqlite_exec">SQLite Exec</a>
*/
public final synchronized boolean execute(CoreStatement stmt, Object[] vals) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
/**
* Executes an SQL INSERT, UPDATE or DELETE statement with the Stmt object and an array of
* parameter values of the SQL statement.
*
* @param stmt Stmt object.
* @param vals Array of parameter values.
* @return Number of database rows that were changed or inserted or deleted by the most recently
* completed SQL.
* @throws SQLException if a database access error occurs.
*/
public final synchronized long executeUpdate(CoreStatement stmt, Object[] vals) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
}

View File

@@ -0,0 +1,94 @@
package org.github.tursodatabase.core;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
/**
* This class provides a thin JNI layer over the SQLite3 C API.
*/
public final class LimboDB extends DB {
/**
* SQLite connection handle.
*/
private long pointer = 0;
private static boolean isLoaded;
private static boolean loadSucceeded;
static {
if ("The Android Project".equals(System.getProperty("java.vm.vendor"))) {
System.loadLibrary("sqlitejdbc");
isLoaded = true;
loadSucceeded = true;
} else {
// continue with non Android execution path
isLoaded = false;
loadSucceeded = false;
}
}
// TODO: receive config as argument
public LimboDB(String url, String fileName) throws SQLException {
super(url, fileName);
}
/**
* Loads the SQLite interface backend.
*
* @return True if the SQLite JDBC driver is successfully loaded; false otherwise.
*/
public static boolean load() throws Exception {
if (isLoaded) return loadSucceeded;
try {
System.loadLibrary("_limbo_java");
loadSucceeded = true;
} finally {
isLoaded = true;
}
return loadSucceeded;
}
// WRAPPER FUNCTIONS ////////////////////////////////////////////
@Override
protected synchronized void _open(String file, int openFlags) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
// TODO: add support for JNI
synchronized native void _open_utf8(byte[] fileUtf8, int openFlags) throws SQLException;
// TODO: add support for JNI
@Override
protected synchronized native void _close() throws SQLException;
@Override
public synchronized int _exec(String sql) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
// TODO: add support for JNI
synchronized native int _exec_utf8(byte[] sqlUtf8) throws SQLException;
// TODO: add support for JNI
@Override
public native void interrupt();
@Override
protected synchronized SafeStmtPtr prepare(String sql) throws SQLException {
// TODO: add implementation
throw new SQLFeatureNotSupportedException();
}
// TODO: add support for JNI
@Override
protected synchronized native int finalize(long stmt);
// TODO: add support for JNI
@Override
public synchronized native int step(long stmt);
}

View File

@@ -0,0 +1,5 @@
package org.github.tursodatabase.core;
// TODO: add fields and methods
public class SafeStmtPtr {
}

View File

@@ -6,6 +6,7 @@ package org.github.tursodatabase.exceptions;
* that may occur while communicating with the JNI.
* <p />
* Refer to ErrorCode in rust package.
* TODO: Deprecate
*/
public class ErrorCode {
public static int CONNECTION_FAILURE = -1;

View File

@@ -4,6 +4,7 @@ import java.lang.Exception;
/**
* Represents a connection to the database.
* TODO: Deprecate classes under limbo package. We leave this source code for reference.
*/
public class Connection {

View File

@@ -2,6 +2,7 @@ package org.github.tursodatabase.limbo;
/**
* Represents a database cursor.
* TODO: Deprecate classes under limbo package. We leave this source code for reference.
*/
public class Cursor {
private long cursorPtr;

View File

@@ -4,6 +4,9 @@ import org.github.tursodatabase.exceptions.ErrorCode;
import java.lang.Exception;
/**
* TODO: Deprecate classes under limbo package. We leave this source code for reference.
*/
public class Limbo {
private static volatile boolean initialized;