[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2388?page=c...
]
strong liu commented on HHH-2388:
---------------------------------
I try to reproduce this issue with the unit test in the *Description* section.
but I got another result, it didn't throw the IllegalStateException, but
org.hibernate.exception.GenericJDBCException: could not insert: [hibernate.MyEntity]
at
org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at
org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2162)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2642)
at
org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at
org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at
org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at
org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at
org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at
org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at hibernate.MyEntityTest.testSDFS(MyEntityTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:154)
--------------------------------------------------------------------
and the log is
15:27:28,299 DEBUG SchemaExport:303 -
create table MyEntity (
id numeric(19,0) identity not null,
cost numeric(10,4) not null,
primary key (id)
)
15:27:28,727 INFO SchemaExport:196 - schema export complete
Hibernate:
insert
into
MyEntity
(cost)
values
(?)
15:27:30,060 WARN JDBCExceptionReporter:77 - SQL Error: 0, SQLState: JZ0NK
15:27:30,061 ERROR JDBCExceptionReporter:78 - JZ0NK: Generated keys are not available
because either the Statement.NO_GENERATED_KEYS was used or no keys were automatically
generated.
15:27:30,870 INFO SessionFactoryImpl:769 - closing
15:27:30,870 INFO DriverManagerConnectionProvider:147 - cleaning up connection pool:
jdbc:sybase:Tds:dev77.qa.atl2.redhat.com:5000/stliu
15:27:31,232 INFO SchemaExport:154 - Running hbm2ddl schema export
15:27:31,233 DEBUG SchemaExport:170 - import file not found: /import.sql
15:27:31,233 INFO SchemaExport:179 - exporting generated schema to database
15:27:35,315 DEBUG SchemaExport:303 -
drop table MyEntity
15:27:35,707 INFO SchemaExport:196 - schema export complete
Insert w/ identity column fails on Sybase but no exception occurs
-----------------------------------------------------------------
Key: HHH-2388
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2388
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.2.1
Environment: Hibernate 3.2.1.GA with annotations
Sybase jConnect 6.05 JDBC driver
Sybase ASE 15 database
Reporter: Tim Morrow
Assignee: strong liu
I have a scenario where storing a new entity fails (i.e. the row is not inserted) but
Hibernate does not realize this. No exceptions are thrown. Later, this leads to
AssertionFailures (if two such entities fail in the same session - they both have the same
PK).
The problem specifically occurs with a table that has a numeric column with precision
(e.g. numeric(10,4)) and an identity column when using Sybase ASE.
==========
To reproduce:
1. Use Sybase jConnect 6.05 JDBC driver with Sybase ASE 15 database.
2. Define an Entity with a long ID and BigDecimal numeric column.
3. Create a corresponding table with an identity column and numeric(10, 4) column.
For example:
hibernate.MyEntity.java:
-----------------------------------------
package hibernate;
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.validator.NotNull;
@Entity
@Table(name = "z_tim_test")
public class MyEntity {
private BigDecimal cost;
private long id;
public MyEntity() {}
@Column(columnDefinition = "numeric(10,4)")
@NotNull public final BigDecimal getCost() {
return cost;
}
@GeneratedValue(strategy = GenerationType.AUTO)
@Id public final long getId() {
return id;
}
public final void setCost(BigDecimal cost) {
this.cost = cost;
}
public final void setId(long id) {
this.id = id;
}
}
Table:
-----------------------------------------
CREATE TABLE z_tim_test
(
id numeric(19) PRIMARY KEY not null,
cost numeric(10,4) not null
);
4. Write some code that stores a new entity and tries to load it:
MyEntity myEntity = new MyEntity();
myEntity.setCost(new BigDecimal("123.12345"));
session.save(myEntity);
session.flush();
session.clear();
List<MyEntity> results = session.createCriteria(MyEntity.class).list();
if (results.size() != 1) {
throw new IllegalStateException("Expected 1 result");
}
This test will throw the IllegalStateException because the row was not persisted and no
errors occurred.
Reason:
* Sybase does not thrown any SQLException when you try and persist a numeric value whose
scale exceeds that defined on the column. Instead, it returns an updateCount of zero and
an identity column value of zero.
* Hibernate does not check the updateCount after executing the statement when using an
Identity column. The offending code is in:
org.hibernate.id.IdentityGenerator$InsertSelectDelegate
public Serializable executeAndExtract(PreparedStatement insert) throws SQLException {
if ( !insert.execute() ) {
while ( !insert.getMoreResults() && insert.getUpdateCount() != -1 ) {
// do nothing until we hit the rsult set containing the generated id
}
}
ResultSet rs = insert.getResultSet();
try {
return IdentifierGeneratorFactory.getGeneratedIdentity( rs,
persister.getIdentifierType() );
}
finally {
rs.close();
}
}
It ignores the updateCount.
The net result is that the object is assigned a PK value of zero. Hibernate continues.
My applicaiton is unaware that the row failed to insert.
Solution:
It would seem to me replacing the above code with:
if (!insert.execute()) {
if (insert.getUpdateCount() < 1) {
throw new HibernateException("No update occurred");
}
while (!insert.getMoreResults()) {
// do nothing until we hit the rsult set containing the generated id
}
}
Would take care of the problem?
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira