From 42594533daad43e83dc64368e4b3f48330a45399 Mon Sep 17 00:00:00 2001 From: tFellner Date: Mon, 20 Dec 2021 04:11:30 +0100 Subject: [PATCH] Support for Sequences in MariaDB (#2304) * Support for Sequneces in MariaDB * clean up readSequenceValue in test class * remove flakiness * remove change for later discussion * replace deprecated methods * strictly allow sequences --- .../dbplatform/mariadb/MariaDbPlatform.java | 12 ++++ .../dbplatform/mariadb/MariaDbSequence.java | 24 ++++++++ .../org/tests/idkeys/TestGeneratedKeys.java | 61 +++++++++++++++---- 3 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbSequence.java diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java index 082f31c11..0abdef7bd 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java @@ -1,6 +1,10 @@ package io.ebean.config.dbplatform.mariadb; +import javax.sql.DataSource; + +import io.ebean.BackgroundExecutor; import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.PlatformIdGenerator; import io.ebean.config.dbplatform.mysql.BaseMySqlPlatform; /** @@ -11,6 +15,14 @@ public class MariaDbPlatform extends BaseMySqlPlatform { public MariaDbPlatform() { super(); this.platform = Platform.MARIADB; + this.sequenceBatchMode = false; this.historySupport = new MariaDbHistorySupport(); + this.dbIdentity.setSupportsSequence(true); } + + @Override + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { + return new MariaDbSequence(be, ds, seqName, stepSize); + } + } diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbSequence.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbSequence.java new file mode 100644 index 000000000..c6350213f --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbSequence.java @@ -0,0 +1,24 @@ +package io.ebean.config.dbplatform.mariadb; + +import io.ebean.BackgroundExecutor; +import io.ebean.config.dbplatform.SequenceStepIdGenerator; + +import javax.sql.DataSource; + +public class MariaDbSequence extends SequenceStepIdGenerator { + + private final String nextSql; + + /** + * Construct where batchSize is the sequence step size. + */ + public MariaDbSequence(BackgroundExecutor be, DataSource ds, String seqName, int stepSize) { + super(be, ds, seqName, stepSize); + this.nextSql = "select next value for " + seqName; + } + + @Override + public String getSql(int batchSize) { + return nextSql; + } +} diff --git a/ebean-test/src/test/java/org/tests/idkeys/TestGeneratedKeys.java b/ebean-test/src/test/java/org/tests/idkeys/TestGeneratedKeys.java index 56245930c..8f57569a0 100644 --- a/ebean-test/src/test/java/org/tests/idkeys/TestGeneratedKeys.java +++ b/ebean-test/src/test/java/org/tests/idkeys/TestGeneratedKeys.java @@ -14,6 +14,8 @@ import org.tests.idkeys.db.GenKeySeqB; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assumptions.assumeTrue; @@ -24,6 +26,7 @@ public class TestGeneratedKeys extends BaseTestCase { @ForPlatform(Platform.H2) // readSequenceValue is H2 specific public void testGenKeySeqA() throws SQLException { assumeTrue(idType() == IdType.SEQUENCE); + SpiEbeanServer server = spiEbeanServer(); try (Transaction tx = server.beginTransaction()) { @@ -69,20 +72,34 @@ public class TestGeneratedKeys extends BaseTestCase { } private long readSequenceValue(Transaction tx, String sequence) throws SQLException { - Statement stm = null; - try { - stm = tx.connection().createStatement(); - ResultSet rs = stm.executeQuery("select currval('" + sequence + "')"); - rs.next(); + String sql; + switch (spiEbeanServer().databasePlatform().getPlatform().base()) { + case H2 : + sql = "select currval('" + sequence + "')"; + break; + case DB2 : + sql = "values previous value for " + sequence; + + break; + case SQLSERVER : + sql = "select current_value from sys.sequences where name = '" + sequence + "'"; + break; + + case MARIADB : + throw new UnsupportedOperationException("reading sequence value outside of the current connection is not supported. " + + "See https://mariadb.com/kb/en/previous-value-for-sequence_name/#description"); + + default : + throw new UnsupportedOperationException("reading sequence value from " + + spiEbeanServer().databasePlatform().getPlatform() + + " is not supported."); + + } + try (Statement stm = tx.connection().createStatement()) { + ResultSet rs = stm.executeQuery(sql); + rs.next(); return rs.getLong(1); - } finally { - if (stm != null) { - try { - stm.close(); - } catch (SQLException e) { - } - } } } @@ -109,5 +126,25 @@ public class TestGeneratedKeys extends BaseTestCase { assertNotNull(al.getId()); } } + + @Test + @ForPlatform({Platform.H2, Platform.MARIADB, Platform.SQLSERVER, Platform.DB2}) + public void testGeneratedKeys() throws SQLException { + assumeTrue(idType() == IdType.SEQUENCE); + + SpiEbeanServer server = spiEbeanServer(); + List idList = new ArrayList<>(52); + + try (Transaction tx = server.beginTransaction()) { + // bigger than increment + for (int i = 1; i < 52; i++) { + GenKeySeqA gks = new GenKeySeqA(); + gks.setDescription("my description " + i); + server.save(gks); + assertFalse(idList.contains(gks.getId())); + idList.add(gks.getId()); + } + } + } }