Compare commits

..
37 changed files with 991 additions and 107 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.17.3</version>
<version>11.17.4</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.17.3</tag>
<tag>ebean-11.17.4</tag>
</scm>
<profiles>
@@ -2,6 +2,8 @@ package io.ebean;
import io.ebean.bean.EntityBean;
import java.util.Collection;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
@@ -115,6 +117,13 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
db().save(bean);
}
/**
* Save all the beans in the collection.
*/
public int saveAll(Collection<T> bean) {
return db().saveAll(bean);
}
/**
* Update this entity.
*
@@ -154,6 +163,13 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
return db().delete(bean);
}
/**
* Delete all the beans in the collection.
*/
public int deleteAll(Collection<T> beans) {
return db().deleteAll(beans);
}
/**
* Delete a bean permanently without soft delete.
* <p>
@@ -57,22 +57,24 @@ import java.util.ServiceLoader;
* <pre>{@code
*
* ServerConfig c = new ServerConfig();
* c.setName("db");
*
* // read the ebean.properties and load
* // those settings into this serverConfig object
* c.loadFromProperties();
*
* // add any classes found in the app.data package
* c.addPackage("com.myapp.domain");
*
* // register as the 'Default' server
* c.setDefaultServer(true);
* // explicitly register the entity beans to avoid classpath scanning
* c.addClass(Customer.class);
* c.addClass(User.class);
*
* EbeanServer server = EbeanServerFactory.create(c);
*
* }</pre>
*
* <p>
* Note that ServerConfigProvider provides a standard Java ServiceLoader mechanism that can
* be used to apply configuration to the ServerConfig.
* </p>
*
* @author emcgreal
* @author rbygrave
* @see EbeanServerFactory
@@ -0,0 +1,39 @@
package io.ebean.config;
/**
* Provides a ServiceLoader based mechanism to configure a ServerConfig.
* <p>
* Provide an implementation and register it via the standard Java ServiceLoader mechanism
* via a file at <code>META-INF/services/io.ebean.config.ServerConfigProvider</code>.
* </p>
* <p>
* If you are using a DI container like Spring or Guice you are unlikely to use this but instead use a
* spring specific configuration. When we are not using a DI container we may use this mechanism to
* explicitly register the entity beans and avoid classpath scanning.
* </p>
* <pre>{@code
*
* public class EbeanConfigProvider implements ServerConfigProvider {
*
* @Override
* public void apply(ServerConfig config) {
*
* // register the entity bean classes explicitly
* config.addClass(Customer.class);
* config.addClass(User.class);
* ...
* }
* }
*
* }</pre>
*/
public interface ServerConfigProvider {
/**
* Apply the configuration to the ServerConfig.
* <p>
* Typically we explicitly register entity bean classes and thus avoid classpath scanning.
* </p>
*/
void apply(ServerConfig config);
}
@@ -53,6 +53,10 @@ public class ScopeTrans {
*/
private boolean rolledBack;
/**
* Flag set when nested commit has occurred.
*/
private boolean nestedCommit;
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope) {
@@ -113,7 +117,6 @@ public class ScopeTrans {
complete();
}
/**
* Complete the transaction programmatically. Try to commit.
*/
@@ -124,7 +127,7 @@ public class ScopeTrans {
}
public void end() {
if (created) {
if (created || !nestedCommit) {
transaction.end();
}
}
@@ -133,6 +136,7 @@ public class ScopeTrans {
if (created) {
transaction.commit();
} else {
nestedCommit = true;
transaction.setBatchFlushOnQuery(restoreBatchFlushOnQuery);
if (restoreBatch != null) {
transaction.setBatch(restoreBatch);
@@ -79,13 +79,21 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
protected void createOrReplaceFunction(DdlBuffer apply, String procedureName, String historyTable, List<String> includedColumns) throws IOException {
apply
.append("create or replace function ").append(procedureName).append("() returns trigger as $$").newLine()
.append("begin").newLine();
.append("create or replace function ").append(procedureName).append("() returns trigger as $$").newLine();
apply.append("declare").newLine()
.append(" lowerTs timestamptz;").newLine()
.append(" upperTs timestamptz;").newLine();
apply.append("begin").newLine()
.append(" lowerTs = lower(OLD.sys_period);").newLine()
.append(" upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);").newLine();
apply
.append(" if (TG_OP = 'UPDATE') then").newLine();
appendInsertIntoHistory(apply, historyTable, includedColumns);
apply
.append(" NEW.").append(sysPeriod).append(" = tstzrange(").append(currentTimestamp).append(",null);").newLine()
.append(" NEW.").append(sysPeriod).append(" = tstzrange(upperTs,null);").newLine()
.append(" return new;").newLine();
apply
.append(" elsif (TG_OP = 'DELETE') then").newLine();
@@ -124,7 +132,7 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriod).append(",");
appendColumnNames(buffer, columns, "");
buffer.append(") values (tstzrange(lower(OLD.").append(sysPeriod).append("), ").append(currentTimestamp).append("), ");
buffer.append(") values (tstzrange(lowerTs,upperTs), ");
appendColumnNames(buffer, columns, "OLD.");
buffer.append(");").newLine();
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.dbmigration.model;
import io.ebeaninternal.dbmigration.migration.ChangeSet;
import io.ebeaninternal.dbmigration.migration.ChangeSetType;
import io.ebeaninternal.dbmigration.migration.DropColumn;
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropTable;
import io.ebeaninternal.dbmigration.migration.Migration;
@@ -207,10 +208,26 @@ public class PendingDrops {
} else if (pendingDrop instanceof DropTable && dropTableIn((DropTable) pendingDrop, appliedDrops)) {
iterator.remove();
} else if (pendingDrop instanceof DropHistoryTable && dropHistoryTableIn((DropHistoryTable) pendingDrop, appliedDrops)) {
iterator.remove();
}
}
}
/**
* Return true if the pendingDrop is contained in the appliedDrops.
*/
private boolean dropHistoryTableIn(DropHistoryTable pendingDrop, ChangeSet appliedDrops) {
for (Object o : appliedDrops.getChangeSetChildren()) {
if (o instanceof DropHistoryTable && sameHistoryTable(pendingDrop, (DropHistoryTable) o)) {
return true;
}
}
return false;
}
/**
* Return true if the pendingDrop is contained in the appliedDrops.
*/
@@ -235,6 +252,13 @@ public class PendingDrops {
return false;
}
/**
* Return true if the DropHistoryTable match by base-table name.
*/
private boolean sameHistoryTable(DropHistoryTable pendingDrop, DropHistoryTable o) {
return pendingDrop.getBaseTable().equals(o.getBaseTable());
}
/**
* Return true if the DropTable match by table name.
*/
@@ -6,6 +6,7 @@ import io.ebean.cache.ServerCacheOptions;
import io.ebean.cache.ServerCachePlugin;
import io.ebean.config.ContainerConfig;
import io.ebean.config.ServerConfig;
import io.ebean.config.ServerConfigProvider;
import io.ebean.config.TenantMode;
import io.ebean.config.UnderscoreNamingConvention;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -62,9 +63,8 @@ public class DefaultContainer implements SpiContainer {
}
private void invokeBootupPlugin() {
Iterator<SpiContainerBootup> it = ServiceLoader.load(SpiContainerBootup.class).iterator();
while (it.hasNext()) {
it.next().bootup();
for (SpiContainerBootup boot : ServiceLoader.load(SpiContainerBootup.class)) {
boot.bootup();
}
}
@@ -103,8 +103,13 @@ public class DefaultContainer implements SpiContainer {
public SpiEbeanServer createServer(ServerConfig serverConfig) {
synchronized (this) {
setNamingConvention(serverConfig);
if (serverConfig.isDefaultServer()) {
for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
configProvider.apply(serverConfig);
}
}
setNamingConvention(serverConfig);
BootupClasses bootupClasses = getBootupClasses(serverConfig);
boolean online = true;
@@ -1734,7 +1734,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (beans == null || beans.isEmpty()) {
return;
}
executeInTrans((txn) -> {
for (Object bean : beans) {
update(checkEntityBean(bean), txn);
@@ -1776,7 +1775,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (beans == null || beans.isEmpty()) {
return;
}
executeInTrans((txn) -> {
for (Object bean : beans) {
persister.insert(checkEntityBean(bean), txn);
@@ -1845,24 +1843,27 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException {
return saveAllInternal(beans.iterator(), transaction);
return saveAllInternal(beans, transaction);
}
@Override
public int saveAll(Collection<?> beans) throws OptimisticLockException {
return saveAllInternal(beans.iterator(), null);
return saveAllInternal(beans, null);
}
/**
* Save all beans in the iterator with an explicit transaction.
*/
private int saveAllInternal(Iterator<?> it, Transaction transaction) {
private int saveAllInternal(Collection<?> beans, Transaction transaction) {
if (beans == null || beans.isEmpty()) {
return 0;
}
return executeInTrans((txn) -> {
txn.checkBatchEscalationOnCollection();
int saveCount = 0;
while (it.hasNext()) {
persister.save(checkEntityBean(it.next()), txn);
for (Object bean : beans) {
persister.save(checkEntityBean(bean), txn);
saveCount++;
}
@@ -1950,12 +1951,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public int deleteAllPermanent(Collection<?> beans) {
return deleteAllInternal(beans.iterator(), null, true);
return deleteAllInternal(beans, null, true);
}
@Override
public int deleteAllPermanent(Collection<?> beans, Transaction t) {
return deleteAllInternal(beans.iterator(), t, true);
return deleteAllInternal(beans, t, true);
}
/**
@@ -1963,7 +1964,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public int deleteAll(Collection<?> beans) {
return deleteAllInternal(beans.iterator(), null, false);
return deleteAllInternal(beans, null, false);
}
/**
@@ -1971,21 +1972,23 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public int deleteAll(Collection<?> beans, Transaction t) {
return deleteAllInternal(beans.iterator(), t, false);
return deleteAllInternal(beans, t, false);
}
/**
* Delete all the beans in the iterator with an explicit transaction.
*/
private int deleteAllInternal(Iterator<?> it, Transaction transaction, boolean permanent) {
private int deleteAllInternal(Collection<?> beans, Transaction transaction, boolean permanent) {
if (beans == null || beans.isEmpty()) {
return 0;
}
return executeInTrans((txn) -> {
txn.checkBatchEscalationOnCollection();
int deleteCount = 0;
while (it.hasNext()) {
EntityBean bean = checkEntityBean(it.next());
persister.delete(bean, txn, permanent);
for (Object bean : beans) {
persister.delete(checkEntityBean(bean), txn, permanent);
deleteCount++;
}
@@ -2,11 +2,16 @@ package io.ebeaninternal.server.persist;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiProfileTransactionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* A batched statement that is held in BatchedPstmtHolder. It has a list of
@@ -17,6 +22,8 @@ import java.util.ArrayList;
*/
public class BatchedPstmt implements SpiProfileTransactionEvent {
private static final Logger log = LoggerFactory.getLogger(BatchedPstmt.class);
/**
* The underlying statement.
*/
@@ -40,6 +47,8 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
private int[] results;
private List<InputStream> inputStreams;
/**
* Create with a given statement.
*/
@@ -117,16 +126,19 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
}
private void executeAndCheckRowCounts() throws SQLException {
try {
results = pstmt.executeBatch();
if (results.length != list.size()) {
String s = "results array error " + results.length + " " + list.size();
throw new SQLException(s);
}
results = pstmt.executeBatch();
if (results.length != list.size()) {
String s = "results array error " + results.length + " " + list.size();
throw new SQLException(s);
}
// check for concurrency exceptions...
for (int i = 0; i < results.length; i++) {
list.get(i).checkRowCount(results[i]);
// check for concurrency exceptions...
for (int i = 0; i < results.length; i++) {
list.get(i).checkRowCount(results[i]);
}
} finally {
closeInputStreams();
}
}
@@ -148,4 +160,23 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
public int[] getResults() {
return results;
}
/**
* Register any inputStreams that should be closed after execution.
*/
public void registerInputStreams(List<InputStream> inputStreams) {
this.inputStreams = inputStreams;
}
private void closeInputStreams() {
if (inputStreams != null) {
for (InputStream inputStream : inputStreams) {
try {
inputStream.close();
} catch (IOException e) {
log.warn("Error closing inputStream ", e);
}
}
}
}
}
@@ -39,6 +39,15 @@ public class BatchedPstmtHolder {
* This will return null if no matching PreparedStatement is found.
*/
public PreparedStatement getStmt(String stmtKey, BatchPostExecute postExecute) {
BatchedPstmt batchedPstmt = getBatchedPstmt(stmtKey, postExecute);
return (batchedPstmt == null) ? null : batchedPstmt.getStatement();
}
/**
* Return the BatchedPstmt that holds the batched statement.
*/
public BatchedPstmt getBatchedPstmt(String stmtKey, BatchPostExecute postExecute) {
BatchedPstmt bs = stmtMap.get(stmtKey);
if (bs == null) {
// the PreparedStatement has need been created
@@ -53,7 +62,7 @@ public class BatchedPstmtHolder {
if (bsSize > maxSize) {
maxSize = bsSize;
}
return bs.getStatement();
return bs;
}
/**
@@ -46,6 +46,8 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
*/
protected DataBind dataBind;
protected BatchedPstmt batchedPstmt;
protected String sql;
/**
@@ -273,20 +275,18 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
/**
* Return a prepared statement taking into account batch requirements.
*/
protected PreparedStatement getPstmt(SpiTransaction t, String sql, PersistRequestBean<?> request,
boolean genKeys) throws SQLException {
protected PreparedStatement getPstmt(SpiTransaction t, String sql, PersistRequestBean<?> request, boolean genKeys) throws SQLException {
BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
PreparedStatement stmt = batch.getStmt(sql, request);
if (stmt != null) {
return stmt;
batchedPstmt = batch.getBatchedPstmt(sql, request);
if (batchedPstmt != null) {
return batchedPstmt.getStatement();
}
stmt = getPstmt(t, sql, genKeys);
PreparedStatement stmt = getPstmt(t, sql, genKeys);
BatchedPstmt bs = new BatchedPstmt(stmt, genKeys, sql, t);
batch.addStmt(bs, request);
batchedPstmt = new BatchedPstmt(stmt, genKeys, sql, t);
batch.addStmt(batchedPstmt, request);
return stmt;
}
@@ -91,7 +91,9 @@ public class InsertHandler extends DmlHandler {
}
dataBind = bind(pstmt);
meta.bind(this, bean, withId, persistRequest.isPublish());
if (persistRequest.isBatched()) {
batchedPstmt.registerInputStreams(dataBind.getInputStreams());
}
logSql(sql);
}
@@ -47,7 +47,9 @@ public class UpdateHandler extends DmlHandler {
}
dataBind = bind(pstmt);
meta.bind(persistRequest, this, updatePlan);
if (persistRequest.isBatched()) {
batchedPstmt.registerInputStreams(dataBind.getInputStreams());
}
setUpdateGenValues();
logSql(sql);
@@ -1,8 +1,11 @@
package io.ebeaninternal.server.type;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
@@ -13,10 +16,14 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class DataBind {
private static final Logger log = LoggerFactory.getLogger(DataBind.class);
private final DataTimeZone dataTimeZone;
private final PreparedStatement pstmt;
@@ -25,6 +32,8 @@ public class DataBind {
private final StringBuilder bindLog = new StringBuilder();
private List<InputStream> inputStreams;
private int pos;
public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt, Connection connection) {
@@ -79,7 +88,24 @@ public class DataBind {
}
public int executeUpdate() throws SQLException {
return pstmt.executeUpdate();
try {
return pstmt.executeUpdate();
} finally {
closeInputStreams();
}
}
private void closeInputStreams() {
if (inputStreams != null) {
for (InputStream inputStream : inputStreams) {
try {
inputStream.close();
} catch (IOException e) {
log.warn("Error closing InputStream that was bound to PreparedStatement", e);
}
}
inputStreams = null;
}
}
public PreparedStatement getPstmt() {
@@ -147,7 +173,19 @@ public class DataBind {
pstmt.setString(++pos, String.valueOf(v));
}
/**
* Return any inputStreams that have been bound (and should be closed).
* This is used for batched statement execution only.
*/
public List<InputStream> getInputStreams() {
return inputStreams;
}
public void setBinaryStream(InputStream inputStream, long length) throws SQLException {
if (inputStreams == null) {
inputStreams = new ArrayList<>();
}
inputStreams.add(inputStream);
pstmt.setBinaryStream(++pos, inputStream, length);
}
@@ -94,6 +94,26 @@ public class EbeanServer_saveAllTest extends BaseTestCase {
}
@Test
public void deleteAll_withNull() {
Ebean.deleteAll(null);
}
@Test
public void deleteAll_withEmpty() {
Ebean.saveAll(beans(0));
}
@Test
public void saveAll_withNull() {
Ebean.saveAll(null);
}
@Test
public void saveAll_withEmpty() {
Ebean.saveAll(beans(0));
}
@Test
public void saveAll_withTransaction() {
@@ -0,0 +1,85 @@
package io.ebeaninternal.dbmigration;
import io.ebean.EbeanServer;
import io.ebean.EbeanServerFactory;
import io.ebean.annotation.Platform;
import io.ebean.config.ServerConfig;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.StrictAssertions.assertThatThrownBy;
/**
* This is the Migrationscript generator. It generates 3 migrationscript for the models
* @author Roland Praml, FOCONIS AG
*
*/
public class DbMigrationDropHistoryTest {
private static final Logger logger = LoggerFactory.getLogger(DbMigrationDropHistoryTest.class);
@Test
public void invokeTest() throws IOException {
main(null);
}
public static void main(String[] args) throws IOException {
logger.info("start");
DefaultDbMigration migration = new DefaultDbMigration();
// We use src/test/resources as output directory (so we see in GIT if files will change)
migration.setPathToResources("src/test/resources");
ServerConfig config = new ServerConfig();
config.setName("migrationtest-history");
config.loadFromProperties();
config.setRegister(false);
config.setDefaultServer(false);
config.setPackages(Arrays.asList("misc.migration.history.v1_0"));
EbeanServer server = EbeanServerFactory.create(config);
migration.setServer(server);
// First, we clean up the output-directory
assertThat(migration.getMigrationDirectory().getAbsolutePath()).contains("migrationtest-history");
Files.walk(migration.getMigrationDirectory().toPath())
.filter(Files::isRegularFile).map(Path::toFile).forEach(File::delete);
// then we generate migration scripts for v1_0
assertThat(migration.generateMigration()).isEqualTo("1.0__initial");
// and we check repeatative calls
assertThat(migration.generateMigration()).isNull();
// and now for v1_1
config.setPackages(Arrays.asList("misc.migration.history.v1_1"));
server = EbeanServerFactory.create(config);
migration.setServer(server);
assertThat(migration.generateMigration()).isEqualTo("1.1");
assertThat(migration.generateMigration()).isNull(); // subsequent call
System.setProperty("ddl.migration.pendingDropsFor", "1.1");
assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1");
assertThatThrownBy(()->migration.generateMigration())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("No 'pendingDrops'"); // subsequent call
System.clearProperty("ddl.migration.pendingDropsFor");
logger.info("end");
}
}
@@ -15,6 +15,7 @@ import java.nio.file.Path;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
@@ -85,6 +86,11 @@ public class DbMigrationGenerateTest {
System.setProperty("ddl.migration.pendingDropsFor", "1.1");
assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1");
assertThatThrownBy(()->migration.generateMigration())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("No 'pendingDrops'"); // subsequent call
System.clearProperty("ddl.migration.pendingDropsFor");
assertThat(migration.generateMigration()).isNull(); // subsequent call
@@ -98,6 +104,10 @@ public class DbMigrationGenerateTest {
System.setProperty("ddl.migration.pendingDropsFor", "1.3");
assertThat(migration.generateMigration()).isEqualTo("1.4__dropsFor_1.3");
assertThatThrownBy(()->migration.generateMigration())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("No 'pendingDrops'"); // subsequent call
System.clearProperty("ddl.migration.pendingDropsFor");
assertThat(migration.generateMigration()).isNull(); // subsequent call
@@ -0,0 +1,24 @@
package misc.migration.history.v1_0;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import io.ebean.annotation.History;
/**
* detects a bug where dropHistoryTable is not applied correctly
*
* @author Roland Praml, FOCONIS AG
*
*/
@Entity
@Table(name = "migtest_e_history7")
@History
public class EHistory7 {
@Id
Integer id;
}
@@ -0,0 +1,21 @@
package misc.migration.history.v1_1;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* detects a bug where dropHistoryTable is not applied correctly
*
* @author Roland Praml, FOCONIS AG
*
*/
@Entity
@Table(name = "migtest_e_history7")
public class EHistory7 {
@Id
Integer id;
}
@@ -4,6 +4,7 @@ import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.SqlQuery;
import io.ebean.SqlRow;
import io.ebean.Transaction;
import io.ebean.Version;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform;
@@ -93,6 +94,52 @@ public class TestHistoryInsert extends BaseTestCase {
assertThat(versions).hasSize(3);
}
@Test
@ForPlatform({Platform.POSTGRES})
public void test_singleTransaction_multipleHistory() {
User user = new User();
user.setName("First");
user.setEmail("first@email.com");
user.setPasswordHash("someHash");
try (Transaction transaction = Ebean.beginTransaction()) {
// insert and many updates inside transaction
Ebean.save(user);
user.setEmail("first2@email.com");
Ebean.save(user);
user.setEmail("first3@email.com");
Ebean.save(user);
user.setEmail("first4@email.com");
Ebean.save(user);
transaction.commit();
}
// a couple more updates outside of the first transaction
user.setEmail("first5@email.com");
Ebean.save(user);
user.setEmail("first6@email.com");
Ebean.save(user);
List<SqlRow> sqlRows =
Ebean.createSqlQuery("select lower(sys_period) lowerBound, upper(sys_period) upperBound from c_user_history where id = :id order by when_modified")
.setParameter("id", user.getId())
.findList();
Timestamp previousUpper = null;
for (SqlRow sqlRow : sqlRows) {
Timestamp nextLower = sqlRow.getTimestamp("lowerBound");
Timestamp nextUpper = sqlRow.getTimestamp("upperBound");
if (previousUpper != null) {
assertThat(previousUpper).isEqualTo(nextLower);
}
previousUpper = nextUpper;
}
}
/**
* Use SqlQuery to query the history table directly.
*/
@@ -4,6 +4,7 @@ import io.ebean.BaseTestCase;
import org.junit.Test;
import org.tests.model.basic.Customer;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -26,6 +27,22 @@ public class TestBeanRepository extends BaseTestCase {
repository.update(fetchCustomer);
repository.delete(fetchCustomer);
List<Customer> custs = new ArrayList<>();
custs.add(newCustomer("c0"));
custs.add(newCustomer("c1"));
int count = repository.saveAll(custs);
assertThat(count).isEqualTo(2);
count = repository.deleteAll(custs);
assertThat(count).isEqualTo(2);
}
private Customer newCustomer(String name) {
Customer customer = new Customer();
customer.setName(name);
return customer;
}
@Test
@@ -0,0 +1,238 @@
package org.tests.transaction;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Transaction;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tests.model.basic.EBasic;
import static org.assertj.core.api.Assertions.assertThat;
public class TestNestedTransaction extends BaseTestCase {
private static final Logger log = LoggerFactory.getLogger(TestNestedTransaction.class);
private EBasic bean;
@Before
public void init() {
bean = new EBasic("new");
Ebean.save(bean);
}
private void assertClean() {
EBasic myBean = Ebean.find(EBasic.class, bean.getId());
assertThat(myBean.getName()).isEqualTo("new");
}
private void assertModified() {
EBasic myBean = Ebean.find(EBasic.class, bean.getId());
assertThat(myBean.getName()).isEqualTo("modified");
}
private void modify() {
bean.setName("modified");
Ebean.save(bean);
}
// ===== level 0 =======
@Test
public void testNested_0() {
try (Transaction txn0 = Ebean.beginTransaction()) {
modify();
// no commit
}
assertClean();
}
@Test
public void testNested_1() {
try (Transaction txn0 = Ebean.beginTransaction()) {
modify();
txn0.commit();
}
assertModified();
}
// ===== level 1 =======
@Test
public void testNested_00() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
modify();
// no commit
}
// no commit
}
assertClean();
}
@Test
public void testNested_01() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
modify();
// no commit
}
attemptCommit(txn0);
}
assertClean();
}
private void attemptCommit(Transaction txn) {
try {
txn.commit();
} catch (IllegalStateException e) {
// expected
log.info("Expected IllegalStateException as transaction already rolled back " + e.getMessage());
}
}
@Test
public void testNested_10() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
modify();
txn1.commit();
}
// no commit
}
assertClean();
}
@Test
public void testNested_11() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
modify();
txn1.commit();
}
txn0.commit();
}
assertModified();
}
// ===== level 2 =======
@Test
public void testNested_000() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
// no commit
}
// no commit
}
// no commit
}
assertClean();
}
@Test
public void testNested_001() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
// no commit
}
// no commit
}
attemptCommit(txn0);
}
assertClean();
}
@Test
public void testNested_010() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
// no commit
}
txn1.commit();
}
// no commit
}
assertClean();
}
@Test
public void testNested_011() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
// no commit
}
txn1.commit();
}
attemptCommit(txn0);
}
assertClean();
}
@Test
public void testNested_100() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
txn2.commit();
}
// no commit
}
// no commit
}
assertClean();
}
@Test
public void testNested_101() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
txn2.commit();
}
// no commit
}
attemptCommit(txn0);
}
assertClean();
}
@Test
public void testNested_110() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
txn2.commit();
}
txn1.commit();
}
// no commit
}
assertClean();
}
@Test
public void testNested_111() {
try (Transaction txn0 = Ebean.beginTransaction()) {
try (Transaction txn1 = Ebean.beginTransaction()) {
try (Transaction txn2 = Ebean.beginTransaction()) {
modify();
txn2.commit();
}
txn1.commit();
}
txn0.commit();
}
assertModified();
}
}
@@ -2,18 +2,107 @@ package org.tests.types;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.tests.model.types.SomeFileBean;
import io.ebean.Transaction;
import org.junit.Test;
import org.tests.model.types.SomeFileBean;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class TestFileType extends BaseTestCase {
File file = getFile("/profile-image.jpg");
File file2 = getFile("/java-64.png");
private File file = getFile("/profile-image.jpg");
private File file2 = getFile("/java-64.png");
private File newTempFile() throws IOException {
File tempFile = File.createTempFile("testfile", "txt");
try (PrintStream ps = new PrintStream(tempFile)) {
ps.println("Hello World!");
}
return tempFile;
}
@Test
public void test_closeFileStreamUnbatched() throws IOException {
File tempFile = newTempFile();
SomeFileBean bean0 = new SomeFileBean();
bean0.setName("tempBeanUnbatched");
bean0.setContent(tempFile);
Ebean.save(bean0);
assertTrue(tempFile.delete());
}
@Test
public void test_closeFileStreamUnbatched_onUpdate() throws IOException {
SomeFileBean bean0 = new SomeFileBean();
bean0.setName("tempBeanUnbatched");
bean0.setContent(newTempFile());
Ebean.save(bean0);
File updateFile = newTempFile();
bean0.setName("tempBeanModified");
bean0.setContent(updateFile);
Ebean.save(bean0);
assertTrue(updateFile.delete());
}
@Test
public void test_closeFileStreamBatched() throws IOException {
SomeFileBean bean0 = new SomeFileBean();
bean0.setName("tempBeanUnbatched");
bean0.setContent(newTempFile());
Ebean.save(bean0);
File tempFile = newTempFile();
try (Transaction txn = Ebean.beginTransaction()) {
txn.setBatchSize(30);
txn.setBatchMode(true);
bean0.setName("tempBeanBatchedModified");
bean0.setContent(tempFile);
Ebean.save(bean0);
txn.commit();
}
assertTrue(tempFile.delete());
}
@Test
public void test_closeFileStreamBatched_update() throws IOException {
File tempFile = newTempFile();
try (Transaction txn = Ebean.beginTransaction()) {
txn.setBatchSize(30);
txn.setBatchMode(true);
SomeFileBean bean0 = new SomeFileBean();
bean0.setName("tempBeanBatched");
bean0.setContent(tempFile);
Ebean.save(bean0);
txn.commit();
}
assertTrue(tempFile.delete());
}
@Test
public void test_insertNullFile() {
@@ -0,0 +1,17 @@
-- Migrationscripts for ebean unittest DbMigrationDropHistoryTest
-- apply changes
create table migtest_e_history7 (
id integer auto_increment not null,
constraint pk_migtest_e_history7 primary key (id)
);
alter table migtest_e_history7 add column sys_period_start datetime(6) default now(6);
alter table migtest_e_history7 add column sys_period_end datetime(6);
create table migtest_e_history7_history(
id integer,
sys_period_start datetime(6),
sys_period_end datetime(6)
);
create view migtest_e_history7_with_history as select * from migtest_e_history7 union all select * from migtest_e_history7_history;
create trigger migtest_e_history7_history_upd before update,delete on migtest_e_history7 for each row call "io.ebean.config.dbplatform.h2.H2HistoryTrigger";
@@ -0,0 +1,10 @@
-- Migrationscripts for ebean unittest DbMigrationDropHistoryTest
-- drop dependencies
drop trigger migtest_e_history7_history_upd;
drop view migtest_e_history7_with_history;
alter table migtest_e_history7 drop column sys_period_start;
alter table migtest_e_history7 drop column sys_period_end;
drop table migtest_e_history7_history;
-- apply changes
@@ -0,0 +1,3 @@
-- h2 and postgres script
@@ -0,0 +1,8 @@
create or replace view order_agg_vw as
select d.order_id, sum(d.order_qty * d.unit_price) as order_total,
sum(d.ship_qty * d.unit_price) as ship_total
from o_order_detail d
group by d.order_id
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<createTable name="migtest_e_history7" withHistory="true" pkName="pk_migtest_e_history7">
<column name="id" type="integer" primaryKey="true"/>
</createTable>
</changeSet>
</migration>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="pendingDrops">
<dropHistoryTable baseTable="migtest_e_history7"/>
</changeSet>
</migration>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply" dropsFor="1.1">
<dropHistoryTable baseTable="migtest_e_history7"/>
</changeSet>
</migration>
@@ -184,13 +184,18 @@ create table migtest_e_history6_history(like migtest_e_history6);
create view migtest_e_history6_with_history as select * from migtest_e_history6 union all select * from migtest_e_history6_history;
create or replace function migtest_e_history2_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2);
return old;
end if;
end;
@@ -201,13 +206,18 @@ create trigger migtest_e_history2_history_upd
for each row execute procedure migtest_e_history2_history_version();
create or replace function migtest_e_history3_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
return old;
end if;
end;
@@ -218,13 +228,18 @@ create trigger migtest_e_history3_history_upd
for each row execute procedure migtest_e_history3_history_version();
create or replace function migtest_e_history4_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
return old;
end if;
end;
@@ -235,13 +250,18 @@ create trigger migtest_e_history4_history_upd
for each row execute procedure migtest_e_history4_history_version();
create or replace function migtest_e_history5_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
return old;
end if;
end;
@@ -252,13 +272,18 @@ create trigger migtest_e_history5_history_upd
for each row execute procedure migtest_e_history5_history_version();
create or replace function migtest_e_history6_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history6_history (sys_period,id, test_number1, test_number2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number1, OLD.test_number2);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history6_history (sys_period,id, test_number1, test_number2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number1, OLD.test_number2);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history6_history (sys_period,id, test_number1, test_number2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number1, OLD.test_number2);
insert into migtest_e_history6_history (sys_period,id, test_number1, test_number2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number1, OLD.test_number2);
return old;
end if;
end;
@@ -131,13 +131,18 @@ create view migtest_e_history4_with_history as select * from migtest_e_history4
create view migtest_e_history5_with_history as select * from migtest_e_history5 union all select * from migtest_e_history5_history;
create or replace function migtest_e_history_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
insert into migtest_e_history_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
return old;
end if;
end;
@@ -149,13 +154,18 @@ create trigger migtest_e_history_history_upd
-- changes: [add test_string2, add test_string3]
create or replace function migtest_e_history2_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
return old;
end if;
end;
@@ -163,13 +173,18 @@ $$ LANGUAGE plpgsql;
-- changes: [exclude test_string]
create or replace function migtest_e_history3_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history3_history (sys_period,id) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history3_history (sys_period,id) values (tstzrange(lowerTs,upperTs), OLD.id);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history3_history (sys_period,id) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id);
insert into migtest_e_history3_history (sys_period,id) values (tstzrange(lowerTs,upperTs), OLD.id);
return old;
end if;
end;
@@ -177,13 +192,18 @@ $$ LANGUAGE plpgsql;
-- changes: [alter test_number]
create or replace function migtest_e_history4_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
return old;
end if;
end;
@@ -191,13 +211,18 @@ $$ LANGUAGE plpgsql;
-- changes: [add test_boolean]
create or replace function migtest_e_history5_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history5_history (sys_period,id, test_number, test_boolean) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number, OLD.test_boolean);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history5_history (sys_period,id, test_number, test_boolean) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number, OLD.test_boolean);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history5_history (sys_period,id, test_number, test_boolean) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number, OLD.test_boolean);
insert into migtest_e_history5_history (sys_period,id, test_number, test_boolean) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number, OLD.test_boolean);
return old;
end if;
end;
@@ -21,13 +21,18 @@ create view migtest_e_history2_with_history as select * from migtest_e_history2
-- changes: [drop obsolete_string1, drop obsolete_string2]
create or replace function migtest_e_history2_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.test_string3);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.test_string3);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.test_string3);
insert into migtest_e_history2_history (sys_period,id, test_string, test_string3) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.test_string3);
return old;
end if;
end;
@@ -74,13 +74,18 @@ create view migtest_e_history4_with_history as select * from migtest_e_history4
-- changes: [add obsolete_string1, add obsolete_string2]
create or replace function migtest_e_history2_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2, test_string2, test_string3) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2, OLD.test_string2, OLD.test_string3);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2, test_string2, test_string3) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2, OLD.test_string2, OLD.test_string3);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2, test_string2, test_string3) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2, OLD.test_string2, OLD.test_string3);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2, test_string2, test_string3) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2, OLD.test_string2, OLD.test_string3);
return old;
end if;
end;
@@ -88,13 +93,18 @@ $$ LANGUAGE plpgsql;
-- changes: [include test_string]
create or replace function migtest_e_history3_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string);
insert into migtest_e_history3_history (sys_period,id, test_string) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string);
return old;
end if;
end;
@@ -102,13 +112,18 @@ $$ LANGUAGE plpgsql;
-- changes: [alter test_number]
create or replace function migtest_e_history4_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
insert into migtest_e_history4_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
return old;
end if;
end;
@@ -50,13 +50,18 @@ create view migtest_e_history5_with_history as select * from migtest_e_history5
-- changes: [drop test_string2, drop test_string3]
create or replace function migtest_e_history2_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_string, OLD.obsolete_string2);
insert into migtest_e_history2_history (sys_period,id, test_string, obsolete_string2) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_string, OLD.obsolete_string2);
return old;
end if;
end;
@@ -64,13 +69,18 @@ $$ LANGUAGE plpgsql;
-- changes: [drop test_boolean]
create or replace function migtest_e_history5_history_version() returns trigger as $$
declare
lowerTs timestamptz;
upperTs timestamptz;
begin
lowerTs = lower(OLD.sys_period);
upperTs = greatest(lowerTs + '1 microsecond',current_timestamp);
if (TG_OP = 'UPDATE') then
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(current_timestamp,null);
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
NEW.sys_period = tstzrange(upperTs,null);
return new;
elsif (TG_OP = 'DELETE') then
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.test_number);
insert into migtest_e_history5_history (sys_period,id, test_number) values (tstzrange(lowerTs,upperTs), OLD.id, OLD.test_number);
return old;
end if;
end;
+12
View File
@@ -171,3 +171,15 @@ ebean.migrationtest.migration.appName=migrationtest
ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest
ebean.migrationtest.migration.strict=true
# parameters for migration test
datasource.migrationtest-history.username=SA
datasource.migrationtest-history.password=SA
datasource.migrationtest-history.databaseUrl=jdbc:h2:mem:migration
datasource.migrationtest-history.databaseDriver=org.h2.Driver
ebean.migrationtest-history.applyPrefix=V
ebean.migrationtest-history.ddl.generate=false
ebean.migrationtest-history.ddl.run=false
ebean.migrationtest-history.ddl.header=-- Migrationscripts for ebean unittest DbMigrationDropHistoryTest
ebean.migrationtest-history.migration.appName=migrationtest-history
ebean.migrationtest-history.migration.migrationPath=dbmigration/migrationtest-history
ebean.migrationtest-history.migration.strict=true