-
Notifications
You must be signed in to change notification settings - Fork 465
Calling Blob#length() causes an InputStream obtained from Blob#getBinaryStream() to close #611
Copy link
Copy link
Closed
Description
Driver version or jar name
6.1.6 and later
SQL Server version
Microsoft SQL Server 2012
Client operating system
Mac OS, Windows, Linux
Java/JVM version
1.8.161
Table schema
create table mytable (
mydata varbinary(max)
);
Problem description
In versions prior to 6.1.6 it was possible to:
- Obtain an InputStream from a BLOB with
myBlob.getBinaryStream(). - Call
myBlob.length()to get the size of the BLOB. - Consume the InputStream.
In version 6.1.6 and later, the InputStream cannot be consumed, because it has been closed, and an exception is thrown:
java.io.IOException: The stream is closed.
at com.microsoft.sqlserver.jdbc.BaseInputStream.checkClosed(SimpleInputStream.java:99)
at com.microsoft.sqlserver.jdbc.PLPInputStream.read(PLPInputStream.java:221)
at com.example.JdbcBlobStreamTester.main(JdbcBlobStreamTester.java:51)
The following works, of course:
- Call
myBlob.length()to get the size of the BLOB. - Obtain an InputStream from a BLOB with
myBlob.getBinaryStream(). - Consume the InputStream.
I suspect that the change of behavior came about with the resolution #16.
Expected behavior and actual behavior
Expected: that the obtained InputStream survives the call to Blob#length().
On the other hand, the stream closing might be expected behavior: 66e395d.
Repro code
package com.example;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcBlobStreamTester {
private static final String URL = "jdbc:sqlserver://database.example.com:1433;DatabaseName=my_database";
private static final String CLASS_NAME = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
public static void main(String... args) {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
System.out.format("Loading class '%s'...", CLASS_NAME);
final Class<?> cls = Class.forName(CLASS_NAME);
final Driver driver = (Driver) cls.newInstance();
System.out.println("OK!");
System.out.format("Loaded driver version %d.%d\n", driver.getMajorVersion(), driver.getMinorVersion());
System.out.format("Connecting using URL '%s'...", URL);
con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
System.out.println("OK!");
final String sql = " SELECT MYDATA FROM MYTABLE ";
stmt = con.createStatement();
System.out.print("Executing query...");
rs = stmt.executeQuery(sql);
System.out.println("OK!");
if (!rs.next()) {
throw new IllegalStateException("The ResultSet is empty");
}
final Blob blob = rs.getBlob(1);
final InputStream is = blob.getBinaryStream();
// Changing the order of the following two lines gives a difference in behavior:
System.out.format("BLOB length: %d bytes\n", blob.length());
System.out.format("First byte of BLOB: %c\n", is.read());
System.out.println("Done!");
} catch (Exception e) {
System.out.println("\n\nAn error occured:");
e.printStackTrace(System.out);
} finally {
close(rs);
close(stmt);
close(con);
}
}
private static void close(AutoCloseable obj) {
if (obj != null) {
try {
obj.close();
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels