mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 01:58:16 +00:00
Update JDBC4Statement.java execute method to return result correctly
This commit is contained in:
parent
afbf041e2f
commit
0f46aaa0ec
5 changed files with 117 additions and 30 deletions
|
@ -1,9 +1,9 @@
|
|||
package org.github.tursodatabase.core;
|
||||
|
||||
import org.github.tursodatabase.annotations.Nullable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.github.tursodatabase.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A table of data representing limbo database result set, which is generated by executing a statement that queries the
|
||||
* database.
|
||||
|
@ -26,7 +26,7 @@ public class LimboResultSet {
|
|||
private boolean pastLastRow = false;
|
||||
|
||||
@Nullable
|
||||
private LimboStepResult lastResult;
|
||||
private LimboStepResult lastStepResult;
|
||||
|
||||
public static LimboResultSet of(LimboStatement statement) {
|
||||
return new LimboResultSet(statement);
|
||||
|
@ -54,11 +54,18 @@ public class LimboResultSet {
|
|||
return false;
|
||||
}
|
||||
|
||||
lastResult = this.statement.step();
|
||||
pastLastRow = lastResult == null || lastResult.isDone();
|
||||
lastStepResult = this.statement.step();
|
||||
pastLastRow = lastStepResult == null || lastStepResult.isDone();
|
||||
return !pastLastRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the last step result has returned row result.
|
||||
*/
|
||||
public boolean hasLastStepReturnedRow() {
|
||||
return lastStepResult != null && lastStepResult.isRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the status of the result set.
|
||||
*
|
||||
|
@ -76,4 +83,17 @@ public class LimboResultSet {
|
|||
throw new SQLException("ResultSet closed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LimboResultSet{" +
|
||||
"statement=" + statement +
|
||||
", isEmptyResultSet=" + isEmptyResultSet +
|
||||
", open=" + open +
|
||||
", maxRows=" + maxRows +
|
||||
", row=" + row +
|
||||
", pastLastRow=" + pastLastRow +
|
||||
", lastResult=" + lastStepResult +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.github.tursodatabase.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.github.tursodatabase.annotations.NativeInvocation;
|
||||
import org.github.tursodatabase.annotations.Nullable;
|
||||
import org.github.tursodatabase.utils.LimboExceptionUtils;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* By default, only one <code>resultSet</code> object per <code>LimboStatement</code> can be open at the same time.
|
||||
* Therefore, if the reading of one <code>resultSet</code> object is interleaved with the reading of another, each must
|
||||
|
@ -13,14 +13,13 @@ import java.sql.SQLException;
|
|||
* implicitly close the current <code>resultSet</code> object of the statement if an open one exists.
|
||||
*/
|
||||
public class LimboStatement {
|
||||
|
||||
private final String sql;
|
||||
private final long statementPointer;
|
||||
private final LimboResultSet resultSet;
|
||||
|
||||
@Nullable
|
||||
protected String sql = null;
|
||||
|
||||
public LimboStatement(long statementPointer) {
|
||||
// TODO: what if the statement we ran was DDL, update queries and etc. Should we still create a resultSet?
|
||||
public LimboStatement(String sql, long statementPointer) {
|
||||
this.sql = sql;
|
||||
this.statementPointer = statementPointer;
|
||||
this.resultSet = LimboResultSet.of(this);
|
||||
}
|
||||
|
@ -29,12 +28,18 @@ public class LimboStatement {
|
|||
return resultSet;
|
||||
}
|
||||
|
||||
public void execute() throws SQLException {
|
||||
/**
|
||||
* Expects a clean statement created right after prepare method is called.
|
||||
*
|
||||
* @return true if the ResultSet has at least one row; false otherwise.
|
||||
*/
|
||||
public boolean execute() throws SQLException {
|
||||
resultSet.next();
|
||||
return resultSet.hasLastStepReturnedRow();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LimboStepResult step() throws SQLException {
|
||||
LimboStepResult step() throws SQLException {
|
||||
return step(this.statementPointer);
|
||||
}
|
||||
|
||||
|
@ -44,11 +49,19 @@ public class LimboStatement {
|
|||
/**
|
||||
* Throws formatted SQLException with error code and message.
|
||||
*
|
||||
* @param errorCode Error code.
|
||||
* @param errorCode Error code.
|
||||
* @param errorMessageBytes Error message.
|
||||
*/
|
||||
@NativeInvocation
|
||||
@NativeInvocation(invokedFrom = "limbo_statement.rs")
|
||||
private void throwLimboException(int errorCode, byte[] errorMessageBytes) throws SQLException {
|
||||
LimboExceptionUtils.throwLimboException(errorCode, errorMessageBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LimboStatement{" +
|
||||
"statementPointer=" + statementPointer +
|
||||
", sql='" + sql + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,23 +8,27 @@ import org.github.tursodatabase.annotations.NativeInvocation;
|
|||
* Represents the step result of limbo's statement's step function.
|
||||
*/
|
||||
public class LimboStepResult {
|
||||
public static final int STEP_RESULT_ID_ROW = 10;
|
||||
public static final int STEP_RESULT_ID_IO = 20;
|
||||
public static final int STEP_RESULT_ID_DONE = 30;
|
||||
public static final int STEP_RESULT_ID_INTERRUPT = 40;
|
||||
public static final int STEP_RESULT_ID_BUSY = 50;
|
||||
public static final int STEP_RESULT_ID_ERROR = 60;
|
||||
private static final int STEP_RESULT_ID_ROW = 10;
|
||||
private static final int STEP_RESULT_ID_IO = 20;
|
||||
private static final int STEP_RESULT_ID_DONE = 30;
|
||||
private static final int STEP_RESULT_ID_INTERRUPT = 40;
|
||||
private static final int STEP_RESULT_ID_BUSY = 50;
|
||||
private static final int STEP_RESULT_ID_ERROR = 60;
|
||||
|
||||
// Identifier for limbo's StepResult
|
||||
private final int stepResultId;
|
||||
private final Object[] result;
|
||||
|
||||
@NativeInvocation
|
||||
@NativeInvocation(invokedFrom = "limbo_statement.rs")
|
||||
public LimboStepResult(int stepResultId, Object[] result) {
|
||||
this.stepResultId = stepResultId;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public boolean isRow() {
|
||||
return stepResultId == STEP_RESULT_ID_ROW;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return stepResultId == STEP_RESULT_ID_DONE;
|
||||
}
|
||||
|
|
|
@ -135,10 +135,6 @@ public class JDBC4Statement implements Statement {
|
|||
* <code>getResultSet</code> or <code>getUpdateCount</code>
|
||||
* to retrieve the result, and <code>getMoreResults</code> to
|
||||
* move to any subsequent result(s).
|
||||
*
|
||||
* @return <code>true</code> if the first result is a <code>ResultSet</code>
|
||||
* object; <code>false</code> if it is an update count or there are
|
||||
* no results
|
||||
*/
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
|
@ -147,13 +143,14 @@ public class JDBC4Statement implements Statement {
|
|||
return this.withConnectionTimeout(
|
||||
() -> {
|
||||
try {
|
||||
// TODO: if sql is a readOnly query, do we still need the locks?
|
||||
connectionLock.lock();
|
||||
statement = connection.prepare(sql);
|
||||
statement.execute();
|
||||
final boolean result = statement.execute();
|
||||
updateGeneratedKeys();
|
||||
exhaustedResults = false;
|
||||
// TODO: determine whether
|
||||
return true;
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
connectionLock.unlock();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.github.tursodatabase.jdbc4;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.github.tursodatabase.TestUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class JDBC4StatementTest {
|
||||
|
||||
private Statement stmt;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
String filePath = TestUtils.createTempFile();
|
||||
String url = "jdbc:sqlite:" + filePath;
|
||||
final JDBC4Connection connection = new JDBC4Connection(url, filePath, new Properties());
|
||||
stmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
|
||||
ResultSet.CONCUR_READ_ONLY,
|
||||
ResultSet.CLOSE_CURSORS_AT_COMMIT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute_ddl_should_return_false() throws Exception{
|
||||
assertFalse(stmt.execute("CREATE TABLE users (id INT PRIMARY KEY, username TEXT);"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute_insert_should_return_false() throws Exception {
|
||||
stmt.execute("CREATE TABLE users (id INT PRIMARY KEY, username TEXT);");
|
||||
assertFalse(stmt.execute("INSERT INTO users VALUES (1, 'limbo');"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("UPDATE not supported yet")
|
||||
void execute_update_should_return_false() throws Exception {
|
||||
stmt.execute("CREATE TABLE users (id INT PRIMARY KEY, username TEXT);");
|
||||
stmt.execute("INSERT INTO users VALUES (1, 'limbo');");
|
||||
assertFalse(stmt.execute("UPDATE users SET username = 'seonwoo' WHERE id = 1;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute_select_should_return_true() throws Exception {
|
||||
stmt.execute("CREATE TABLE users (id INT PRIMARY KEY, username TEXT);");
|
||||
stmt.execute("INSERT INTO users VALUES (1, 'limbo');");
|
||||
assertTrue(stmt.execute("SELECT * FROM users;"));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue