Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Spring Data JDBC - Cannot persist null byte array #1827

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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