diff --git a/src/main/java/io/ebean/DB.java b/src/main/java/io/ebean/DB.java
index db386a5e5..0379bae6d 100644
--- a/src/main/java/io/ebean/DB.java
+++ b/src/main/java/io/ebean/DB.java
@@ -1237,4 +1237,18 @@ public class DB {
return getDefault().json();
}
+ /**
+ * Truncate the base tables for the given bean types.
+ */
+ public static void truncate(Class>... types) {
+ getDefault().truncate(types);
+ }
+
+ /**
+ * Truncate the given tables.
+ */
+ public static void truncate(String... tables) {
+ getDefault().truncate(tables);
+ }
+
}
diff --git a/src/main/java/io/ebean/Database.java b/src/main/java/io/ebean/Database.java
index 8a7b3a9f4..ee9ece29d 100644
--- a/src/main/java/io/ebean/Database.java
+++ b/src/main/java/io/ebean/Database.java
@@ -1580,4 +1580,15 @@ public interface Database {
*
*/
Set validateQuery(Query query);
+
+ /**
+ * Truncate all the given tables.
+ */
+ void truncate(String... tables);
+
+ /**
+ * Truncate the base tables for the given bean types.
+ */
+ void truncate(Class>... tables);
+
}
diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
index f5f865dfc..8f5e4b41c 100644
--- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java
@@ -139,6 +139,10 @@ public class DatabasePlatform {
*/
protected Platform platform = Platform.GENERIC;
+ protected String truncateTable = "truncate table %s";
+ protected String truncateTableBefore;
+ protected String truncateTableAfter;
+
protected String columnAliasPrefix = "c";
protected String tableAliasPlaceHolder = "${ta}";
@@ -708,6 +712,27 @@ public class DatabasePlatform {
return persistBatchOnCascade;
}
+ /**
+ * Return a statement to truncate a table.
+ */
+ public String truncateStatement(String table) {
+ return String.format(truncateTable, table);
+ }
+
+ /**
+ * Return a statement to execute prior to truncate (like disable foreign keys for mysql).
+ */
+ public String truncateStatementBefore() {
+ return truncateTableBefore;
+ }
+
+ /**
+ * Return a statement to execute after truncate (like enable foreign keys for mysql).
+ */
+ public String truncateStatementAfter() {
+ return truncateTableAfter;
+ }
+
/**
* Create the DB schema if it does not exist.
*/
diff --git a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java
index b8ba7d227..df76c6064 100644
--- a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java
+++ b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java
@@ -22,6 +22,7 @@ public class DB2Platform extends DatabasePlatform {
this.platform = Platform.DB2;
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
+ this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
this.sqlLimiter = new Db2SqlLimiter();
this.dbIdentity.setSupportsGetGeneratedKeys(true);
diff --git a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java
index d3418904d..c914559eb 100644
--- a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java
+++ b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java
@@ -26,7 +26,8 @@ public class H2Platform extends DatabasePlatform {
this.supportsDeleteTableAlias = true;
this.dbDefaultValue.setNow("now()");
this.columnAliasPrefix = null;
-
+ //this.truncateTableBefore = "set referential_integrity false";
+ //this.truncateTableAfter = "set referential_integrity true";
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("50200","HYT00")
diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java
index 3e06d0094..6422f7c81 100644
--- a/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java
@@ -18,7 +18,6 @@ public class HanaPlatform extends DatabasePlatform {
this.persistBatchOnCascade = PersistBatch.NONE;
this.supportsResultSetConcurrencyModeUpdatable = false;
this.columnAliasPrefix = null;
-
this.historySupport = new HanaHistorySupport();
this.basicSqlLimiter = new HanaBasicSqlLimiter();
diff --git a/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java b/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java
index 1450b01f7..b8cb1e0dd 100644
--- a/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java
@@ -21,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
super();
this.platform = Platform.HSQLDB;
this.dbEncrypt = new H2DbEncrypt();
-
+ this.truncateTable = "delete from %s";
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
index e744ecbad..977ea97f0 100644
--- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
@@ -31,7 +31,8 @@ public class MySqlPlatform extends DatabasePlatform {
this.dbEncrypt = new MySqlDbEncrypt();
this.historySupport = new MySqlHistorySupport();
this.columnAliasPrefix = null;
-
+ //this.truncateTableBefore = "set foreign_key_checks = 0";
+ //this.truncateTableAfter = "set foreign_key_checks = 1";
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsIdentity(true);
diff --git a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java
index cedd2a481..5ba237428 100644
--- a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java
@@ -30,7 +30,7 @@ public class OraclePlatform extends DatabasePlatform {
this.sqlLimiter = new RownumSqlLimiter();
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
this.historySupport = new OracleDbHistorySupport();
-
+ this.truncateTable = "truncate table %s cascade";
dbIdentity.setIdType(IdType.SEQUENCE);
dbIdentity.setSupportsSequence(true);
dbIdentity.setSupportsIdentity(true);
diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java
index 938f5b3b3..f7a4f63d9 100644
--- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java
@@ -36,7 +36,7 @@ public class PostgresPlatform extends DatabasePlatform {
this.clobDbType = Types.VARCHAR;
this.nativeUuidType = true;
this.columnAliasPrefix = null;
-
+ this.truncateTable = "truncate table %s cascade";
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
diff --git a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java
index 2e15fd007..09db19312 100644
--- a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java
@@ -17,7 +17,7 @@ public class SQLitePlatform extends DatabasePlatform {
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSupportsSequence(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()");
-
+ this.truncateTable = "delete from %s";
this.booleanDbType = Types.INTEGER;
this.likeClauseRaw = "like ?";
this.likeClauseEscaped = "like ?";
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index 85c4391db..9818052c3 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -124,8 +124,10 @@ import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
+import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.Clock;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -639,6 +641,38 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
externalModification(evt);
}
+ @Override
+ public void truncate(Class>... types) {
+ List tableNames = new ArrayList<>();
+ for (Class> type : types) {
+ tableNames.add(getBeanDescriptor(type).getBaseTable());
+ }
+ truncate(tableNames.toArray(new String[0]));
+ }
+
+ @Override
+ public void truncate(String... tables) {
+ try (Connection connection = getDataSource().getConnection()) {
+ executeSql(connection, databasePlatform.truncateStatementBefore());
+ for (String table : tables) {
+ executeSql(connection, databasePlatform.truncateStatement(table));
+ }
+ executeSql(connection, databasePlatform.truncateStatementAfter());
+ connection.commit();
+ } catch(SQLException e) {
+ throw new PersistenceException("Error executing truncate", e);
+ }
+ }
+
+ private void executeSql(Connection connection, String sql) throws SQLException {
+ if (sql != null) {
+ try (PreparedStatement stmt = connection.prepareStatement(sql)) {
+ transactionManager.log().sql().debug(sql);
+ stmt.execute();
+ }
+ }
+ }
+
/**
* Clear the query execution statistics.
*/
diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
index bde5e8b34..e52dda337 100644
--- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
+++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
@@ -94,7 +94,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void setClock(Clock clock) {
-
}
@Override
@@ -104,7 +103,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void shutdownManaged() {
-
}
@Override
@@ -113,8 +111,15 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
}
@Override
- public void scopedTransactionEnter(TxScope txScope) {
+ public void truncate(String... tables) {
+ }
+ @Override
+ public void truncate(Class>... tables) {
+ }
+
+ @Override
+ public void scopedTransactionEnter(TxScope txScope) {
}
@Override
@@ -229,7 +234,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void clearServerTransaction() {
-
}
@Override
@@ -249,7 +253,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void remoteTransactionEvent(RemoteTransactionEvent event) {
-
}
@Override
@@ -274,17 +277,14 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void merge(Object bean) {
-
}
@Override
public void merge(Object bean, MergeOptions options) {
-
}
@Override
public void merge(Object bean, MergeOptions options, Transaction transaction) {
-
}
@Override
@@ -304,12 +304,10 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void loadBean(LoadBeanRequest loadRequest) {
-
}
@Override
public void loadMany(LoadManyRequest loadRequest) {
-
}
@Override
@@ -324,27 +322,22 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void collectQueryStats(ObjectGraphNode objectGraphNode, long loadedBeanCount, long timeMicros) {
-
}
@Override
public void visitMetrics(MetricVisitor visitor) {
-
}
@Override
public void loadMany(BeanCollection> collection, boolean onlyIds) {
-
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
-
}
@Override
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) {
-
}
@Override
@@ -439,7 +432,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void sort(List list, String sortByClause) {
-
}
@Override
@@ -449,12 +441,10 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void findDtoEach(SpiDtoQuery query, Consumer consumer) {
-
}
@Override
public void findDtoEachWhile(SpiDtoQuery query, Predicate consumer) {
-
}
@Override
@@ -509,7 +499,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void findEachRow(SpiSqlQuery query, RowConsumer consumer) {
-
}
@Override
@@ -539,7 +528,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void register(TransactionCallback transactionCallback) throws PersistenceException {
-
}
@Override
@@ -614,32 +602,26 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void flush() {
-
}
@Override
public void commitTransaction() {
-
}
@Override
public void rollbackTransaction() {
-
}
@Override
public void endTransaction() {
-
}
@Override
public void refresh(Object bean) {
-
}
@Override
public void refreshMany(Object bean, String propertyName) {
-
}
@Override
@@ -679,12 +661,10 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void findEach(Query query, Consumer consumer, Transaction transaction) {
-
}
@Override
public void findEachWhile(Query query, Predicate consumer, Transaction transaction) {
-
}
@Override
@@ -757,7 +737,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void save(Object bean) throws OptimisticLockException {
-
}
@Override
@@ -807,7 +786,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted) {
-
}
@Override
@@ -817,37 +795,30 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void save(Object bean, Transaction transaction) throws OptimisticLockException {
-
}
@Override
public void markAsDirty(Object bean) {
-
}
@Override
public void update(Object bean) throws OptimisticLockException {
-
}
@Override
public void update(Object bean, Transaction t) throws OptimisticLockException {
-
}
@Override
public void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException {
-
}
@Override
public void insert(Object bean) {
-
}
@Override
public void insert(Object bean, Transaction t) {
-
}
@Override
@@ -887,7 +858,6 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
-
}
@Override
@@ -902,12 +872,10 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void execute(TxScope scope, Runnable r) {
-
}
@Override
public void execute(Runnable r) {
-
}
@Override
@@ -982,27 +950,22 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
@Override
public void updateAll(Collection> beans) throws OptimisticLockException {
-
}
@Override
public void updateAll(Collection> beans, Transaction transaction) throws OptimisticLockException {
-
}
@Override
public void insertAll(Collection> beans) {
-
}
@Override
public void insertAll(Collection> beans, Transaction transaction) {
-
}
@Override
public void slowQueryCheck(long executionTimeMicros, int rowCount, SpiQuery> query) {
-
}
@Override
diff --git a/src/test/java/main/StartCockroach.java b/src/test/java/main/StartCockroach.java
new file mode 100644
index 000000000..5aa4a87a5
--- /dev/null
+++ b/src/test/java/main/StartCockroach.java
@@ -0,0 +1,16 @@
+package main;
+
+import io.ebean.docker.commands.CockroachConfig;
+import io.ebean.docker.commands.CockroachContainer;
+
+public class StartCockroach {
+
+ public static void main(String[] args) {
+
+ CockroachConfig config = new CockroachConfig();
+ config.setDbName("unit");
+
+ CockroachContainer container = new CockroachContainer(config);
+ container.startWithDropCreate();
+ }
+}
diff --git a/src/test/java/org/tests/model/nofk/Test2NoFk.java b/src/test/java/org/tests/model/nofk/Test2NoFk.java
index a6851bf9b..bf00656a8 100644
--- a/src/test/java/org/tests/model/nofk/Test2NoFk.java
+++ b/src/test/java/org/tests/model/nofk/Test2NoFk.java
@@ -1,6 +1,7 @@
package org.tests.model.nofk;
import io.ebean.BaseTestCase;
+import io.ebean.DB;
import io.ebean.Ebean;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
@@ -21,9 +22,8 @@ public class Test2NoFk extends BaseTestCase {
@Before
public void setup() {
// Reset t
- Ebean.find(EFile2NoFk.class).delete();
- Ebean.find(EUserNoFk.class).delete();
- Ebean.find(EUserNoFkSoftDel.class).delete();
+ DB.truncate(EFile2NoFk.class, EUserNoFk.class, EUserNoFkSoftDel.class);
+ assertThat(DB.find(EFile2NoFk.class).findCount()).isEqualTo(0);
// There are two user accounts persisted in our database
EUserNoFk root = new EUserNoFk();
diff --git a/src/test/java/org/tests/model/nofk/TestTruncate.java b/src/test/java/org/tests/model/nofk/TestTruncate.java
new file mode 100644
index 000000000..bf22cb284
--- /dev/null
+++ b/src/test/java/org/tests/model/nofk/TestTruncate.java
@@ -0,0 +1,46 @@
+package org.tests.model.nofk;
+
+import io.ebean.DB;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestTruncate {
+
+ @Test
+ public void test_truncateByClass() {
+ DB.truncate(EUserNoFkSoftDel.class, EUserNoFk.class);
+
+ insertRows();
+ assertRowCounts(1);
+
+ DB.truncate(EUserNoFkSoftDel.class, EUserNoFk.class);
+ assertRowCounts(0);
+ }
+
+ @Test
+ public void test_truncateByTable() {
+ DB.truncate(EUserNoFkSoftDel.class, EUserNoFk.class);
+
+ insertRows();
+ assertRowCounts(1);
+
+ DB.truncate("euser_no_fk_soft_del", "euser_no_fk");
+ assertRowCounts(0);
+ }
+
+ private void insertRows() {
+ EUserNoFk root = new EUserNoFk();
+ root.setUserName("root");
+ DB.save(root);
+
+ EUserNoFkSoftDel rootSoftDel = new EUserNoFkSoftDel();
+ rootSoftDel.setUserName("root");
+ DB.save(rootSoftDel);
+ }
+
+ private void assertRowCounts(int expected) {
+ assertThat(DB.find(EUserNoFk.class).findCount()).isEqualTo(expected);
+ assertThat(DB.find(EUserNoFkSoftDel.class).findCount()).isEqualTo(expected);
+ }
+}
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
index 8d4ee5d7c..50294ed9b 100644
--- a/src/test/resources/logback-test.xml
+++ b/src/test/resources/logback-test.xml
@@ -79,7 +79,7 @@
-
+