Skip to content

Spring Data JDBC - Cannot persist null byte array #1827

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
Bram80 opened this issue Jun 26, 2024 · 6 comments
Closed

Spring Data JDBC - Cannot persist null byte array #1827

Bram80 opened this issue Jun 26, 2024 · 6 comments
Assignees
Labels
for: external-project For an external project and not something we can fix

Comments

@Bram80
Copy link

Bram80 commented Jun 26, 2024

We're receiving following stacktrace when persisting a byte array as null using Spring Data:

Caused by: org.springframework.jdbc.UncategorizedSQLException: 
PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO "SOME_TABLE" 
("CONTENT") VALUES (?)]; SQL state [S0003]; error code [257]; Implicit conversion from data type nvarchar to varbinary(max) is not allowed. Use the CONVERT function to run this query.
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1549)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1001)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:365)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:349)
at org.springframework.data.jdbc.core.convert.IdGeneratingInsertStrategy.execute(IdGeneratingInsertStrategy.java:68)
at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.insert(DefaultDataAccessStrategy.java:110)
at org.springframework.data.jdbc.core.JdbcAggregateChangeExecutionContext.executeInsertRoot(JdbcAggregateChangeExecutionContext.java:83)
at org.springframework.data.jdbc.core.AggregateChangeExecutor.execute(AggregateChangeExecutor.java:85)
... 34 more
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Implicit conversion from data type nvarchar to varbinary(max) is not allowed. Use the CONVERT function to run this query.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:261)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1752)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:686)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:605)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7748)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:4410)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:293)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:263)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:548)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.springframework.jdbc.core.JdbcTemplate.lambda$update$3(JdbcTemplate.java:1002)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)

We're receiving this using spring-boot-starter-parent version 3.3.1,
with version 3.2.0 everythings works.

Example implementation:

@Table("SOME_TABLE")
public record SomeTable(
    @Id @Column("ID")
    Long id,
    @Column("CONTENT")
    byte[] content
) {
}

public interface SomeTableRepository extends CrudRepository<SomeTable, Long> {
}

@DataJdbcTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@EnableJdbcRepositories(considerNestedRepositories = true)
@ContextConfiguration(classes = {
    SomeTableRepository.class
})
@Sql(executionPhase = BEFORE_TEST_METHOD, value = {
    "classpath:0_init.sql",
    "classpath:1_load.sql"
})
@Sql(executionPhase = AFTER_TEST_METHOD, value = "classpath:2_clean.sql")
class ByteTest extends MssqlContainerBaseTest {

  @Autowired
  private SomeTableRepository someTableRepository;

  @Test
  void testByteArrayNotNull() {
      final SomeTable record = new SomeTable(null, "abc".getBytes());
      someTableRepository.save(record);
  }

  @Test
  void testByteArrayNull() {
      final SomeTable record = new SomeTable(null, null);
      someTableRepository.save(record);
  }

  @Test
  void testByteArrayEmpty() {
      final SomeTable record = new SomeTable(null, new byte[]{});
      someTableRepository.save(record);
  }

}

testByteArrayNull test method doesn't work.

testByteArrayNotNull and testByteArrayEmpty test methods work fine.

So we've a workaround by an using empty Byte array instead of null.
Although, null should be possible as it was by earlier versions.

I included a reproducable example.
test-container-test.zip

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 26, 2024
@mp911de mp911de added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 27, 2024
@schauder
Copy link
Contributor

schauder commented Jul 2, 2024

All the tests in the reproducer are green, but there is no testByteArrayEmpty.

Please provide an actual reproducer of the issue.

@schauder schauder added the status: waiting-for-feedback We need additional information before we can continue label Jul 2, 2024
@Bram80
Copy link
Author

Bram80 commented Jul 2, 2024

Here you go :-)

test-container-test.zip

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 2, 2024
@schauder
Copy link
Contributor

schauder commented Jul 4, 2024

Thanks for the reproducer.

This does not seem to originate in Spring Data JDBC, since it can be reproduced with just a NamedParameterJdbcTemplate.

My first guess was a regression in the JDBC driver, but switching that arround doesn't seem to make a difference.

See the additional test and branches in https://github.com/schauder/issue-jdbc-1827-insert-null-array

I'll see what the Spring Framework team has to say.

@schauder schauder added for: external-project For an external project and not something we can fix and removed type: bug A general bug status: feedback-provided Feedback has been provided labels Jul 4, 2024
@jhoeller
Copy link

jhoeller commented Jul 6, 2024

@Bram80 assuming that spring-projects/spring-framework#25679 might be the cause here: Does it help to set the following system property (can also be an entry in a spring.properties file in the root of the classpath) - spring.jdbc.getParameterType.ignore=false

@schauder schauder added the status: waiting-for-feedback We need additional information before we can continue label Jul 8, 2024
@Bram80
Copy link
Author

Bram80 commented Jul 8, 2024

@jhoeller Setting the system property you mentioned solves the issue.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 8, 2024
@schauder
Copy link
Contributor

schauder commented Jul 9, 2024

@jhoeller I'm going to close this issue, since the problem of the OP is resolved. Thanks for the help there.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

5 participants