Skip to content

Commit

Permalink
#822 Modify the set/updateObject methods with int scaleOrLength to ap…
Browse files Browse the repository at this point in the history
…ply the length if a Reader or InputStream
  • Loading branch information
mrotteveel committed Sep 25, 2024
1 parent 98149c3 commit 6bdae77
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/docs/asciidoc/release_notes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,7 @@ If the JSpecify JAR is not included on the classpath or modulepath, Jaybird will
* `DatabaseMetaData` now reports `ResultSet.TYPE_SCROLL_SENSITIVE` as not supported, as it is always downgraded to `TYPE_SCROLL_INSENSITIVE`, and thus effectively not supported.
+
This affects the return value of the methods `supportsResultSetType(int)`, `supportsResultSetConcurrency(int, int)`, `ownUpdatesAreVisible(int)`, `ownDeletesAreVisible(int)`, `ownInsertsAreVisible(int)`.
* Improvement: `setObject`/`updateObject` methods on `PreparedStatement`, `CallableStatement` and `ResultSet` with the `int scaleOrLength` parameter will now redirect to variants accepting a length of `set/updateBinaryStream` for `InputStream` and `set/updateCharacterStream` for `Reader` (https://github.com/FirebirdSQL/jaybird/issues/822[#822])
[#potentially-breaking-changes]
=== Potentially breaking changes
Expand Down
19 changes: 17 additions & 2 deletions src/main/org/firebirdsql/jdbc/FBCallableStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -1219,9 +1219,24 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException {
setInputParam(parameterIndex, null);
}

/**
* {@inheritDoc}
* <p>
* Implementation note: ignores {@code scaleOrLength} and {@code targetSqlType} and works as
* {@link #setObject(int, Object)}, {@code scaleOrLength} is not ignored if {@code x} is a {@link Reader} or
* {@link InputStream}.
* </p>
*/
@Override
public void setObject(int parameterIndex, @Nullable Object x, int targetSqlType, int scale) throws SQLException {
setInputParam(parameterIndex, x);
public void setObject(int parameterIndex, @Nullable Object x, int targetSqlType, int scaleOrLength)
throws SQLException {
if (x instanceof InputStream) {
setBinaryStream(parameterIndex, (InputStream) x, scaleOrLength);
} else if (x instanceof Reader) {
setCharacterStream(parameterIndex, (Reader) x, scaleOrLength);
} else {
setInputParam(parameterIndex, x);
}
}

@Override
Expand Down
16 changes: 12 additions & 4 deletions src/main/org/firebirdsql/jdbc/FBPreparedStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -508,13 +508,21 @@ public void clearParameters() throws SQLException {
/**
* {@inheritDoc}
* <p>
* Implementation note: ignores {@code scale} and {@code targetSqlType} and works as
* {@link #setObject(int, Object)}.
* Implementation note: ignores {@code scaleOrLength} and {@code targetSqlType} and works as
* {@link #setObject(int, Object)}, {@code scaleOrLength} is not ignored if {@code x} is a {@link Reader} or
* {@link InputStream}.
* </p>
*/
@Override
public void setObject(int parameterIndex, @Nullable Object x, int targetSqlType, int scale) throws SQLException {
setObject(parameterIndex, x);
public void setObject(int parameterIndex, @Nullable Object x, int targetSqlType, int scaleOrLength)
throws SQLException {
if (x instanceof InputStream) {
setBinaryStream(parameterIndex, (InputStream) x, scaleOrLength);
} else if (x instanceof Reader) {
setCharacterStream(parameterIndex, (Reader) x, scaleOrLength);
} else {
setObject(parameterIndex, x);
}
}

/**
Expand Down
32 changes: 22 additions & 10 deletions src/main/org/firebirdsql/jdbc/FBResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -1105,25 +1105,31 @@ public void updateBinaryStream(String columnLabel, @Nullable InputStream x) thro
/**
* {@inheritDoc}
* <p>
* Jaybird delegates to {@link #updateObject(int, Object)} and ignores the value of {@code scaleOrLength}.
* Jaybird delegates to {@link #updateObject(int, Object)} and ignores the value of {@code scaleOrLength}, if
* {@code x} is anything other than a {@link Reader} or {@link InputStream}.
* </p>
*/
@Override
public void updateObject(int columnIndex, @Nullable Object x, int scaleOrLength) throws SQLException {
updateObject(columnIndex, x);
if (x instanceof InputStream) {
updateBinaryStream(columnIndex, (InputStream) x, scaleOrLength);
} else if (x instanceof Reader) {
updateCharacterStream(columnIndex, (Reader) x, scaleOrLength);
} else {
updateObject(columnIndex, x);
}
}

/**
* {@inheritDoc}
* <p>
* Jaybird delegates to {@link #updateObject(int, Object)} and ignores the values of {@code targetSqlType} and
* {@code scaleOrLength}.
* Jaybird delegates to {@link #updateObject(int, Object, int)} and ignores the value of {@code targetSqlType}.
* </p>
*/
@Override
public void updateObject(int columnIndex, @Nullable Object x, SQLType targetSqlType, int scaleOrLength)
throws SQLException {
updateObject(columnIndex, x);
updateObject(columnIndex, x, scaleOrLength);
}

@Override
Expand Down Expand Up @@ -1398,25 +1404,31 @@ public void updateNCharacterStream(String columnLabel, @Nullable Reader reader)
/**
* {@inheritDoc}
* <p>
* Jaybird delegates to {@link #updateObject(String, Object)} and ignores the value of {@code scaleOrLength}.
* Jaybird delegates to {@link #updateObject(String, Object)} and ignores the value of {@code scaleOrLength}, if
* {@code x} is anything other than a {@link Reader} or {@link InputStream}.
* </p>
*/
@Override
public void updateObject(String columnName, @Nullable Object x, int scaleOrLength) throws SQLException {
updateObject(columnName, x);
if (x instanceof InputStream) {
updateBinaryStream(columnName, (InputStream) x, scaleOrLength);
} else if (x instanceof Reader) {
updateCharacterStream(columnName, (Reader) x, scaleOrLength);
} else {
updateObject(columnName, x);
}
}

/**
* {@inheritDoc}
* <p>
* Jaybird delegates to {@link #updateObject(String, Object)} and ignores the value of {@code targetSqlType} and
* {@code scaleOrLength}.
* Jaybird delegates to {@link #updateObject(String, Object, int)} and ignores the value of {@code targetSqlType}.
* </p>
*/
@Override
public void updateObject(String columnLabel, @Nullable Object x, SQLType targetSqlType, int scaleOrLength)
throws SQLException {
updateObject(columnLabel, x);
updateObject(columnLabel, x, scaleOrLength);
}

@Override
Expand Down
32 changes: 32 additions & 0 deletions src/test/org/firebirdsql/jdbc/FBCallableStatementTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.Properties;
import java.util.stream.Stream;
Expand Down Expand Up @@ -1192,6 +1195,35 @@ recreate procedure RAISE_EXCEPTION_RS (PARAM1 varchar(50) not null) returns (COL
}
}

@Test
void setObject_Reader_scaleOrLength() throws Exception {
executeCreateTable(con, CREATE_SIMPLE_OUT_PROC);
String sourceValue = "1234567890";
final int usedLength = 5;
try (var cstmt = con.prepareCall(EXECUTE_SIMPLE_OUT_PROCEDURE_1)) {
cstmt.registerOutParameter(1, JDBCType.VARCHAR);
cstmt.setObject(2, new StringReader(sourceValue), JDBCType.VARCHAR, usedLength);
cstmt.execute();

assertEquals(sourceValue.substring(0, usedLength), cstmt.getString(1));
}
}

@Test
void setObject_InputStream_scaleOrLength() throws Exception {
executeDDL(con, CREATE_SIMPLE_OUT_PROC);
String sourceValue = "1234567890";
final int usedLength = 5;
try (var cstmt = con.prepareCall(EXECUTE_SIMPLE_OUT_PROCEDURE_1)) {
cstmt.registerOutParameter(1, JDBCType.VARCHAR);
cstmt.setObject(2, new ByteArrayInputStream(sourceValue.getBytes(StandardCharsets.US_ASCII)),
JDBCType.VARCHAR, usedLength);
cstmt.execute();

assertEquals(sourceValue.substring(0, usedLength), cstmt.getString(1));
}
}

static Stream<String> scrollableCursorPropertyValues() {
// We are unconditionally emitting SERVER, to check if the value behaves appropriately on versions that do
// not support server-side scrollable cursors
Expand Down
36 changes: 36 additions & 0 deletions src/test/org/firebirdsql/jdbc/FBPreparedStatementTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -1489,6 +1490,41 @@ recreate procedure RAISE_EXCEPTION_RS (PARAM1 varchar(50) not null) returns (COL
}
}

@Test
void setObject_Reader_scaleOrLength() throws Exception {
executeCreateTable(con, CREATE_TEST_CHARS_TABLE);
String sourceValue = "1234567890";
final int usedLength = 5;
try (var pstmt = con.prepareStatement("INSERT INTO testtab(id, field1, field2) VALUES(1, '', ?)")) {
pstmt.setObject(1, new StringReader(sourceValue), JDBCType.VARCHAR, usedLength);
pstmt.execute();
}

try (var stmt = con.createStatement()) {
var rs = stmt.executeQuery("select field2 from testtab");
assertNextRow(rs);
assertRowEquals(rs, List.of(sourceValue.substring(0, usedLength)));
}
}

@Test
void setObject_InputStream_scaleOrLength() throws Exception {
executeCreateTable(con, CREATE_TEST_CHARS_TABLE);
String sourceValue = "1234567890";
final int usedLength = 5;
try (var pstmt = con.prepareStatement("INSERT INTO testtab(id, field1, field2) VALUES(1, '', ?)")) {
pstmt.setObject(1, new ByteArrayInputStream(sourceValue.getBytes(StandardCharsets.US_ASCII)),
JDBCType.VARCHAR, usedLength);
pstmt.execute();
}

try (var stmt = con.createStatement()) {
var rs = stmt.executeQuery("select field2 from testtab");
assertNextRow(rs);
assertRowEquals(rs, List.of(sourceValue.substring(0, usedLength)));
}
}

private void prepareTestData() throws SQLException {
con.setAutoCommit(false);
try (var pstmt = con.prepareStatement(INSERT_DATA)) {
Expand Down
92 changes: 92 additions & 0 deletions src/test/org/firebirdsql/jdbc/FBResultSetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,98 @@ void scrollableCursor_detectsOwnInserts(String scrollableCursorPropertyValue) th
}
}

@Test
void updateObject_int_Reader_type_scaleOrLength() throws SQLException {
try (var connection = getConnectionViaDriverManager()) {
executeCreateTable(connection, CREATE_TABLE_STATEMENT);
createTestData(1, connection);
String sourceValue = "1234567890";
final int usedLength = 5;

try (var stmt = connection.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE)) {
var rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);

rs.updateObject(2, new StringReader(sourceValue), JDBCType.VARCHAR, usedLength);
rs.updateRow();

rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);
assertRowEquals(rs, List.of(1, sourceValue.substring(0, usedLength)));
}
}
}

@Test
void updateObject_String_Reader_type_scaleOrLength() throws SQLException {
try (var connection = getConnectionViaDriverManager()) {
executeCreateTable(connection, CREATE_TABLE_STATEMENT);
createTestData(1, connection);
String sourceValue = "1234567890";
final int usedLength = 5;

try (var stmt = connection.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE)) {
var rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);

rs.updateObject("str", new StringReader(sourceValue), JDBCType.VARCHAR, usedLength);
rs.updateRow();

rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);
assertRowEquals(rs, List.of(1, sourceValue.substring(0, usedLength)));
}
}
}

