OpenJPA
  1. OpenJPA
  2. OPENJPA-2072

InvalidStateException deleting an instance with a timestamp in its primary key

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.2.1, 1.2.2, 1.2.3
    • Fix Version/s: 1.0.5, 1.2.3, 2.0.2, 2.1.2, 2.2.1, 2.3.0
    • Component/s: None
    • Labels:
      None
    • Environment:
      Linux, JUnit + Spring and HSQLDB in a case; Windows, WebSphere and DB2 in another case
    • Patch Info:
      Patch Available

      Description

      Attempting to remove an instance that has a timestamp field in its primary key results in this error:
      org.apache.openjpa.persistence.InvalidStateException: Operation attempted on a deleted instance.

      Suppose I have this table:
      CREATE TABLE test_tsp (
      t Timestamp,
      desc char(30)
      )

      containing just the following row:
      INSERT INTO test_tsp(T,DESC) VALUES ( CURRENT_TIMESTAMP, 'one')

      the table is mapped to this JPA Entity
      @Entity
      @Table(name="TEST_TSP")
      public class TestTsp implements Serializable {
      private static final long serialVersionUID = -5756434331459759089L;
      @Column(name="T")
      @Id
      private Timestamp idTsp;

      @Column(name="DESC")
      private String desc;

      public TestTsp()

      { super(); }

      ...getters and setters here...
      }

      and the following code attempts a delete of the row I've inserted

      Query query = em.createQuery("select t from TestTsp t where t.desc='one'");
      List<TestTsp> list = query.getResultList();
      for (TestTsp t : list)

      { em.remove(t); }

      Here is the error I get:
      ...
      Caused by: <openjpa-1.2.2-r422266:898935 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: Operation attempted on a deleted instance.
      FailedObject: org.apache.openjpa.enhance.provatsp$TestTsp$pcsubclass@3c0b655a
      at org.apache.openjpa.kernel.PCState.error(PCState.java:443)
      at org.apache.openjpa.kernel.PDeletedState.beforeOptimisticWrite(PDeletedState.java:76)
      at org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1575)
      at org.apache.openjpa.kernel.StateManagerImpl.dirty(StateManagerImpl.java:1515)
      at org.apache.openjpa.util.Proxies.dirty(Proxies.java:66)
      at org.apache.openjpa.util.java$sql$Timestamp$proxy.setNanos(Unknown Source)
      at org.apache.openjpa.jdbc.sql.DBDictionary.setTimestamp(DBDictionary.java:1144)
      at org.apache.openjpa.jdbc.sql.DBDictionary.setTyped(DBDictionary.java:1282)
      at org.apache.openjpa.jdbc.sql.RowImpl.flush(RowImpl.java:890)
      at org.apache.openjpa.jdbc.sql.RowImpl.flush(RowImpl.java:850)
      at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushAndUpdate(PreparedStatementManagerImpl.java:118)
      at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushAndUpdate(BatchingPreparedStatementManagerImpl.java:82)
      at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushInternal(PreparedStatementManagerImpl.java:89)
      at org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flush(PreparedStatementManagerImpl.java:72)
      at org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:543)
      at org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:119)
      at org.apache.openjpa.jdbc.kernel.BatchingConstraintUpdateManager.flush(BatchingConstraintUpdateManager.java:59)
      at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:89)
      at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:72)
      at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:721)
      at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:130)
      ... 40 more

      N.B.: the error doesn't happen if the primary key annotation (@Id) is moved on the other field of the entity, which is not a timestamp but a char:
      @Column(name="T")
      private Timestamp idTsp;

      @Column(name="DESC")
      @Id
      private String desc;

        Activity

        Hide
        Helen Xu added a comment -

        Before it set the time stamp value to the delete prepared statement, it will set the nanosecond of the time stamp based on the precision. This setting triggered the dirty update on PDeletedState and caused the invalid state error being generated.

        here is the code path

        PDeletedState.beforeOptimisticWrite(StateManagerImpl, int, boolean) line: 76
        StateManagerImpl.dirty(int, Boolean, boolean) line: 1546
        StateManagerImpl.dirty(int) line: 1485
        Proxies.dirty(Proxy, boolean) line: 66
        java$sql$Timestamp$proxy.setNanos(int) line: not available
        DB2Dictionary(DBDictionary).setTimestamp(PreparedStatement, int, Timestamp, Calendar, Column) line: 1103
        DB2Dictionary(DBDictionary).setTyped(PreparedStatement, int, Object, Column, int, JDBCStore) line: 1241
        PrimaryRow(RowImpl).flush(PreparedStatement, int, DBDictionary, JDBCStore) line: 888
        PrimaryRow(RowImpl).flush(PreparedStatement, DBDictionary, JDBCStore) line: 848
        PreparedStatementManagerImpl.flushInternal(RowImpl) line: 95
        PreparedStatementManagerImpl.flush(RowImpl) line: 73
        ConstraintUpdateManager.flush(Collection, PreparedStatementManager) line: 543
        ConstraintUpdateManager.flush(RowManager, PreparedStatementManager, Collection) line: 119
        ConstraintUpdateManager(AbstractUpdateManager).flush(Collection, JDBCStore, PreparedStatementManager) line: 89
        ConstraintUpdateManager(AbstractUpdateManager).flush(Collection, JDBCStore) line: 72
        JDBCStoreManager.flush(Collection) line: 514
        ROPStoreManager(DelegatingStoreManager).flush(Collection) line: 130
        FinalizingBrokerImpl(BrokerImpl).flush(int) line: 1956
        FinalizingBrokerImpl(BrokerImpl).flushSafe(int) line: 1854
        FinalizingBrokerImpl(BrokerImpl).beforeCompletion() line: 1772
        LocalManagedRuntime.commit() line: 81
        FinalizingBrokerImpl(BrokerImpl).commit() line: 1294
        DelegatingBroker.commit() line: 861
        EntityManagerImpl.commit() line: 408

        Fix and test case attached.

        Show
        Helen Xu added a comment - Before it set the time stamp value to the delete prepared statement, it will set the nanosecond of the time stamp based on the precision. This setting triggered the dirty update on PDeletedState and caused the invalid state error being generated. here is the code path PDeletedState.beforeOptimisticWrite(StateManagerImpl, int, boolean) line: 76 StateManagerImpl.dirty(int, Boolean, boolean) line: 1546 StateManagerImpl.dirty(int) line: 1485 Proxies.dirty(Proxy, boolean) line: 66 java$sql$Timestamp$proxy.setNanos(int) line: not available DB2Dictionary(DBDictionary).setTimestamp(PreparedStatement, int, Timestamp, Calendar, Column) line: 1103 DB2Dictionary(DBDictionary).setTyped(PreparedStatement, int, Object, Column, int, JDBCStore) line: 1241 PrimaryRow(RowImpl).flush(PreparedStatement, int, DBDictionary, JDBCStore) line: 888 PrimaryRow(RowImpl).flush(PreparedStatement, DBDictionary, JDBCStore) line: 848 PreparedStatementManagerImpl.flushInternal(RowImpl) line: 95 PreparedStatementManagerImpl.flush(RowImpl) line: 73 ConstraintUpdateManager.flush(Collection, PreparedStatementManager) line: 543 ConstraintUpdateManager.flush(RowManager, PreparedStatementManager, Collection) line: 119 ConstraintUpdateManager(AbstractUpdateManager).flush(Collection, JDBCStore, PreparedStatementManager) line: 89 ConstraintUpdateManager(AbstractUpdateManager).flush(Collection, JDBCStore) line: 72 JDBCStoreManager.flush(Collection) line: 514 ROPStoreManager(DelegatingStoreManager).flush(Collection) line: 130 FinalizingBrokerImpl(BrokerImpl).flush(int) line: 1956 FinalizingBrokerImpl(BrokerImpl).flushSafe(int) line: 1854 FinalizingBrokerImpl(BrokerImpl).beforeCompletion() line: 1772 LocalManagedRuntime.commit() line: 81 FinalizingBrokerImpl(BrokerImpl).commit() line: 1294 DelegatingBroker.commit() line: 861 EntityManagerImpl.commit() line: 408 Fix and test case attached.

          People

          • Assignee:
            Helen Xu
            Reporter:
            Ernesto Ricci
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development