apache / apache/grails-core

Cascading deletion attempts to set a non-nullable column to null

Open
#14,586 0 comments 0 reactions 0 assignees View on GitHub
relates-to: gorm
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

### Task List

- [x] Steps to reproduce provided
- [x] Stacktrace (if present) provided
- [x] Example that reproduces the problem uploaded to Github
- [x] Full description of the issue provided (see below)

### Steps to Reproduce

1. Create a parent domain object that aggregates two child domain objects, and one of those child domain object has the other child domain object as a property (https://github.com/joemccall86/cascade-delete-test/tree/master/grails-app/domain/cascade/delete/test)
2. Populate the domain objects and attempt to delete the parent domain object
3. Delete the object (force a flush to see the error immediately)

### Expected Behaviour

The parent object is deleted, and deletions cascade onto the child objects

### Actual Behaviour

The underlying database complains that a `null` value is being set for a non-nullable column. e.g.,:
```
org.h2.jdbc.JdbcSQLException: NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]
```

Stacktrace:

```
2018-02-20 16:10:06.995 ERROR --- [ Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper : NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]
cascade.delete.test.OrganizationSpec > organization deletions cascade FAILED
org.springframework.dao.DataIntegrityViolationException at OrganizationSpec.groovy:29
Caused by: org.h2.jdbc.JdbcSQLException at OrganizationSpec.groovy:29

Hibernate operation: could not execute statement; SQL [n/a]; NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]; nested exception is org.h2.jdbc.JdbcSQLException: NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]
org.springframework.dao.DataIntegrityViolationException: Hibernate operation: could not execute statement; SQL [n/a]; NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]; nested exception is org.h2.jdbc.JdbcSQLException: NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:243)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.grails.orm.hibernate.GrailsHibernateTemplate.convertJdbcAccessException(GrailsHibernateTemplate.java:711)
at org.grails.orm.hibernate.GrailsHibernateTemplate.convertHibernateAccessException(GrailsHibernateTemplate.java:699)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:290)
at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:230)
at org.grails.orm.hibernate.GrailsHibernateTemplate.execute(GrailsHibernateTemplate.java:116)
at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.delete(AbstractHibernateGormInstanceApi.groovy:193)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.delete(GormEntity.groovy:193)
at cascade.delete.test.OrganizationSpec.$tt__$spock_feature_0_0(OrganizationSpec.groovy:29)
at cascade.delete.test.OrganizationSpec.organization deletions cascade_closure1(OrganizationSpec.groovy)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at grails.transaction.GrailsTransactionTemplate$1.doInTransaction(GrailsTransactionTemplate.groovy:70)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.transaction.GrailsTransactionTemplate.executeAndRollback(GrailsTransactionTemplate.groovy:67)
at cascade.delete.test.OrganizationSpec.organization deletions cascade(OrganizationSpec.groovy)
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "SELECTED_CHANNEL_ID"; SQL statement:
update person set version=?, name=?, organization_id=?, selected_channel_id=? where id=? and version=? [23502-194]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.table.Column.validateConvertUpdateSequence(Column.java:311)
at org.h2.table.Table.validateConvertUpdateSequence(Table.java:793)
at org.h2.command.dml.Update.update(Update.java:125)
at org.h2.command.CommandContainer.update(CommandContainer.java:101)
at org.h2.command.Command.executeUpdate(Command.java:258)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:160)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:146)
at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:138)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3132)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3011)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3391)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:145)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1295)
at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.delete_closure1(AbstractHibernateGormInstanceApi.groovy:196)
at groovy.lang.Closure.call(Closure.java:414)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:286)
... 12 more
```

### Environment Information

- **Operating System**: Ubuntu MATE 17.10
- **GORM Version:** 6.0.13.RELEASE
- **Grails Version (if using Grails):** 3.2.12
- **JDK Version:** `openjdk version "1.8.0_162"`

### Example Application

- https://github.com/joemccall86/cascade-delete-test

### Note

This issue does not appear in 6.1.8.RELEASE.

Contributor guide

Open the contributing guide

Research direction

Start with the linked cascade-delete-test example and OrganizationSpec.groovy:29, where deletion and flushing reproduce the failure on GORM 6.0.13. Compare the behavior with GORM 6.1.8, where the issue is reported absent, and trace the delete operation shown in the stacktrace. Done means cascading deletion no longer attempts to write null to the non-nullable selected_channel_id column.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.