Nikola Hrusov (
https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%...
) *created* an issue
Hibernate ORM (
https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiOGY3ZDFlNjQ0...
) / Bug (
https://hibernate.atlassian.net/browse/HHH-14122?atlOrigin=eyJpIjoiOGY3ZD...
) HHH-14122 (
https://hibernate.atlassian.net/browse/HHH-14122?atlOrigin=eyJpIjoiOGY3ZD...
) org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare
statement; when trying to delete entities (
https://hibernate.atlassian.net/browse/HHH-14122?atlOrigin=eyJpIjoiOGY3ZD...
)
Issue Type: Bug Affects Versions: 5.4.0 Assignee: Unassigned Components: hibernate-core,
query-sql Created: 28/Jul/2020 02:01 AM Priority: Critical Reporter: Nikola Hrusov (
https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%...
)
We have an issue when we tried to upgrade our springboot from 2.1.0 to 2.2.0
After posting in spring-boot github issues:
https://github.com/spring-projects/spring-boot/issues/22599
and then into Spring JPA project:
https://jira.spring.io/browse/DATAJPA-1763 I ended up
here, which is perhaps where I should've started.
We are trying to update our springboot application from 2.1.0 to 2.3.2
All goes good except for some specific queries that we have. Our queries work up until
2.1.16, but not on 2.2.0
Our query is as following:
@Modifying
@Transactional
@Query( "DELETE FROM MainTable mt WHERE mt.special.id = :special_id" )
int deleteBySpecialId(@Param( "special_id" ) Long special_id);
For springboot <= 2.1.16 that works.
For springboot >= 2.2.0 it throws:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare
statement; SQL [delete from main_table cross join special special1_ where id=?]; nested
exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
I tried to read the release notes of 2.2.0 here, but I cannot find anything related to
this, thus I think it might be a bug. Now I know based on Mark Paluch's answer that
that Spring Boot 2.1 was using Hibernate 5.3 while Boot 2.2 has upgraded to Hibernate 5.4.
(source) (
https://jira.spring.io/browse/DATAJPA-1763?focusedCommentId=189684&pa...
)
When I run both versions (2.1.16 and 2.2.0) with `spring.jpa.show-sql=true` I can see it
produces different queries:
2.1.16:
Hibernate: delete from MainTable where special=?
2.2.0:
Hibernate: delete from MainTable cross join Special special1_ where id=?
Minimal setup to replicate the issue is as following:
MainTable:
@Entity
@Table
public class MainTable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "special" )
@NotFound(action = NotFoundAction.IGNORE)
private Special special;
public void setSpecial(Special special) {
this.special = special;
}
}
Special:
@Entity
@Table
public class Special {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String value;
public Long getId() {
return id;
}
}
MainTableRepository:
@Repository
public interface MainTableRepository extends CrudRepository<MainTable, Long > {
@Modifying
@Transactional
@Query( "DELETE FROM MainTable mt WHERE mt.special.id = :special_id" )
int deleteBySpecialId(@Param( "special_id" ) Long special_id);
}
SpecialRepository:
@Repository
public interface SpecialRepository extends CrudRepository<Special, Long > {
}
Test:
@RunWith(SpringRunner.class)
@DataJpaTest
public class MainTableRepositoryTest {
@Autowired
private MainTableRepository mainTableRepository;
@Autowired
private SpecialRepository specialRepository;
@Test
@Transactional
@Modifying
public void test() {
Special special = new Special();
MainTable mainTable = new MainTable();
mainTable.setSpecial(special);
mainTableRepository.save(mainTable);
specialRepository.save(special);
assertEquals(1, mainTableRepository.count());
assertEquals(1, specialRepository.count());
mainTableRepository.deleteBySpecialId(special.getId());
Assert.isTrue( true );
}
}
test application.properties:
spring.datasource.driver- class- name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.show-sql= true
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
That test passes when ran with the lower version of springboot, but fails with 2.2.0,
2.2.9, 2.3.0 and 2.3.2
This is the full exception:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare
statement; SQL [delete from main_table cross join special special1_ where id=?]; nested
exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:280)
at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:254)
at
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
at
org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at
org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at
org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:149)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy130.deleteBySpecialId(Unknown Source)
at mytestproject.MainTableRepositoryTest.test(MainTableRepositoryTest.java:43) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at
org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at
org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at
org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at
org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at
org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at
org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at
org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at
com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement
at
org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
at
org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at
org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)
at
org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:81)
at org.hibernate.hql.internal.ast.exec.BasicExecutor.doExecute(BasicExecutor.java:87)
at org.hibernate.hql.internal.ast.exec.BasicExecutor.execute(BasicExecutor.java:59)
at org.hibernate.hql.internal.ast.exec.DeleteExecutor.execute(DeleteExecutor.java:113)
at
org.hibernate.hql.internal.ast.QueryTranslatorImpl.executeUpdate(QueryTranslatorImpl.java:454)
at
org.hibernate.engine.query.spi.HQLQueryPlan.performExecuteUpdate(HQLQueryPlan.java:377)
at org.hibernate.internal.SessionImpl.executeUpdate(SessionImpl.java:1434)
at
org.hibernate.query.internal.AbstractProducedQuery.doExecuteUpdate(AbstractProducedQuery.java:1623)
at
org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1605)
at
org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:238)
at
org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)
at
org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154)
at
org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 38 more
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement
"DELETE FROM MAIN_TABLE CROSS[*] JOIN SPECIAL SPECIAL1_ WHERE ID=? " ; SQL
statement:delete from main_table cross join special special1_ where id=? [42000-199]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:451)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:427)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.message.DbException.getSyntaxError(DbException.java:229)
at org.h2.command.Parser.getSyntaxError(Parser.java:989)
at org.h2.command.Parser.prepareCommand(Parser.java:686)
at org.h2.engine.Session.prepareLocal(Session.java:627)
at org.h2.engine.Session.prepareCommand(Session.java:565)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1292)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:77)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:349)
at
org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:90)
at
org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176)
... 58 more
(
https://hibernate.atlassian.net/browse/HHH-14122#add-comment?atlOrigin=ey...
) Add Comment (
https://hibernate.atlassian.net/browse/HHH-14122#add-comment?atlOrigin=ey...
)
Get Jira notifications on your phone! Download the Jira Cloud app for Android (
https://play.google.com/store/apps/details?id=com.atlassian.android.jira....
) or iOS (
https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=Em...
) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100140- sha1:454f3ac )