Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -483,18 +483,30 @@ public CallableStatement prepareCall(String sql, int resultSetType, int resultSe

@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return Map.of();
throw new SQLFeatureNotSupportedException("Type maps are not supported");
}

@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {}
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("Type maps are not supported");
}

@Override
public void setHoldability(int holdability) throws SQLException {}
public void setHoldability(int holdability) throws SQLException {
checkClosed();
checkHoldability(holdability);
}

@Override
public int getHoldability() throws SQLException {
return 1; // HOLD_CURSORS_OVER_COMMIT
checkClosed();
return ResultSet.CLOSE_CURSORS_AT_COMMIT;
}

private static void checkHoldability(int holdability) throws SQLException {
if (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
throw new SQLException("SQLite only supports CLOSE_CURSORS_AT_COMMIT");
}
}

@Override
Expand All @@ -519,16 +531,22 @@ public void releaseSavepoint(Savepoint savepoint) throws SQLException {

@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
checkClosed();
checkHoldability(resultSetHoldability);
return createStatement();
}

@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
checkClosed();
checkHoldability(resultSetHoldability);
return prepareStatement(sql);
}

@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
checkClosed();
checkHoldability(resultSetHoldability);
return prepareCall(sql);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,8 +565,8 @@ public Connection getConnection() throws SQLException {
@Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { throw new UnsupportedOperationException(); }
@Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { throw new UnsupportedOperationException(); }
@Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { throw new UnsupportedOperationException(); }
@Override public boolean supportsResultSetHoldability(int holdability) throws SQLException { return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT; }
@Override public int getResultSetHoldability() throws SQLException { return ResultSet.HOLD_CURSORS_OVER_COMMIT; }
@Override public boolean supportsResultSetHoldability(int holdability) throws SQLException { return holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT; }
@Override public int getResultSetHoldability() throws SQLException { return ResultSet.CLOSE_CURSORS_AT_COMMIT; }
@Override public int getDatabaseMajorVersion() throws SQLException {
String[] parts = resolveDatabaseProductVersion().split("\\.");
try { return Integer.parseInt(parts[0]); } catch (NumberFormatException e) { return 3; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class LibsqlResultSet implements ResultSet {
private int currentRowIndex = -1;
private int lastColumnIndex = 0;
private boolean closed = false;
private int fetchSize = 0;
private LibsqlResultSetMetaData metadata;

// Mitigation for Bug 6: O(1) column label lookup
Expand Down Expand Up @@ -867,8 +868,14 @@ public boolean isLast() throws SQLException {
@Override public boolean previous() throws SQLException { throw new SQLException("Forward only"); }
@Override public void setFetchDirection(int direction) throws SQLException {}
@Override public int getFetchDirection() throws SQLException { return FETCH_FORWARD; }
@Override public void setFetchSize(int rows) throws SQLException {}
@Override public int getFetchSize() throws SQLException { return 0; }
@Override
public void setFetchSize(int rows) throws SQLException {
if (rows < 0) {
throw new SQLException("fetch size " + rows + " out of bounds 0");
}
fetchSize = rows;
}
@Override public int getFetchSize() throws SQLException { return fetchSize; }
@Override public boolean rowUpdated() throws SQLException { return false; }
@Override public boolean rowInserted() throws SQLException { return false; }
@Override public boolean rowDeleted() throws SQLException { return false; }
Expand Down Expand Up @@ -947,7 +954,7 @@ public boolean isLast() throws SQLException {
@Override public RowId getRowId(String columnLabel) throws SQLException { throw new UnsupportedOperationException(); }
@Override public void updateRowId(int columnIndex, RowId x) throws SQLException { throw new UnsupportedOperationException(); }
@Override public void updateRowId(String columnLabel, RowId x) throws SQLException { throw new UnsupportedOperationException(); }
@Override public int getHoldability() throws SQLException { return HOLD_CURSORS_OVER_COMMIT; }
@Override public int getHoldability() throws SQLException { return CLOSE_CURSORS_AT_COMMIT; }
@Override public void updateNString(int columnIndex, String nString) throws SQLException { throw new UnsupportedOperationException(); }
@Override public void updateNString(String columnLabel, String nString) throws SQLException { throw new UnsupportedOperationException(); }
@Override public void updateNClob(int columnIndex, NClob nClob) throws SQLException { throw new UnsupportedOperationException(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class LibsqlStatement implements Statement {
private ResultSet generatedKeys = null;
private boolean resultSetRequested = false;
private boolean closing = false;
private int fetchSize = 0;

public LibsqlStatement(LibsqlConnection connection) {
this.connection = connection;
Expand Down Expand Up @@ -413,8 +414,22 @@ public boolean isClosed() throws SQLException {
@Override public void setCursorName(String name) throws SQLException {}
@Override public void setFetchDirection(int direction) throws SQLException {}
@Override public int getFetchDirection() throws SQLException { return ResultSet.FETCH_FORWARD; }
@Override public void setFetchSize(int rows) throws SQLException {}
@Override public int getFetchSize() throws SQLException { return 0; }
@Override
public void setFetchSize(int rows) throws SQLException {
if (rows < 0) {
throw new SQLException("fetch size " + rows + " out of bounds 0");
}
synchronized (stateLock) {
fetchSize = rows;
}
}

@Override
public int getFetchSize() throws SQLException {
synchronized (stateLock) {
return fetchSize;
}
}
@Override public int getResultSetConcurrency() throws SQLException { return ResultSet.CONCUR_READ_ONLY; }
@Override public int getResultSetType() throws SQLException { return ResultSet.TYPE_FORWARD_ONLY; }
@Override
Expand Down Expand Up @@ -445,7 +460,7 @@ public ResultSet getGeneratedKeys() throws SQLException {
@Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { return execute(sql); }
@Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { return execute(sql); }
@Override public boolean execute(String sql, String[] columnNames) throws SQLException { return execute(sql); }
@Override public int getResultSetHoldability() throws SQLException { return ResultSet.HOLD_CURSORS_OVER_COMMIT; }
@Override public int getResultSetHoldability() throws SQLException { return ResultSet.CLOSE_CURSORS_AT_COMMIT; }
@Override public void setPoolable(boolean poolable) throws SQLException {}
@Override public boolean isPoolable() throws SQLException { return false; }
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.github.magnusp.libsql.jdbc;

import com.github.magnusp.libsql.hrana.codec.Col;
import com.github.magnusp.libsql.hrana.codec.StmtResult;
import org.junit.jupiter.api.Test;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class LibsqlDriverSettingsTest {

private static final StmtResult EMPTY =
new StmtResult(List.of(new Col("value", null)), List.of(), 0, null);

@Test
void typeMapReadAndWriteAreRejected() throws SQLException {
LibsqlConnection connection = new LibsqlConnection(null, null);

assertThatThrownBy(connection::getTypeMap)
.isInstanceOf(SQLFeatureNotSupportedException.class);
assertThatThrownBy(() -> connection.setTypeMap(Map.of("x", String.class)))
.isInstanceOf(SQLFeatureNotSupportedException.class);
}

@Test
void connectionHoldabilityIsCloseCursorsAtCommit() throws SQLException {
LibsqlConnection connection = new LibsqlConnection(null, null);

assertThat(connection.getHoldability()).isEqualTo(ResultSet.CLOSE_CURSORS_AT_COMMIT);
connection.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertThat(connection.getHoldability()).isEqualTo(ResultSet.CLOSE_CURSORS_AT_COMMIT);
}

@Test
void connectionRejectsHoldCursorsOverCommit() throws SQLException {
LibsqlConnection connection = new LibsqlConnection(null, null);

assertThatThrownBy(() -> connection.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT))
.isInstanceOf(SQLException.class)
.hasMessageContaining("CLOSE_CURSORS_AT_COMMIT");
}

@Test
void statementFactoriesRejectHoldCursorsOverCommit() throws SQLException {
LibsqlConnection connection = new LibsqlConnection(null, null);

assertThatThrownBy(() -> connection.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT))
.isInstanceOf(SQLException.class)
.hasMessageContaining("CLOSE_CURSORS_AT_COMMIT");
assertThatThrownBy(() -> connection.prepareStatement(
"select 1",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT))
.isInstanceOf(SQLException.class)
.hasMessageContaining("CLOSE_CURSORS_AT_COMMIT");
}

@Test
void metadataHoldabilityAgreesWithConnection() throws SQLException {
LibsqlConnection connection = new LibsqlConnection(null, null);
DatabaseMetaData metadata = connection.getMetaData();

assertThat(metadata.getResultSetHoldability())
.isEqualTo(ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertThat(metadata.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT))
.isTrue();
assertThat(metadata.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT))
.isFalse();
}

@Test
void statementAndResultSetReportCloseCursorsAtCommit() throws SQLException {
LibsqlStatement statement = new LibsqlStatement(null);

assertThat(statement.getResultSetHoldability())
.isEqualTo(ResultSet.CLOSE_CURSORS_AT_COMMIT);
assertThat(new LibsqlResultSet(statement, EMPTY).getHoldability())
.isEqualTo(ResultSet.CLOSE_CURSORS_AT_COMMIT);
}

@Test
void statementFetchSizeRoundTripsAndRejectsNegativeValues() throws SQLException {
LibsqlStatement statement = new LibsqlStatement(null);

assertThat(statement.getFetchSize()).isZero();
statement.setFetchSize(10);
assertThat(statement.getFetchSize()).isEqualTo(10);
assertThatThrownBy(() -> statement.setFetchSize(-1))
.isInstanceOf(SQLException.class);
}

@Test
void resultSetFetchSizeRoundTripsAndRejectsNegativeValues() throws SQLException {
LibsqlResultSet resultSet = new LibsqlResultSet(new LibsqlStatement(null), EMPTY);

assertThat(resultSet.getFetchSize()).isZero();
resultSet.setFetchSize(10);
assertThat(resultSet.getFetchSize()).isEqualTo(10);
assertThatThrownBy(() -> resultSet.setFetchSize(-1))
.isInstanceOf(SQLException.class);
}
}
Loading