diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Version.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Version.java index 3086daa5a..57a19043c 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Version.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Version.java @@ -368,7 +368,7 @@ public class Version } /** - * @return a Map specifying how to update each version + * @return a Map specifying how to update each version * column in this instance during a bulk update. * * @since 1.0.0 diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java index 60c80c2f1..9f7e6382d 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java @@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.schema.Column; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.StoreManager; +import org.apache.openjpa.jdbc.schema.Column; /** * Handles optimistic lock versioning for a class. @@ -78,7 +79,7 @@ public interface VersionStrategy public int compareVersion(Object v1, Object v2); /** - * @return a Map specifying how to update each version + * @return a Map specifying how to update each version * column during a bulk update. * * @since 1.0.0 diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java index 957e403a8..0393d5f64 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java @@ -1972,9 +1972,15 @@ public class DBDictionary iter.hasNext(); ) { Map.Entry e = (Map.Entry) iter.next(); Column col = (Column) e.getKey(); - String val = (String) e.getValue(); - sql.append(", ").append(col.getName()) - .append(" = ").append(val); + Object val = e.getValue(); + sql.append(", ").append(col.getName()).append(" = "); + // Version update value for Numeric version is encoded in a String + // to make SQL such as version = version+1 while Time stamp version is parameterized + if (val instanceof String) { + sql.append((String)val); + } else { + sql.appendValue(val); + } } } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/NumericVersionedEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/NumericVersionedEntity.java new file mode 100644 index 000000000..4ec37b043 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/NumericVersionedEntity.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.update; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Version; + +/** + * An entity using a Timestamp as Version field. + * + * + * @author Pinaki Poddar + * + */ +@Entity +public class NumericVersionedEntity { + @Id + @GeneratedValue + private long id; + + private String name; + + @Version + private int version; + + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getVersion() { + return version; + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TestTimestampVersion.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TestTimestampVersion.java new file mode 100644 index 000000000..9c57c00d7 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TestTimestampVersion.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.update; + +import java.sql.Timestamp; + +import javax.persistence.EntityManager; + +import org.apache.openjpa.persistence.test.SingleEMFTestCase; + +/** + * Tests for update on entity that uses a Timestamp as version. + * + * @see OPENJPA-1583 + * + * @author Pinaki Poddar + * + */ +public class TestTimestampVersion extends SingleEMFTestCase { + public void setUp() { + super.setUp(CLEAR_TABLES, TimestampedEntity.class, NumericVersionedEntity.class); + } + + public void testBulkUpdateOnTimestampedVersion() { + TimestampedEntity pc = new TimestampedEntity(); + pc.setName("Original"); + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(pc); + em.getTransaction().commit(); + + try { + // delay to ensure the new timestamp exceeds the timer's resolution. + Thread.sleep(100); + } catch (InterruptedException e) { + } + + em.getTransaction().begin(); + Timestamp oldVersion = pc.getVersion(); + String jpql = "UPDATE TimestampedEntity t SET t.name=:newname WHERE t.name=:oldname"; + em.createQuery(jpql) + .setParameter("newname", "Updated") + .setParameter("oldname", "Original") + .executeUpdate(); + em.getTransaction().commit(); + + em.getTransaction().begin(); + em.refresh(pc); + Timestamp newVersion = pc.getVersion(); + assertTrue(newVersion.after(oldVersion)); + } + + public void testBulkUpdateOnNumericVersion() { + NumericVersionedEntity pc = new NumericVersionedEntity(); + pc.setName("Original"); + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(pc); + em.getTransaction().commit(); + + em.getTransaction().begin(); + int oldVersion = pc.getVersion(); + String jpql = "UPDATE NumericVersionedEntity t SET t.name=:newname WHERE t.name=:oldname"; + em.createQuery(jpql) + .setParameter("newname", "Updated") + .setParameter("oldname", "Original") + .executeUpdate(); + em.getTransaction().commit(); + + em.getTransaction().begin(); + em.refresh(pc); + int newVersion = pc.getVersion(); + assertEquals(newVersion, oldVersion+1); + } + + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TimestampedEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TimestampedEntity.java new file mode 100644 index 000000000..599967ddc --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/update/TimestampedEntity.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.update; + +import java.sql.Timestamp; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Version; + +/** + * An entity using a Timestamp as Version field. + * + * + * @author Pinaki Poddar + * + */ +@Entity +@Table(name="TSENTITY") +public class TimestampedEntity { + @Id + @GeneratedValue + private long id; + + private String name; + + @Version + private Timestamp version; + + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Timestamp getVersion() { + return version; + } + +}