Internal exception when updating date filed (TemporalType.DATE)

#1

Hello!

ObjectDB version 2.5.3_02.

I get internal exception when commiting update Date field (javax.persistence.TemporalType.DATE).

[ObjectDB 2.5.3_02] javax.persistence.RollbackException
Failed to commit transaction:  (error 613)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:290)
at odbdatebugtestcase.DataManager.updatePersonsBirthday(DataManager.java:42)
at odbdatebugtestcase.OdbDateBugTestCase.main(OdbDateBugTestCase.java:27)
Caused by: com.objectdb.o.InternalException
at com.objectdb.o.InternalException.f(InternalException.java:236)
at com.objectdb.o.IPW.ar(IPW.java:119)
at com.objectdb.o.PGW.am(PGW.java:201)
at com.objectdb.o.UPT.G(UPT.java:257)
at com.objectdb.o.UPT.m(UPT.java:172)
at com.objectdb.o.URT.m(URT.java:181)
at com.objectdb.o.TSK.k(TSK.java:183)
at com.objectdb.o.TSK.i(TSK.java:156)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.UTT.A(UTT.java:365)
at com.objectdb.o.UTT.l(UTT.java:218)
at com.objectdb.o.TSK.i(TSK.java:145)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.MST.Vc(MST.java:1315)
at com.objectdb.o.WRA.Vc(WRA.java:372)
at com.objectdb.o.WSM.Vc(WSM.java:183)
at com.objectdb.o.OBM.bN(OBM.java:918)
at com.objectdb.o.OBM.bL(OBM.java:823)
at com.objectdb.o.OBM.bJ(OBM.java:729)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:287)
... 2 more

My test example attached 

Here is my output:

run:
Type not found exception - new database?
Set new birthday:Sat Mar 01 12:38:39 MSK 1980
Set new birthday:Tue Mar 31 12:38:39 MSK 1981
Set new birthday:Wed Apr 01 13:38:39 MSD 1981
[ObjectDB 2.5.3_02] javax.persistence.RollbackException
Failed to commit transaction:  (error 613)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:290)
at odbdatebugtestcase.DataManager.updatePersonsBirthday(DataManager.java:42)
at odbdatebugtestcase.OdbDateBugTestCase.main(OdbDateBugTestCase.java:27)
Caused by: com.objectdb.o.InternalException
at com.objectdb.o.InternalException.f(InternalException.java:236)
at com.objectdb.o.IPW.ar(IPW.java:119)
at com.objectdb.o.PGW.am(PGW.java:201)
at com.objectdb.o.UPT.G(UPT.java:257)
at com.objectdb.o.UPT.m(UPT.java:172)
at com.objectdb.o.URT.m(URT.java:181)
at com.objectdb.o.TSK.k(TSK.java:183)
at com.objectdb.o.TSK.i(TSK.java:156)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.UTT.A(UTT.java:365)
at com.objectdb.o.UTT.l(UTT.java:218)
at com.objectdb.o.TSK.i(TSK.java:145)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.MST.Vc(MST.java:1315)
at com.objectdb.o.WRA.Vc(WRA.java:372)
at com.objectdb.o.WSM.Vc(WSM.java:183)
at com.objectdb.o.OBM.bN(OBM.java:918)
at com.objectdb.o.OBM.bL(OBM.java:823)
at com.objectdb.o.OBM.bJ(OBM.java:729)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:287)
... 2 more

Best regards,

Alexander.

#2

Running the project produced the following output with no error:

run:
Set new birthday:Sat Mar 01 01:59:26 IST 1980
Set new birthday:Tue Mar 31 01:59:26 IST 1981
Set new birthday:Wed Apr 01 01:59:26 IST 1981

In addition, test cases should be in the form of a single top level class, as explained in the posting instructions.

Here is your test case in that form. Try to modify it to produce the error, and if possible, remove any irrelevant lines, so the test case will be as short as possible.

import java.util.*;
import javax.jdo.annotations.Index;
import javax.persistence.*;

public class T1312 {

