Bug 522312: Add support to start sequence generation at nextval
Signed-off-by: Will Dazey <dazeydev.3@gmail.com>
Reviewed-by: Dalia Abo Sheasha <daliasheasha@gmail.com>
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java
index 5051e58..a7415a0 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/PersistenceUnitProperties.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
+ * Copyright (c) 1998, 2017 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -41,6 +41,8 @@
* - 478331 : Added support for defining local or server as the default locale for obtaining timestamps
* 12/03/2015-2.6 Dalia Abo Sheasha
* - 483582: Add the javax.persistence.sharedCache.mode property
+ * 09/14/2017-2.6 Will Dazey
+ * - 522312: Add the eclipselink.sequencing.start-sequence-at-nextval property
******************************************************************************/
package org.eclipse.persistence.config;
@@ -2260,6 +2262,20 @@ public class PersistenceUnitProperties {
public static final String SEQUENCING_SEQUENCE_DEFAULT = "eclipselink.sequencing.default-sequence-to-table";
/**
+ * By default, EclipseLink generates sequence values at (NEXTVAL - allocationSize). For instance, if NEXTVAL returns a
+ * value of 100 and the allocationSize is 50 (default), EclipseLink will begin sequence values at 100 - allocationSize.
+ * When the "<code>eclipselink.sequencing.start-sequence-at-nextval</code>" property
+ * is set to true, the ID values generated from sequences starting at NEXTVAL and proceeding forward.
+ * <p>
+ * <b>Allowed Values</b> (String)<b>:</b>
+ * <ul>
+ * <li>"<code>false</code>" - (DEFAULT) uses default behavior of next value - allocationSize
+ * <li>"<code>true</code>"
+ * </ul>
+ */
+ public static final String SEQUENCING_START_AT_NEXTVAL = "eclipselink.sequencing.start-sequence-at-nextval";
+
+ /**
* The "<code>eclipselink.session.customizer</code>" property configures a
* {@link SessionCustomizer} used to alter the runtime configuration through
* API.
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java
index 607a526..b6fb00f 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/databaseaccess/DatasourcePlatform.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -11,6 +11,8 @@
* Oracle - initial API and implementation from Oracle TopLink
* 09/29/2016-2.7 Tomas Kraus
* - 426852: @GeneratedValue(strategy=GenerationType.IDENTITY) support in Oracle 12c
+ * 09/14/2017-2.6 Will Dazey
+ * - 522312: Add the eclipselink.sequencing.start-sequence-at-nextval property
******************************************************************************/
package org.eclipse.persistence.internal.databaseaccess;
@@ -87,6 +89,9 @@ public class DatasourcePlatform implements Platform {
/** If the native sequence type is not supported, if table sequencing should be used. */
protected boolean defaultNativeSequenceToTable;
+ /** If sequences should start at Next Value */
+ protected boolean defaultSeqenceAtNextValue;
+
public DatasourcePlatform() {
this.tableQualifier = "";
this.startDelimiter = "";
@@ -107,6 +112,20 @@ public void setDefaultNativeSequenceToTable(boolean defaultNativeSequenceToTable
this.defaultNativeSequenceToTable = defaultNativeSequenceToTable;
}
+ /**
+ * Return if the sequence generation should start at next value.
+ */
+ public boolean getDefaultSeqenceAtNextValue() {
+ return defaultSeqenceAtNextValue;
+ }
+
+ /**
+ * Set if the sequence generation should start at next value.
+ */
+ public void setDefaultSeqenceAtNextValue(boolean defaultSeqenceAtNextValue) {
+ this.defaultSeqenceAtNextValue = defaultSeqenceAtNextValue;
+ }
+
protected void addOperator(ExpressionOperator operator) {
platformOperators.put(Integer.valueOf(operator.getSelector()), operator);
}
@@ -220,7 +239,8 @@ public void copyInto(Platform platform) {
}
datasourcePlatform.setSequences(getSequences());
datasourcePlatform.sequencesAfterCloneCleanup();
- datasourcePlatform.defaultNativeSequenceToTable = this.defaultNativeSequenceToTable;
+ datasourcePlatform.setDefaultNativeSequenceToTable(getDefaultNativeSequenceToTable());
+ datasourcePlatform.setDefaultSeqenceAtNextValue(getDefaultSeqenceAtNextValue());
}
/**
diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sequencing/StandardSequence.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sequencing/StandardSequence.java
index 00f9e98..cf144db 100644
--- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sequencing/StandardSequence.java
+++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sequencing/StandardSequence.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -9,6 +9,8 @@
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
+ * 09/14/2017-2.6 Will Dazey
+ * - 522312: Add the eclipselink.sequencing.start-sequence-at-nextval property
******************************************************************************/
package org.eclipse.persistence.sequencing;
@@ -72,6 +74,9 @@ public Vector getGeneratedVector(Accessor accessor, AbstractSession writeSession
if (value == null) {
throw DatabaseException.errorPreallocatingSequenceNumbers();
}
+ if(writeSession.getPlatform().getDefaultSeqenceAtNextValue()) {
+ return createVectorAtNextVal(value, seqName, size);
+ }
return createVector(value, seqName, size);
} else {
return null;
@@ -103,6 +108,30 @@ protected Vector createVector(Number sequence, String seqName, int size) {
return sequencesForName;
}
+ /**
+ * INTERNAL:
+ * given sequence = 10, size = 5 will create Vector (10,11,12,13,14)
+ * @param seqName String is sequencing number field name
+ * @param size int size of Vector to create.
+ */
+ protected Vector createVectorAtNextVal(Number sequence, String seqName, int size) {
+ long nextSequence = sequence.longValue();
+
+ Vector sequencesForName = new Vector(size);
+
+ // Check for incorrect values return to validate that the sequence is setup correctly.
+ // PRS 36451 intvalue would wrap
+ if (nextSequence < -1L) {
+ throw ValidationException.sequenceSetupIncorrectly(seqName);
+ }
+
+ for (int index = size; index > 0; index--) {
+ sequencesForName.add(nextSequence);
+ nextSequence = nextSequence + 1L;
+ }
+ return sequencesForName;
+ }
+
public void setInitialValue(int initialValue) {
// sequence value should be positive
if (initialValue <= 0) {
diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/TestSequenceStartAtNextValue.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/TestSequenceStartAtNextValue.java
new file mode 100644
index 0000000..232e0a1
--- /dev/null
+++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/TestSequenceStartAtNextValue.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * 09/14/2017-2.6.0 Will Dazey
+ * - 522312: Add support for sequence generation to start forward from nextval
+ ******************************************************************************/
+package org.eclipse.persistence.jpa.test.sequence;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform;
+import org.eclipse.persistence.internal.jpa.EntityManagerImpl;
+import org.eclipse.persistence.jpa.test.framework.DDLGen;
+import org.eclipse.persistence.jpa.test.framework.Emf;
+import org.eclipse.persistence.jpa.test.framework.EmfRunner;
+import org.eclipse.persistence.jpa.test.framework.Property;
+import org.eclipse.persistence.jpa.test.sequence.model.SequenceEntity;
+import org.eclipse.persistence.queries.ValueReadQuery;
+import org.eclipse.persistence.sequencing.QuerySequence;
+import org.eclipse.persistence.sequencing.Sequence;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * The purpose of this test is to test that when Sequencing defaultSeqenceAtNextValue is set,
+ * the ID values generated from the sequence will start at the Next Val value and not -size.
+ */
+@RunWith(EmfRunner.class)
+public class TestSequenceStartAtNextValue {
+
+ @Emf(createTables = DDLGen.DROP_CREATE, classes = { SequenceEntity.class, }, properties = {
+ @Property(name = "eclipselink.sequencing.start-sequence-at-nextval", value = "true") })
+ private EntityManagerFactory emf;
+
+ @Test
+ public void testStartSequenceAtNextval() {
+ EntityManagerImpl em = emf.createEntityManager().unwrap(EntityManagerImpl.class);
+
+ Sequence seq = em.getServerSession().getDescriptor(SequenceEntity.class).getSequence();
+ if (seq instanceof QuerySequence) {
+ if(((DatasourcePlatform)seq.getDatasourcePlatform()).supportsSequenceObjects()) {
+ ValueReadQuery q = ((DatasourcePlatform)seq.getDatasourcePlatform()).buildSelectQueryForSequenceObject(seq.getQualified(seq.getName()), seq.getPreallocationSize());
+ if(q != null) {
+ //Execute NextVal or whatever query moves the sequence forward size
+ //This gives us a baseline to compare to
+ int nextVal = ((Number)em.getServerSession().executeQuery(q)).intValue();
+ //Calling this next should prompt another query for NextVal, returning the next ID value
+ int seqNum = em.getServerSession().getNextSequenceNumberValue(SequenceEntity.class).intValue();
+ //Expect (nextVal + size), not (nextVal + size) - size
+ Assert.assertEquals("Expected " + seqNum + " == " + nextVal + " + " + seq.getPreallocationSize() + "(Size)", nextVal + seq.getPreallocationSize(), seqNum);
+ } else {
+ Assert.fail((DatasourcePlatform)seq.getDatasourcePlatform() + " does support SequenceObjects, but SelectQuery is null.");
+ }
+ } else {
+ System.out.println((DatasourcePlatform)seq.getDatasourcePlatform() + " does not support SequenceObjects. Test is not valid.");
+ }
+ } else {
+ Assert.fail("Expected sequence for " + SequenceEntity.class + " to be of type QuerySequence, but was " + seq);
+ }
+
+ em.close();
+ }
+}
diff --git a/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/model/SequenceEntity.java b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/model/SequenceEntity.java
new file mode 100644
index 0000000..3814971
--- /dev/null
+++ b/jpa/eclipselink.jpa.test.jse/src/org/eclipse/persistence/jpa/test/sequence/model/SequenceEntity.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * 09/14/2017-2.6.0 Will Dazey
+ * - 522312: Add support for sequence generation to start forward from nextval
+ ******************************************************************************/
+package org.eclipse.persistence.jpa.test.sequence.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="SEQ_ENTITY")
+public class SequenceEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private Integer id;
+
+}
\ No newline at end of file
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
index 97a5121..f0fee31 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1998, 2016 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
+ * Copyright (c) 1998, 2017 Oracle and/or its affiliates, IBM Corporation. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
@@ -74,6 +74,8 @@
* - 483582: Add the javax.persistence.sharedCache.mode property
* 09/29/2016-2.7 Tomas Kraus
* - 426852: @GeneratedValue(strategy=GenerationType.IDENTITY) support in Oracle 12c
+ * 09/14/2017-2.6 Will Dazey
+ * - 522312: Add the eclipselink.sequencing.start-sequence-at-nextval property
*****************************************************************************/
package org.eclipse.persistence.internal.jpa;
@@ -2801,6 +2803,7 @@ protected void updateSession(Map m, ClassLoader loader) {
updateNativeSQLSetting(m);
updateSequencing(m);
+ updateSequencingStart(m);
updateAllowNativeSQLQueriesSetting(m);
updateSQLCastSetting(m);
updateUppercaseSetting(m);
@@ -3291,6 +3294,17 @@ protected void updateSequencing(Map m){
}
}
+ protected void updateSequencingStart(Map m) {
+ String local = EntityManagerFactoryProvider.getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.SEQUENCING_START_AT_NEXTVAL, m, session);
+ try {
+ if (local != null) {
+ this.session.getPlatform().setDefaultSeqenceAtNextValue(Boolean.parseBoolean(local));
+ }
+ } catch (NumberFormatException exception) {
+ this.session.handleException(ValidationException.invalidValueForProperty(local, PersistenceUnitProperties.USE_LOCAL_TIMESTAMP, exception));
+ }
+ }
+
/**
* Load the projectCacheAccessor for JPA project caching
*/