//

@Test
void updateObject_int_InputStream_type_scaleOrLength() throws SQLException {
try (var connection = getConnectionViaDriverManager()) {
executeCreateTable(connection, CREATE_TABLE_STATEMENT);
createTestData(1, connection);
String sourceValue = "1234567890";
final int usedLength = 5;

try (var stmt = connection.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE)) {
var rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);

rs.updateObject(2, new ByteArrayInputStream(sourceValue.getBytes(StandardCharsets.US_ASCII)),
JDBCType.VARCHAR, usedLength);
rs.updateRow();

rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);
assertRowEquals(rs, List.of(1, sourceValue.substring(0, usedLength)));
}
}
}

@Test
void updateObject_String_InputStream_type_scaleOrLength() throws SQLException {
try (var connection = getConnectionViaDriverManager()) {
executeCreateTable(connection, CREATE_TABLE_STATEMENT);
createTestData(1, connection);
String sourceValue = "1234567890";
final int usedLength = 5;

try (var stmt = connection.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE)) {
var rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);

rs.updateObject("str", new ByteArrayInputStream(sourceValue.getBytes(StandardCharsets.US_ASCII)),
JDBCType.VARCHAR, usedLength);
rs.updateRow();

rs = stmt.executeQuery(SELECT_TEST_TABLE);
assertNextRow(rs);
assertRowEquals(rs, List.of(1, sourceValue.substring(0, usedLength)));
}
}
}

static Stream<String> scrollableCursorPropertyValues() {
// We are unconditionally emitting SERVER, to check if the value behaves appropriately on versions that do
// not support server-side scrollable cursors
Expand Down

0 comments on commit 6bdae77

Please sign in to comment.