    public static void main(String[] args) {

        DataManager dataManager = new DataManager("$objectdb/db/persons.odb");
        dataManager.initDatabase();

        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+03:00"));
        List<Date> dates = new ArrayList<Date>();
        calendar.set(1980, 2, 1);
        dates.add(calendar.getTime());
        calendar.set(1981, 2, 31);
        dates.add(calendar.getTime());
        calendar.set(1981, 3, 1);
        dates.add(calendar.getTime());

        for (Date newBirthday : dates) {
            dataManager.updatePersonsBirthday(newBirthday);
        }

        dataManager.close();
    }

    public static class DataManager {

        private final int GENERATE_PERSONS_COUNT = 1000;

        private EntityManagerFactory entityManagerFactory;
        private EntityManager entityManager;

        public DataManager(String connectionString) {
            entityManagerFactory = Persistence.createEntityManagerFactory(connectionString);
            entityManager = entityManagerFactory.createEntityManager();
        }

        public void initDatabase() {
            long personsCount = getPersonsCount();
            if (personsCount == 0) {
                createPersons(GENERATE_PERSONS_COUNT);
            }
        }

        public void updatePersonsBirthday(Date newBirthday) {
            System.out.println("Set new birthday:" + newBirthday.toString());
            try {
                entityManager.getTransaction().begin();
                TypedQuery<Person> personQuery = entityManager.createQuery(
                    "select p from Person p", Person.class);
                List<Person> persons = personQuery.getResultList();
                for(Person person : persons) {
                    person.setBirthday(newBirthday);
                }
                entityManager.getTransaction().commit();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        public void close() {
            entityManager.close();
            entityManagerFactory.close();
        }

        private void createPersons(long count) {
            try {
                entityManager.getTransaction().begin();
                for (int index = 0; index < count; index++) {
                    Person person = generatePerson();
                    entityManager.persist(person);
                }
                entityManager.getTransaction().commit();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        private Person generatePerson() {
            Person person = new Person();
            person.setName(UUID.randomUUID().toString());
            person.setBirthday(new Date());
            return person;
        }

        private long getPersonsCount() {
            try {
                Query countQuery = entityManager.createQuery("select count(p.id) from Person p");
                return (Long)countQuery.getSingleResult();
            } catch (javax.persistence.PersistenceException ex) {
                System.out.println("Type not found exception - new database?");
                return 0;
            }
        }
    }

    @Entity
    public static class Person {

        private static final long serialVersionUID = 1L;

        // -------------------- persistent fields ----------------------------------

        @Id
        private String id = UUID.randomUUID().toString();

        @Temporal(javax.persistence.TemporalType.TIMESTAMP) @Index
        private Date createDate = new Date();

        @Temporal(javax.persistence.TemporalType.TIMESTAMP)
        private Date modifyDate = new Date();

        private String name;

        @Index
        @Temporal(javax.persistence.TemporalType.DATE)
        private Date birthday;

        // -------------------- accessors ------------------------------------------

        public String getId() {
            return id;
        }

        public Date getCreateDate() {
            return createDate;
        }

        public Date getModifyDate() {
            return modifyDate;
        }

        public void setModifyDate(Date modifyDate) {
            this.modifyDate = modifyDate;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Date getBirthday() {
            return birthday;
        }

        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }

        // -------------------- override -------------------------------------------
        @Override
        public String toString() {
            return "Person : { id:" + id + ", birthday:" + birthday.toString() + " }";
        }

    }
}
ObjectDB Support
#3

The problem arise when the vm time zone is "Europe/Moscow" and entity count is greater or equal 1000.

There is no problem then i set time zone "GMT+04:00".

The problem does not occur every time, when I create less than 1,000 users.

I slightly changed my example to reproduce my issue (set timezone to "Europe/Moscow").

My output:

run:
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=14400000,dstSavings=0,useDaylight=false,transitions=78,lastRule=null]
Set new birthday:Sat Mar 01 16:40:26 MSK 1980
Set new birthday:Tue Mar 31 16:40:26 MSK 1981
Set new birthday:Wed Apr 01 16:40:26 MSD 1981
[ObjectDB 2.5.3_02] javax.persistence.RollbackException
Failed to commit transaction:  (error 613)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:290)
at odbdatebugtestcase.OdbDateBugTestCase.main(OdbDateBugTestCase.java:67)
Caused by: com.objectdb.o.InternalException
at com.objectdb.o.InternalException.f(InternalException.java:236)
at com.objectdb.o.IPW.ar(IPW.java:119)
at com.objectdb.o.PGW.am(PGW.java:201)
at com.objectdb.o.UPT.G(UPT.java:257)
at com.objectdb.o.UPT.m(UPT.java:172)
at com.objectdb.o.URT.m(URT.java:181)
at com.objectdb.o.TSK.k(TSK.java:183)
at com.objectdb.o.TSK.i(TSK.java:156)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.UTT.A(UTT.java:365)
at com.objectdb.o.UTT.l(UTT.java:218)
at com.objectdb.o.TSK.i(TSK.java:145)
at com.objectdb.o.TSK.f(TSK.java:95)
at com.objectdb.o.TSM.e(TSM.java:86)
at com.objectdb.o.MST.Vc(MST.java:1315)
at com.objectdb.o.WRA.Vc(WRA.java:372)
at com.objectdb.o.WSM.Vc(WSM.java:183)
at com.objectdb.o.OBM.bN(OBM.java:918)
at com.objectdb.o.OBM.bL(OBM.java:823)
at com.objectdb.o.OBM.bJ(OBM.java:729)
at com.objectdb.jpa.EMImpl.commit(EMImpl.java:287)
... 1 more

 

Best regards,

Alexander.

#4

Exapmle source:

 

package odbdatebugtestcase;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import javax.jdo.annotations.Index;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Id;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.Temporal;
import javax.persistence.TypedQuery;

public class OdbDateBugTestCase {

