From dd6a473008be0ee2c14c08f2012cd687cf68fa25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler=20=28JPo=29?= Date: Mon, 22 Mar 2021 15:59:59 +0100 Subject: [PATCH] ADD: Test and possible fix for (C)LOBs being handed out of connnection-context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Pöhler (JPo) --- .../server/rawsql/DRawSqlService.java | 21 ++++++ .../server/rawsql/TestRawSqlBuilder.java | 64 +++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlService.java b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlService.java index 0b5eb4ad6..7c27264a8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlService.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlService.java @@ -9,6 +9,7 @@ import io.ebeaninternal.server.query.DefaultSqlRow; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Types; public class DRawSqlService implements SpiRawSqlService { @@ -49,6 +50,26 @@ public class DRawSqlService implements SpiRawSqlService { name = combine(meta.getSchemaName(i), meta.getTableName(i), name); } ret.put(name, resultSet.getObject(i)); + + // convert (C/B)LOBs to java objects. + // A java.sql.Clob depends on an open connection, so storing this object in a map + // that is accessed later, when the connection is closed, will result in a "connection is closed" exception. + // From the java.sql.Clob documentation: "... which means that a Clob object contains a logical pointer to the SQL CLOB + // data rather than the data itself." + switch (meta.getColumnType(i)) { + case Types.CLOB: + case Types.NCLOB: + ret.put(name, resultSet.getString(i)); + break; + + case Types.BLOB: + ret.put(name, resultSet.getBytes(i)); + break; + + default: + ret.put(name, resultSet.getObject(i)); + break; + } } return ret; } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlBuilder.java b/ebean-core/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlBuilder.java index 4e0a32e24..0fa4c746e 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlBuilder.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlBuilder.java @@ -9,17 +9,26 @@ import io.ebean.RawSqlBuilder; import io.ebean.SqlRow; import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; +import io.ebean.datasource.DataSourceConfig; +import io.ebeaninternal.server.core.DefaultServer; import io.ebeaninternal.server.rawsql.SpiRawSql.Sql; import org.junit.Test; import org.tests.model.basic.Customer; +import org.tests.model.basic.EBasicClob; +import org.tests.model.basic.PersistentFileContent; import org.tests.model.basic.ResetBasicData; import org.tests.model.rawsql.ERawSqlAggBean; import javax.sql.DataSource; +import java.nio.charset.StandardCharsets; +import java.sql.Blob; import java.sql.Connection; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; @@ -283,4 +292,59 @@ public class TestRawSqlBuilder extends BaseTestCase { } } + @Test + public void testCLobClosedConnection() throws Exception { + final EBasicClob eBasicClob = new EBasicClob(); + eBasicClob.setName("eBasicClob"); + final String description = "This is the CLob description"; + eBasicClob.setDescription(description); + DB.save(eBasicClob); + + final String sql = "select description from ebasic_clob where id = ?"; + + List rows = new ArrayList<>(); + final DataSourceConfig config = ((DefaultServer) DB.getDefault()).getServerConfig().getDataSourceConfig(); + + try (Connection connection = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword()); + PreparedStatement stmt = connection.prepareStatement(sql)) { + stmt.setLong(1, eBasicClob.getId()); + + try (ResultSet resultSet = stmt.executeQuery()) { + while (resultSet.next()) { + rows.add(RawSqlBuilder.sqlRow(resultSet, "true", false)); + } + } + } + + assertThat(rows).hasSize(1); + assertThat(rows.get(0).getString("description")).isEqualTo(description); + } + + @Test + public void testBLobClosedConnection() throws Exception { + final PersistentFileContent pfc = new PersistentFileContent(); + final byte[] bytes = "This is the blob as String".getBytes(StandardCharsets.UTF_8); + pfc.setContent(bytes); + DB.save(pfc); + + final String sql = "select content from persistent_file_content where id = ?"; + + List rows = new ArrayList<>(); + final DataSourceConfig config = ((DefaultServer) DB.getDefault()).getServerConfig().getDataSourceConfig(); + + try (Connection connection = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword()); + PreparedStatement stmt = connection.prepareStatement(sql)) { + stmt.setLong(1, pfc.getId()); + + try (ResultSet resultSet = stmt.executeQuery()) { + while (resultSet.next()) { + rows.add(RawSqlBuilder.sqlRow(resultSet, "true", false)); + } + } + } + + assertThat(rows).hasSize(1); + assertThat(((Blob) rows.get(0).get("content")).getBytes(0, bytes.length)).isEqualTo(bytes); + } + }