mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-29 22:14:23 +01:00
Merge 'java/bindings: Add support for creating statement ' from Kim Seon Woo
## Purpose of this PR - Add support for `createStatement` in `JDBC4Connection` - Following works can use this statement to execute queries ## Changes - Implement `createStatement` for `JDBC4Connection` - Add `JDBC4Statement` ## References - https://github.com/tursodatabase/limbo/issues/615 Closes #693
This commit is contained in:
@@ -4,6 +4,7 @@ import org.github.tursodatabase.core.AbstractDB;
|
||||
import org.github.tursodatabase.core.LimboDB;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -61,4 +62,43 @@ public abstract class LimboConnection implements Connection {
|
||||
database.open(0);
|
||||
return database;
|
||||
}
|
||||
|
||||
protected void checkOpen() throws SQLException {
|
||||
if (isClosed()) throw new SQLException("database connection closed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
if (isClosed()) return;
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
return database.isClosed();
|
||||
}
|
||||
|
||||
// TODO: check whether this is still valid for limbo
|
||||
/**
|
||||
* Checks whether the type, concurrency, and holdability settings for a {@link ResultSet} are
|
||||
* supported by the SQLite interface. Supported settings are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>type: {@link ResultSet#TYPE_FORWARD_ONLY}
|
||||
* <li>concurrency: {@link ResultSet#CONCUR_READ_ONLY})
|
||||
* <li>holdability: {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}
|
||||
* </ul>
|
||||
*
|
||||
* @param resultSetType the type setting.
|
||||
* @param resultSetConcurrency the concurrency setting.
|
||||
* @param resultSetHoldability the holdability setting.
|
||||
*/
|
||||
protected void checkCursor(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY)
|
||||
throw new SQLException("SQLite only supports TYPE_FORWARD_ONLY cursors");
|
||||
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY)
|
||||
throw new SQLException("SQLite only supports CONCUR_READ_ONLY cursors");
|
||||
if (resultSetHoldability != ResultSet.CLOSE_CURSORS_AT_COMMIT)
|
||||
throw new SQLException("SQLite only supports closing cursors at commit");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
package org.github.tursodatabase.core;
|
||||
|
||||
public class Codes {
|
||||
/** Successful result */
|
||||
public static final int SQLITE_OK = 0;
|
||||
|
||||
/** SQL error or missing database */
|
||||
public static final int SQLITE_ERROR = 1;
|
||||
|
||||
/** An internal logic error in SQLite */
|
||||
public static final int SQLITE_INTERNAL = 2;
|
||||
|
||||
/** Access permission denied */
|
||||
public static final int SQLITE_PERM = 3;
|
||||
|
||||
/** Callback routine requested an abort */
|
||||
public static final int SQLITE_ABORT = 4;
|
||||
|
||||
/** The database file is locked */
|
||||
public static final int SQLITE_BUSY = 5;
|
||||
|
||||
/** A table in the database is locked */
|
||||
public static final int SQLITE_LOCKED = 6;
|
||||
|
||||
/** A malloc() failed */
|
||||
public static final int SQLITE_NOMEM = 7;
|
||||
|
||||
/** Attempt to write a readonly database */
|
||||
public static final int SQLITE_READONLY = 8;
|
||||
|
||||
/** Operation terminated by sqlite_interrupt() */
|
||||
public static final int SQLITE_INTERRUPT = 9;
|
||||
|
||||
/** Some kind of disk I/O error occurred */
|
||||
public static final int SQLITE_IOERR = 10;
|
||||
|
||||
/** The database disk image is malformed */
|
||||
public static final int SQLITE_CORRUPT = 11;
|
||||
|
||||
/** (Internal Only) Table or record not found */
|
||||
public static final int SQLITE_NOTFOUND = 12;
|
||||
|
||||
/** Insertion failed because database is full */
|
||||
public static final int SQLITE_FULL = 13;
|
||||
|
||||
/** Unable to open the database file */
|
||||
public static final int SQLITE_CANTOPEN = 14;
|
||||
|
||||
/** Database lock protocol error */
|
||||
public static final int SQLITE_PROTOCOL = 15;
|
||||
|
||||
/** (Internal Only) Database table is empty */
|
||||
public static final int SQLITE_EMPTY = 16;
|
||||
|
||||
/** The database schema changed */
|
||||
public static final int SQLITE_SCHEMA = 17;
|
||||
|
||||
/** Too much data for one row of a table */
|
||||
public static final int SQLITE_TOOBIG = 18;
|
||||
|
||||
/** Abort due to constraint violation */
|
||||
public static final int SQLITE_CONSTRAINT = 19;
|
||||
|
||||
/** Data type mismatch */
|
||||
public static final int SQLITE_MISMATCH = 20;
|
||||
|
||||
/** Library used incorrectly */
|
||||
public static final int SQLITE_MISUSE = 21;
|
||||
|
||||
/** Uses OS features not supported on host */
|
||||
public static final int SQLITE_NOLFS = 22;
|
||||
|
||||
/** Authorization denied */
|
||||
public static final int SQLITE_AUTH = 23;
|
||||
|
||||
/** sqlite_step() has another row ready */
|
||||
public static final int SQLITE_ROW = 100;
|
||||
|
||||
/** sqlite_step() has finished executing */
|
||||
public static final int SQLITE_DONE = 101;
|
||||
|
||||
// types returned by sqlite3_column_type()
|
||||
|
||||
public static final int SQLITE_INTEGER = 1;
|
||||
public static final int SQLITE_FLOAT = 2;
|
||||
public static final int SQLITE_TEXT = 3;
|
||||
public static final int SQLITE_BLOB = 4;
|
||||
public static final int SQLITE_NULL = 5;
|
||||
}
|
||||
@@ -1,5 +1,26 @@
|
||||
package org.github.tursodatabase.core;
|
||||
|
||||
// TODO: add fields and methods
|
||||
public class CoreStatement {
|
||||
import org.github.tursodatabase.LimboConnection;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public abstract class CoreStatement {
|
||||
|
||||
private final LimboConnection connection;
|
||||
|
||||
protected CoreStatement(LimboConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
protected void internalClose() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
protected void clearGeneratedKeys() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
protected void updateGeneratedKeys() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,25 @@ public class JDBC4Connection extends LimboConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Statement createStatement() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
return createStatement(
|
||||
ResultSet.TYPE_FORWARD_ONLY,
|
||||
ResultSet.CONCUR_READ_ONLY,
|
||||
ResultSet.CLOSE_CURSORS_AT_COMMIT
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
|
||||
return createStatement(resultSetType, resultSetConcurrency, ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
checkOpen();
|
||||
checkCursor(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
|
||||
return new JDBC4Statement(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,13 +142,6 @@ public class JDBC4Connection extends LimboConnection {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
|
||||
@@ -193,13 +201,6 @@ public class JDBC4Connection extends LimboConnection {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
package org.github.tursodatabase.jdbc4;
|
||||
|
||||
import org.github.tursodatabase.LimboConnection;
|
||||
import org.github.tursodatabase.annotations.SkipNullableCheck;
|
||||
import org.github.tursodatabase.core.CoreStatement;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link Statement} interface for JDBC 4.
|
||||
*/
|
||||
public class JDBC4Statement extends CoreStatement implements Statement {
|
||||
|
||||
private boolean closed;
|
||||
private boolean closeOnCompletion;
|
||||
|
||||
private final int resultSetType;
|
||||
private final int resultSetConcurrency;
|
||||
private final int resultSetHoldability;
|
||||
|
||||
public JDBC4Statement(LimboConnection connection) {
|
||||
this(connection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
public JDBC4Statement(LimboConnection connection, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
|
||||
super(connection);
|
||||
this.resultSetType = resultSetType;
|
||||
this.resultSetConcurrency = resultSetConcurrency;
|
||||
this.resultSetHoldability = resultSetHoldability;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
clearGeneratedKeys();
|
||||
internalClose();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public SQLWarning getWarnings() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public ResultSet getResultSet() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return resultSetConcurrency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return resultSetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() throws SQLException {
|
||||
// TODO
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public Connection getConnection() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public ResultSet getGeneratedKeys() throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return resultSetHoldability;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) throws SQLException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() throws SQLException {
|
||||
if (closed) throw new SQLException("statement is closed");
|
||||
closeOnCompletion = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the statement should be closed automatically when all its dependent result sets are closed.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() throws SQLException {
|
||||
if (closed) throw new SQLException("statement is closed");
|
||||
return closeOnCompletion;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SkipNullableCheck
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.github.tursodatabase.jdbc4;
|
||||
|
||||
import org.github.tursodatabase.TestUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class JDBC4ConnectionTest {
|
||||
|
||||
private JDBC4Connection connection;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
String fileUrl = TestUtils.createTempFile();
|
||||
String url = "jdbc:sqlite:" + fileUrl;
|
||||
connection = new JDBC4Connection(url, fileUrl, new Properties());
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_create_statement_valid() throws SQLException {
|
||||
Statement stmt = connection.createStatement();
|
||||
assertNotNull(stmt);
|
||||
assertEquals(ResultSet.TYPE_FORWARD_ONLY, stmt.getResultSetType());
|
||||
assertEquals(ResultSet.CONCUR_READ_ONLY, stmt.getResultSetConcurrency());
|
||||
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, stmt.getResultSetHoldability());
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_create_statement_with_type_and_concurrency_valid() throws SQLException {
|
||||
Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
assertNotNull(stmt);
|
||||
assertEquals(ResultSet.TYPE_FORWARD_ONLY, stmt.getResultSetType());
|
||||
assertEquals(ResultSet.CONCUR_READ_ONLY, stmt.getResultSetConcurrency());
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_create_statement_with_all_params_valid() throws SQLException {
|
||||
Statement stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
assertNotNull(stmt);
|
||||
assertEquals(ResultSet.TYPE_FORWARD_ONLY, stmt.getResultSetType());
|
||||
assertEquals(ResultSet.CONCUR_READ_ONLY, stmt.getResultSetConcurrency());
|
||||
assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, stmt.getResultSetHoldability());
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_create_statement_invalid() {
|
||||
assertThrows(SQLException.class, () -> {
|
||||
connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, -1);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user