    public static void main(String[] args) {
       
        // time zone with problems
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
   
        // init connection
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("$objectdb/db/persons.odb");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getMetamodel().entity(Person.class);
       
        // generate persons
        Query countQuery = entityManager.createQuery("select count(p.id) from Person p");
        long personsCount = (long) countQuery.getSingleResult();
       
        if (personsCount == 0) {
            entityManager.getTransaction().begin();
            for (int index = 0; index < 10000; index++) {
                Person person = new Person();
                person.setBirthday(new Date());
                entityManager.persist(person);
            }
            entityManager.getTransaction().commit();
        }
       
        // create dates for update
        Calendar calendar = Calendar.getInstance();
        System.out.println(calendar.getTimeZone().toString());
        List<Date> dates = new ArrayList<Date>();
        calendar.set(1980, 2, 1);
        dates.add(calendar.getTime());
        calendar.set(1981, 2, 31);
        dates.add(calendar.getTime());
        calendar.set(1981, 3, 1);
        dates.add(calendar.getTime());

        // update birthday field
        for (Date newBirthday : dates) {
            System.out.println("Set new birthday:" + newBirthday.toString());
            try {
                entityManager.getTransaction().begin();
                TypedQuery<Person> personQuery = entityManager.createQuery("select p from Person p", Person.class);
                List<Person> persons = personQuery.getResultList();
                for(Person person : persons) {
                    person.setBirthday(newBirthday);
                }
                entityManager.getTransaction().commit();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
       
        entityManager.close();
        entityManagerFactory.close();
       
    }
   
    @Entity
    public static class Person {

        private static final long serialVersionUID = 1L;

        // -------------------- persistent fields ----------------------------------

        @Id
        private String id = UUID.randomUUID().toString();

        @Index
        @Temporal(javax.persistence.TemporalType.DATE)
        private Date birthday;

        // -------------------- accessors ------------------------------------------

        public String getId() {
            return id;
        }

        public Date getBirthday() {
            return birthday;
        }

        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }

        // -------------------- override -------------------------------------------
        @Override
        public String toString() {
            return "Person : { id:" + id + ", birthday:" + birthday.toString() + " }";
        }

    }
   
}
#5

Thank you for this test case, which exposes an ObjectDB bug in handling dates in some time zones.

Please try build 2.5.4_02, which should fix this issue.

ObjectDB Support
#6

Due to another issue relevant code has changed on build 2.6.4_03. The test case above still seems to work, so hopefully the cause of the "Europe/Moscow" time zone issue reported in this thread will not repeat.

ObjectDB Support

Reply