mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
82
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef8d9c7eb0 | ||
|
|
a464c763d0 | ||
|
|
d4d1e571d3 | ||
|
|
92e85e32a2 | ||
|
|
ff1b01e5ca | ||
|
|
327f25c568 | ||
|
|
00a1324c52 | ||
|
|
75b9df942c | ||
|
|
946b390037 | ||
|
|
3a1e1e23f5 | ||
|
|
d9ea465102 | ||
|
|
3bc7f061eb | ||
|
|
0bc07d38b2 | ||
|
|
79f6d6d0f0 | ||
|
|
782e41098d | ||
|
|
0225fddf6d | ||
|
|
be3e08018e | ||
|
|
c9204eed3f | ||
|
|
edb6a0ebe2 | ||
|
|
826b507b77 | ||
|
|
8ad8f47c6b | ||
|
|
5944777a13 | ||
|
|
05a1b0d64e | ||
|
|
4d62958645 | ||
|
|
610a8b2df6 | ||
|
|
5b8bb41598 | ||
|
|
9e16d955ae | ||
|
|
197bb0509a | ||
|
|
5536aeb829 | ||
|
|
d629fb2dbd | ||
|
|
10c01574d2 | ||
|
|
cfad20c8e1 | ||
|
|
0ea375b4fc | ||
|
|
71fce1b4c5 | ||
|
|
db60065389 | ||
|
|
d3a765a532 | ||
|
|
fd4be0ca59 | ||
|
|
267a81b792 | ||
|
|
1615beadd1 | ||
|
|
a3e5c3de72 | ||
|
|
267b1b7303 | ||
|
|
c902caed24 | ||
|
|
662666e1a4 | ||
|
|
394f245e33 | ||
|
|
89da952b15 | ||
|
|
d927b8c2c2 | ||
|
|
6867c4568c | ||
|
|
e0e572a8b4 | ||
|
|
3c7555de36 | ||
|
|
75662aac5c | ||
|
|
e4ddcbd40a | ||
|
|
a8f390c3b7 | ||
|
|
f1b196cf2e | ||
|
|
04675ea76b | ||
|
|
8e44ad71e8 | ||
|
|
febd56c9c0 | ||
|
|
0d3649853a | ||
|
|
beed67567a | ||
|
|
0fe0803374 | ||
|
|
5fd7aca3d9 | ||
|
|
348fecddf7 | ||
|
|
b333449d84 | ||
|
|
87a97c2889 | ||
|
|
790147e42d | ||
|
|
3a93abaa7f | ||
|
|
1049d951d9 | ||
|
|
c3bdac5271 | ||
|
|
9bcba0b80d | ||
|
|
1529a2f12b | ||
|
|
b41b6da40e | ||
|
|
4285cbaeb2 | ||
|
|
26fd7c5498 | ||
|
|
6ec4e4b965 | ||
|
|
e3a20a351d | ||
|
|
9b8f7be98f | ||
|
|
61f5442e3b | ||
|
|
c5acd31da4 | ||
|
|
49fde7654e | ||
|
|
05338531ed | ||
|
|
eb4d906814 | ||
|
|
f571da5154 | ||
|
|
b88e4a35f8 |
@@ -0,0 +1,39 @@
|
||||
|
||||
name: JDK EA
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '39 6 * * 1,3,5'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
java_version: [17,18,19,loom,valhalla,metropolis,panama]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Java
|
||||
uses: oracle-actions/setup-java@v1
|
||||
with:
|
||||
website: jdk.java.net
|
||||
release: ${{ matrix.java_version }}
|
||||
- name: Maven cache
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: maven-cache
|
||||
with:
|
||||
path:
|
||||
~/.m2
|
||||
key: build-${{ env.cache-name }}
|
||||
- name: Build with Maven
|
||||
run: mvn package
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
@@ -106,7 +106,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -829,7 +829,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
/**
|
||||
* Load the bean when it is a reference.
|
||||
*/
|
||||
protected void loadBean(int loadProperty) {
|
||||
void loadBean(int loadProperty) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (beanLoader == null) {
|
||||
@@ -886,7 +886,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Helper method to check if two objects are equal.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
protected static boolean notEqual(Object obj1, Object obj2) {
|
||||
static boolean notEqual(Object obj1, Object obj2) {
|
||||
if (obj1 == null) {
|
||||
return (obj2 != null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* BackgroundExecutorWrapper that can be used to wrap tasks that are sent to background (i.e. another thread).
|
||||
* It should copy all necessary thread-local variables. See {@link MdcBackgroundExecutorWrapper} for implementation details.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public interface BackgroundExecutorWrapper {
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
<T> Callable<T> wrap(Callable<T> task);
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
Runnable wrap(Runnable task);
|
||||
|
||||
/**
|
||||
* Combines two wrappers by nesting them.
|
||||
*/
|
||||
default BackgroundExecutorWrapper with(BackgroundExecutorWrapper inner) {
|
||||
return new BackgroundExecutorWrapper() {
|
||||
|
||||
@Override
|
||||
public Runnable wrap(Runnable task) {
|
||||
return BackgroundExecutorWrapper.this.wrap(inner.wrap(task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Callable<T> wrap(Callable<T> task) {
|
||||
return BackgroundExecutorWrapper.this.wrap(inner.wrap(task));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -445,6 +445,7 @@ public class DatabaseConfig {
|
||||
|
||||
private int backgroundExecutorSchedulePoolSize = 1;
|
||||
private int backgroundExecutorShutdownSecs = 30;
|
||||
private BackgroundExecutorWrapper backgroundExecutorWrapper = new MdcBackgroundExecutorWrapper();
|
||||
|
||||
// defaults for the L2 bean caching
|
||||
|
||||
@@ -1463,6 +1464,20 @@ public class DatabaseConfig {
|
||||
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the background executor wrapper.
|
||||
*/
|
||||
public BackgroundExecutorWrapper getBackgroundExecutorWrapper() {
|
||||
return backgroundExecutorWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background executor wrapper. The wrapper is used when a task is sent to background and should copy the thread-locals.
|
||||
*/
|
||||
public void setBackgroundExecutorWrapper(BackgroundExecutorWrapper backgroundExecutorWrapper) {
|
||||
this.backgroundExecutorWrapper = backgroundExecutorWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max size.
|
||||
*/
|
||||
@@ -2884,6 +2899,7 @@ public class DatabaseConfig {
|
||||
|
||||
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
|
||||
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
|
||||
backgroundExecutorWrapper = p.createInstance(BackgroundExecutorWrapper.class, "backgroundExecutorWrapper", backgroundExecutorWrapper);
|
||||
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
|
||||
currentUserProvider = p.createInstance(CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
|
||||
databasePlatform = p.createInstance(DatabasePlatform.class, "databasePlatform", databasePlatform);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Propagates MDC context for tasks executed in the background.
|
||||
*/
|
||||
public final class MdcBackgroundExecutorWrapper implements BackgroundExecutorWrapper {
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
@Override
|
||||
public <T> Callable<T> wrap(Callable<T> task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return task.call();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
@Override
|
||||
public Runnable wrap(Runnable task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
//this.exceptionTranslator =
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.dbDefaultValue.setFalse("0");
|
||||
this.dbDefaultValue.setTrue("1");
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
|
||||
@@ -36,6 +36,7 @@ public abstract class BaseDB2Platform extends DatabasePlatform {
|
||||
.addDataIntegrity("23502","23503","23504","23511","23512","23511","42917","23515")
|
||||
.build();
|
||||
|
||||
historySupport = new DB2HistorySupport();
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint", false));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.ebean.config.dbplatform.db2;
|
||||
|
||||
import io.ebean.config.dbplatform.DbStandardHistorySupport;
|
||||
|
||||
/**
|
||||
* DB2 based history support.
|
||||
*/
|
||||
public class DB2HistorySupport extends DbStandardHistorySupport {
|
||||
|
||||
@Override
|
||||
public String getAsOfViewSuffix(String asOfViewSuffix) {
|
||||
return " for system_time as of ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
|
||||
return " for system_time between ? and ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_start";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_end";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.15.1</tag>
|
||||
<tag>ebean-parent-12.16.0</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
@@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+15
-15
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -71,88 +71,88 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+8
-8
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.15.1</tag>
|
||||
<tag>ebean-parent-12.16.0</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-runner</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>${ebean-ddl-runner.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -35,25 +35,25 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration-auto</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>${ebean-migration-auto.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -152,7 +152,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A buffer of beans for batch lazy loading and secondary query loading.
|
||||
@@ -13,7 +13,7 @@ public interface LoadBeanBuffer {
|
||||
|
||||
int batchSize();
|
||||
|
||||
List<EntityBeanIntercept> batch();
|
||||
Set<EntityBeanIntercept> batch();
|
||||
|
||||
BeanDescriptor<?> descriptor();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Set;
|
||||
*/
|
||||
public final class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
private final Set<EntityBeanIntercept> batch;
|
||||
private final LoadBeanBuffer loadBuffer;
|
||||
private final String lazyLoadProperty;
|
||||
private final boolean loadCache;
|
||||
@@ -58,7 +58,7 @@ public final class LoadBeanRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the batch of beans to actually load.
|
||||
*/
|
||||
public List<EntityBeanIntercept> batch() {
|
||||
public Set<EntityBeanIntercept> batch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,9 @@ final class DScriptRunner implements ScriptRunner {
|
||||
try (Connection connection = obtainConnection()) {
|
||||
DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName);
|
||||
runner.runAll(content, connection);
|
||||
connection.commit();
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
}
|
||||
runner.runNonTransactional(connection);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
@@ -17,6 +16,7 @@ import org.slf4j.Logger;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper to handle lazy loading and refreshing of beans.
|
||||
@@ -39,14 +39,14 @@ final class DefaultBeanLoader {
|
||||
}
|
||||
|
||||
void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
loadManyInternal(bc.getOwnerBean(), bc.getPropertyName(), null, false, onlyIds);
|
||||
loadManyInternal(bc.getOwnerBean(), bc.getPropertyName(), false, onlyIds);
|
||||
}
|
||||
|
||||
void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
loadManyInternal(parentBean, propertyName, null, true, false);
|
||||
loadManyInternal(parentBean, propertyName, true, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, boolean onlyIds) {
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, boolean refresh, boolean onlyIds) {
|
||||
EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
BeanDescriptor<?> parentDesc = server.descriptor(parentBean.getClass());
|
||||
@@ -105,7 +105,7 @@ final class DefaultBeanLoader {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
server.findOne(query, t);
|
||||
server.findOne(query, null);
|
||||
if (beanCollection != null) {
|
||||
if (beanCollection.checkEmptyLazyLoad()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -121,7 +121,7 @@ final class DefaultBeanLoader {
|
||||
* Load a batch of beans for +query or +lazy loading.
|
||||
*/
|
||||
void loadBean(LoadBeanRequest loadRequest) {
|
||||
List<EntityBeanIntercept> batch = loadRequest.batch();
|
||||
Set<EntityBeanIntercept> batch = loadRequest.batch();
|
||||
if (batch.isEmpty()) {
|
||||
throw new RuntimeException("Nothing in batch?");
|
||||
}
|
||||
@@ -199,7 +199,7 @@ final class DefaultBeanLoader {
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
if (draft) {
|
||||
query.asDraft();
|
||||
} else {
|
||||
} else if (mode == SpiQuery.Mode.LAZYLOAD_BEAN) {
|
||||
query.setIncludeSoftDeletes();
|
||||
}
|
||||
if (embeddedOwnerIndex > -1) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.config.BackgroundExecutorWrapper;
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.DatabaseConfigProvider;
|
||||
@@ -67,7 +68,8 @@ public final class DefaultContainer implements SpiContainer {
|
||||
String namePrefix = "ebean-" + config.getName();
|
||||
int schedulePoolSize = config.getBackgroundExecutorSchedulePoolSize();
|
||||
int shutdownSecs = config.getBackgroundExecutorShutdownSecs();
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix);
|
||||
BackgroundExecutorWrapper wrapper = config.getBackgroundExecutorWrapper();
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -373,7 +373,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
migrationRunner.setDefaultDbSchema(dbSchema);
|
||||
}
|
||||
migrationRunner.setName(config.getName());
|
||||
migrationRunner.setPlatform(config.getDatabasePlatform().getPlatform().base().name().toLowerCase());
|
||||
Platform platform = config.getDatabasePlatform().getPlatform();
|
||||
migrationRunner.setBasePlatform(platform.base().name().toLowerCase());
|
||||
migrationRunner.setPlatform(platform.name().toLowerCase());
|
||||
migrationRunner.loadProperties(config.getProperties());
|
||||
migrationRunner.run(config.getDataSource());
|
||||
}
|
||||
|
||||
+20
-2
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.query.SqlTreeJoin;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -60,11 +61,28 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
|
||||
return ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
// add join to support the discriminator column
|
||||
String relativePrefix = ctx.getRelativePrefix(property.name);
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
ctx.addExtraJoin(new Extra(relativePrefix, joinType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra join to support the discriminator column.
|
||||
*/
|
||||
final class Extra implements SqlTreeJoin {
|
||||
final String relativePrefix;
|
||||
final SqlJoinType joinType;
|
||||
Extra(String relativePrefix, SqlJoinType joinType) {
|
||||
this.relativePrefix = relativePrefix;
|
||||
this.joinType = joinType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addJoin(DbSqlContext ctx) {
|
||||
// add join to support the discriminator column *IF* join is not already present
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1310,8 +1310,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
||||
* Hit the bean cache trying to load a list/batch of entities.
|
||||
* Return the set of entities that were successfully loaded from L2 cache.
|
||||
*/
|
||||
public Set<EntityBeanIntercept> cacheBeanLoadAll(List<EntityBeanIntercept> list, PersistenceContext persistenceContext, int lazyLoadProperty, String propertyName) {
|
||||
return cacheHelp.beanCacheLoadAll(list, persistenceContext, lazyLoadProperty, propertyName);
|
||||
public Set<EntityBeanIntercept> cacheBeanLoadAll(Set<EntityBeanIntercept> batch, PersistenceContext persistenceContext, int lazyLoadProperty, String propertyName) {
|
||||
return cacheHelp.beanCacheLoadAll(batch, persistenceContext, lazyLoadProperty, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-3
@@ -693,9 +693,9 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
/**
|
||||
* Load a batch of entities from L2 bean cache checking the lazy loaded property is loaded.
|
||||
*/
|
||||
Set<EntityBeanIntercept> beanCacheLoadAll(List<EntityBeanIntercept> list, PersistenceContext context, int lazyLoadProperty, String propertyName) {
|
||||
Set<EntityBeanIntercept> beanCacheLoadAll(Set<EntityBeanIntercept> batch, PersistenceContext context, int lazyLoadProperty, String propertyName) {
|
||||
Map<Object, EntityBeanIntercept> ebis = new HashMap<>();
|
||||
for (EntityBeanIntercept ebi : list) {
|
||||
for (EntityBeanIntercept ebi : batch) {
|
||||
ebis.put(desc.cacheKeyForBean(ebi.getOwner()), ebi);
|
||||
}
|
||||
|
||||
@@ -716,7 +716,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
|
||||
}
|
||||
iterator.remove();
|
||||
} else {
|
||||
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
|
||||
loaded.add(ebi);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.query.SqlTreeJoin;
|
||||
|
||||
/**
|
||||
* Used to provide context during sql construction.
|
||||
@@ -133,4 +134,13 @@ public interface DbSqlContext {
|
||||
*/
|
||||
void appendFromForUpdate();
|
||||
|
||||
/**
|
||||
* Delay adding an extra join to support inheritance discriminator in projection (IF required).
|
||||
*/
|
||||
void addExtraJoin(SqlTreeJoin treeJoin);
|
||||
|
||||
/**
|
||||
* Add extra joins *IF* required to support inheritance discriminator in projection.
|
||||
*/
|
||||
void flushExtraJoins();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A "CachedThreadPool" based on Daemon threads.
|
||||
* <p>
|
||||
* The Threads are created as needed and once idle live for 60 seconds.
|
||||
*/
|
||||
final class DaemonExecutorService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonExecutorService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final String namePrefix;
|
||||
private final int shutdownWaitSeconds;
|
||||
private final ExecutorService service;
|
||||
|
||||
DaemonExecutorService(int shutdownWaitSeconds, String namePrefix) {
|
||||
this.service = Executors.newCachedThreadPool(new DaemonThreadFactory(namePrefix));
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
<T> Future<T> submit(Callable<T> task) {
|
||||
return service.submit(task);
|
||||
}
|
||||
|
||||
Future<?> submit(Runnable task) {
|
||||
return service.submit(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still working.
|
||||
*/
|
||||
void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (service.isShutdown()) {
|
||||
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonExecutorService[{}] shutting down...", namePrefix);
|
||||
service.shutdown();
|
||||
if (!service.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonExecutorService[{}] shut down timeout exceeded. Terminating running threads.", namePrefix);
|
||||
service.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+69
-41
@@ -1,15 +1,13 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import io.avaje.lang.NonNullApi;
|
||||
import io.ebean.config.BackgroundExecutorWrapper;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
@@ -17,56 +15,81 @@ import java.util.concurrent.TimeUnit;
|
||||
@NonNullApi
|
||||
public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean.BackgroundExecutor");
|
||||
|
||||
private final ScheduledExecutorService schedulePool;
|
||||
private final DaemonExecutorService pool;
|
||||
private final BackgroundExecutorWrapper wrapper;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.executor = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix);
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix, BackgroundExecutorWrapper wrapper) {
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
|
||||
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
|
||||
this.wrapper = wrapper;
|
||||
log.debug("Created backgroundExecutor {} (schedulePoolSize={}, shutdownWaitSeconds={})", namePrefix, schedulePoolSize, shutdownWaitSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
<T> Callable<T> wrapMDC(Callable<T> task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
<T> Callable<T> wrap(Callable<T> task) {
|
||||
if (wrapper == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return task.call();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
return wrapper.wrap(task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
Runnable wrapMDC(Runnable task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
Runnable wrap(Runnable task) {
|
||||
if (wrapper == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return wrapper.wrap(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decorates a runnable by adding an exception handler and some timing metrics.
|
||||
* This is used in methods that accepts a <code>Runnable</code> and return
|
||||
* either <code>void</code> or <code>ScheduledFuture</code>, as there is
|
||||
* normally no Future.get() call.
|
||||
*
|
||||
* Note: When submitting a <code>Callable</code>, you must check
|
||||
* <code>Future.get()</code> for exceptions.
|
||||
*/
|
||||
private Runnable logExceptions(Runnable task) {
|
||||
long queued = System.nanoTime();
|
||||
log.trace("Queued {}", task);
|
||||
return () -> {
|
||||
try {
|
||||
if (log.isTraceEnabled()) {
|
||||
long start = System.nanoTime();
|
||||
log.trace("Start {} (delay time {} us)", task, (start - queued) / 1000L);
|
||||
task.run();
|
||||
log.trace("Stop {} (exec time {} us)", task, (System.nanoTime() - start) / 1000L);
|
||||
} else {
|
||||
task.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// log any exception here. Note they will not bubble up to the calling user
|
||||
// unless Future.get() is checked. (Which is almost never done on scheduled
|
||||
// background executions)
|
||||
log.error("Error while executing the task {}", task, t);
|
||||
throw t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
return executor.submit(wrapMDC(task));
|
||||
// Note: No "logExceptions" as we expect Future.get() by the invoker
|
||||
return pool.submit(wrap(task));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,47 +97,52 @@ public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
*/
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
return executor.submit(wrapMDC(task));
|
||||
return pool.submit(wrap(task));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
submit(task);
|
||||
submit(logExceptions(task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable task, long delay, TimeUnit unit) {
|
||||
executor.scheduleWithFixedDelay(wrapMDC(task), delay, delay, unit);
|
||||
schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), delay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
|
||||
schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
|
||||
return schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return executor.scheduleAtFixedRate(wrapMDC(task), initialDelay, delay, unit);
|
||||
return schedulePool.scheduleAtFixedRate(wrap(logExceptions(task)), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
|
||||
return executor.schedule(wrapMDC(task), delay, unit);
|
||||
return schedulePool.schedule(wrap(logExceptions(task)), delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
|
||||
return executor.schedule(wrapMDC(task), delay, unit);
|
||||
// Note: No "logExceptions" as we expect Future.get() by the invoker
|
||||
return schedulePool.schedule(wrap(task), delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
executor.shutdown();
|
||||
log.trace("BackgroundExecutor shutting down");
|
||||
schedulePool.shutdown();
|
||||
pool.shutdown();
|
||||
log.debug("BackgroundExecutor stopped");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-14
@@ -15,6 +15,7 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
@@ -66,7 +67,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
}
|
||||
}
|
||||
|
||||
protected void register(EntityBeanIntercept ebi) {
|
||||
void register(EntityBeanIntercept ebi) {
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(batchSize);
|
||||
}
|
||||
@@ -91,7 +92,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
try {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
if (!loadBuffer.batch.isEmpty()) {
|
||||
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
|
||||
}
|
||||
if (forEach) {
|
||||
@@ -115,13 +116,13 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
private final ReentrantLock bufferLock = new ReentrantLock();
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
private final Set<EntityBeanIntercept> batch;
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<>(batchSize);
|
||||
this.batch = new HashSet<>(Math.max((int) (batchSize/.75f) + 1, 16));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,7 +140,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return batchSize == list.size();
|
||||
return batchSize == batch.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,12 +151,12 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
// get persistenceContext from first loaded bean into the buffer
|
||||
persistenceContext = ebi.getPersistenceContext();
|
||||
}
|
||||
list.add(ebi);
|
||||
batch.add(ebi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityBeanIntercept> batch() {
|
||||
return list;
|
||||
public Set<EntityBeanIntercept> batch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,13 +191,13 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
// lazy load property was a Many
|
||||
return;
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
if (!batch.contains(ebi)) {
|
||||
// re-add to the batch and lazy load from DB skipping l2 cache
|
||||
list.add(ebi);
|
||||
batch.add(ebi);
|
||||
} else if (context.hitCache) {
|
||||
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(list, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
|
||||
list.removeAll(hits);
|
||||
if (list.isEmpty() || hits.contains(ebi)) {
|
||||
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(batch, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
|
||||
batch.removeAll(hits);
|
||||
if (batch.isEmpty() || hits.contains(ebi)) {
|
||||
// successfully hit the L2 cache so don't invoke DB lazy loading
|
||||
return;
|
||||
}
|
||||
@@ -204,7 +205,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
|
||||
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, ebi, context.hitCache);
|
||||
context.desc.ebeanServer().loadBean(req);
|
||||
list.clear();
|
||||
batch.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.util.ArrayStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
final class DefaultDbSqlContext implements DbSqlContext {
|
||||
|
||||
@@ -43,7 +44,9 @@ final class DefaultDbSqlContext implements DbSqlContext {
|
||||
|
||||
private String currentPrefix;
|
||||
|
||||
private ArrayList<BeanProperty> encryptedProps;
|
||||
private List<BeanProperty> encryptedProps;
|
||||
|
||||
private List<SqlTreeJoin> extraJoins;
|
||||
|
||||
private final CQueryDraftSupport draftSupport;
|
||||
|
||||
@@ -70,6 +73,24 @@ final class DefaultDbSqlContext implements DbSqlContext {
|
||||
return alias.isIncludeSoftDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExtraJoin(SqlTreeJoin treeJoin) {
|
||||
if (extraJoins == null) {
|
||||
extraJoins = new ArrayList<>();
|
||||
}
|
||||
extraJoins.add(treeJoin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushExtraJoins() {
|
||||
if (extraJoins != null) {
|
||||
for (SqlTreeJoin extra : extraJoins) {
|
||||
extra.addJoin(this);
|
||||
}
|
||||
extraJoins = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendFromForUpdate() {
|
||||
if (fromForUpdate != null) {
|
||||
|
||||
@@ -13,30 +13,22 @@ import java.util.Set;
|
||||
final class SqlTree {
|
||||
|
||||
private final SqlTreeNode rootNode;
|
||||
|
||||
/**
|
||||
* Property if resultSet contains master and detail rows.
|
||||
*/
|
||||
private final STreePropertyAssocMany manyProperty;
|
||||
|
||||
private final String distinctOn;
|
||||
|
||||
private final String selectSql;
|
||||
|
||||
private final String fromSql;
|
||||
|
||||
private final String groupBy;
|
||||
|
||||
/**
|
||||
* Encrypted Properties require additional binding.
|
||||
*/
|
||||
private final STreeProperty[] encryptedProps;
|
||||
|
||||
/**
|
||||
* Where clause for inheritance.
|
||||
*/
|
||||
private final String inheritanceWhereSql;
|
||||
|
||||
private final boolean noJoins;
|
||||
|
||||
/**
|
||||
@@ -44,7 +36,6 @@ final class SqlTree {
|
||||
*/
|
||||
SqlTree(SqlTreeNode rootNode, String distinctOn, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql,
|
||||
STreeProperty[] encryptedProps, STreePropertyAssocMany manyProperty, boolean includeJoins) {
|
||||
|
||||
this.rootNode = rootNode;
|
||||
this.distinctOn = distinctOn;
|
||||
this.selectSql = selectSql;
|
||||
|
||||
@@ -15,22 +15,14 @@ import java.util.TreeSet;
|
||||
final class SqlTreeAlias {
|
||||
|
||||
private final SpiQuery.TemporalMode temporalMode;
|
||||
|
||||
private int counter;
|
||||
|
||||
private int manyWhereCounter;
|
||||
|
||||
private final TreeSet<String> joinProps = new TreeSet<>();
|
||||
|
||||
private HashSet<String> embeddedPropertyJoins;
|
||||
|
||||
private final TreeSet<String> manyWhereJoinProps = new TreeSet<>();
|
||||
|
||||
private final HashMap<String, String> aliasMap = new HashMap<>();
|
||||
|
||||
private final HashMap<String, String> manyWhereAliasMap = new HashMap<>();
|
||||
|
||||
private final String rootTableAlias;
|
||||
private int counter;
|
||||
private int manyWhereCounter;
|
||||
|
||||
SqlTreeAlias(String rootTableAlias, SpiQuery.TemporalMode temporalMode) {
|
||||
this.rootTableAlias = rootTableAlias;
|
||||
|
||||
@@ -224,8 +224,7 @@ public final class SqlTreeBuilder {
|
||||
* Recursively build the query tree depending on what leaves in the tree
|
||||
* should be included.
|
||||
*/
|
||||
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
|
||||
STreeType desc, List<SqlTreeNode> joinList) {
|
||||
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> joinList) {
|
||||
List<SqlTreeNode> myJoinList = new ArrayList<>();
|
||||
List<STreePropertyAssocOne> extraProps = new ArrayList<>();
|
||||
for (STreePropertyAssocOne one : desc.propsOne()) {
|
||||
@@ -256,7 +255,7 @@ public final class SqlTreeBuilder {
|
||||
}
|
||||
addManyWhereJoins(myJoinList);
|
||||
}
|
||||
extraProps.forEach(props::add);
|
||||
extraProps.forEach(props::addExtra);
|
||||
|
||||
if (!rawSql && manyWhereJoins.isFormulaWithJoin(prefix)) {
|
||||
for (String property : manyWhereJoins.getFormulaJoinProperties(prefix)) {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
/**
|
||||
* Extra Sql joins conditionally added if required (after children are joined).
|
||||
*/
|
||||
public interface SqlTreeJoin {
|
||||
|
||||
/**
|
||||
* Add the extra join if required.
|
||||
*/
|
||||
void addJoin(DbSqlContext ctx);
|
||||
|
||||
}
|
||||
@@ -279,18 +279,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
ctx.pushTableAlias(prefix);
|
||||
|
||||
baseTableAlias = ctx.getTableAlias(prefix);
|
||||
|
||||
// join and return SqlJoinType to use for child joins
|
||||
joinType = appendFromBaseTable(ctx, joinType);
|
||||
|
||||
for (STreeProperty property : properties) {
|
||||
// usually nothing... except for 1-1 Exported
|
||||
property.appendFrom(ctx, joinType, null);
|
||||
}
|
||||
|
||||
for (SqlTreeNode child : children) {
|
||||
child.appendFrom(ctx, joinType);
|
||||
}
|
||||
ctx.flushExtraJoins();
|
||||
ctx.popTableAlias();
|
||||
ctx.popJoin();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ public final class SqlTreeProperties {
|
||||
propsList.addAll(Arrays.asList(props));
|
||||
}
|
||||
|
||||
public void addExtra(STreePropertyAssocOne prop) {
|
||||
if (!propsList.contains(prop)) {
|
||||
add(prop);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(STreeProperty prop) {
|
||||
propsList.add(prop);
|
||||
propNames.add(prop.name());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.core.type.DataBinder;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
@@ -18,6 +19,15 @@ class ScalarTypeClob extends ScalarTypeStringBase {
|
||||
super(true, Types.CLOB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBinder binder, String value) throws SQLException {
|
||||
if (value == null) {
|
||||
binder.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
binder.setClob(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read(DataReader reader) throws SQLException {
|
||||
return reader.getStringFromStream();
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DaemonExecutorServiceTest {
|
||||
|
||||
private final int count = 10;
|
||||
private final int waitMillis = 100;
|
||||
|
||||
@Test
|
||||
void submit() throws Exception {
|
||||
DaemonExecutorService des = new DaemonExecutorService(5, "junk");
|
||||
long start = System.currentTimeMillis();
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
futures.add(des.submit(this::doStuff));
|
||||
}
|
||||
for (Future<?> f: futures) {
|
||||
f.get();
|
||||
}
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
assertThat(exeMillis).isLessThan(count * waitMillis);
|
||||
des.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void submit_via_DefaultBackgroundExecutor() throws Exception {
|
||||
DefaultBackgroundExecutor des = new DefaultBackgroundExecutor(1, 5, "junk", null);
|
||||
long start = System.currentTimeMillis();
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
futures.add(des.submit(this::doStuff));
|
||||
}
|
||||
for (Future<?> f: futures) {
|
||||
f.get();
|
||||
}
|
||||
long exeMillis = System.currentTimeMillis() - start;
|
||||
assertThat(exeMillis).isLessThan(count * waitMillis);
|
||||
des.shutdown();
|
||||
}
|
||||
|
||||
private void doStuff() {
|
||||
try {
|
||||
Thread.sleep(waitMillis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean ddl generation</name>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-runner</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>${ebean-ddl-runner.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -28,14 +28,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Object that represents an Alter Table statements. Table alters are grouped together by tableName in DDL and can be extended by
|
||||
* a ddl-specific handler (e.g. doing a reorg for DB2 or implement special grouping for Hana). There is one instance per table.
|
||||
*
|
||||
* @author TODO Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public interface DdlAlterTable {
|
||||
|
||||
/**
|
||||
* Writes the alter table statements to <code>target</code>
|
||||
*/
|
||||
void write(Appendable target) throws IOException;
|
||||
|
||||
/**
|
||||
* Adds an alter table command for given column. When you invoke<br>
|
||||
* <code>alterTable(writer, "my_table").add("alter column","my_column).append("type integer")</code> the resulting DDL (in
|
||||
* standard implementation) would be<br>
|
||||
* <code>alter table my_table alter column my_column type integer</code>
|
||||
*
|
||||
* @return a DdlBuffer, which can be used for further appends. Note you MUST NOT call <code>.endOfStatement()</code> on this
|
||||
* buffer.
|
||||
*/
|
||||
DdlBuffer append(String operation, String columnName);
|
||||
|
||||
/**
|
||||
* Adds a raw command. This is mainly used for executing user stored procedures.
|
||||
*/
|
||||
DdlBuffer raw(String string);
|
||||
|
||||
/**
|
||||
* Flag that detects if history DDL (switching on) is handled for this table.
|
||||
*/
|
||||
boolean isHistoryHandled();
|
||||
|
||||
/**
|
||||
* Sets the history handled flag for this table.
|
||||
*/
|
||||
void setHistoryHandled();
|
||||
|
||||
|
||||
}
|
||||
+101
-21
@@ -1,12 +1,28 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.BaseDdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.model.MConfiguration;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import io.ebeaninternal.dbmigration.model.ModelContainer;
|
||||
|
||||
/**
|
||||
* Write context holding the buffers for both apply and rollback DDL.
|
||||
* Write context holding the buffers for both apply and rollback DDL. Description of the apply buffers:
|
||||
* <ul>
|
||||
* <li><b>applyDropDependencies:</b> Contains drops for foreign keys, indices, constraint or drop history table</li>
|
||||
* <li><b>apply:</b> Contains @DbMigraion.before, create table, create sequence or disable system versioning statements</li>
|
||||
* <li><b>applyAlterTables:</b> Contains table alters (only that change the table data structure, there may be table alters like
|
||||
* constraints etc. in postAlter)</li>
|
||||
* <li><b>applyPostAlter:</b> Contains check constraints, unique constraints (which CAN be an index), column and table comments,
|
||||
* @DbMigraion.after, drop tables, drop sequences or enable system versioning statement</li>
|
||||
* <li><b>applyForeignKeys: Contains foreign keys and indices.</b>
|
||||
* <li><b>applyHistoryView:</b> The views for trigger based history support</li>
|
||||
* <li><b>applyHistoryTrigger:</b> The triggers for trigger based history support</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class DdlWrite {
|
||||
|
||||
@@ -16,12 +32,12 @@ public class DdlWrite {
|
||||
|
||||
private final DdlBuffer apply = new BaseDdlBuffer();
|
||||
|
||||
private final Map<String, DdlAlterTable> applyAlterTables = new TreeMap<>();
|
||||
|
||||
private final DdlBuffer applyPostAlter = new BaseDdlBuffer();
|
||||
|
||||
private final DdlBuffer applyForeignKeys = new BaseDdlBuffer();
|
||||
|
||||
private final DdlBuffer applyHistoryView = new BaseDdlBuffer();
|
||||
|
||||
private final DdlBuffer applyHistoryTrigger = new BaseDdlBuffer();
|
||||
|
||||
private final DdlBuffer dropAllForeignKeys = new BaseDdlBuffer();
|
||||
|
||||
private final DdlBuffer dropAll = new BaseDdlBuffer();
|
||||
@@ -66,12 +82,19 @@ public class DdlWrite {
|
||||
*/
|
||||
public boolean isApplyEmpty() {
|
||||
return apply.getBuffer().isEmpty()
|
||||
&& applyAlterTables.isEmpty()
|
||||
&& applyPostAlter.getBuffer().isEmpty()
|
||||
&& applyForeignKeys.getBuffer().isEmpty()
|
||||
&& applyHistoryView.getBuffer().isEmpty()
|
||||
&& applyHistoryTrigger.getBuffer().isEmpty()
|
||||
&& applyDropDependencies.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that POST ALTER is written to.
|
||||
*/
|
||||
public DdlBuffer applyPostAlter() {
|
||||
return applyPostAlter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to.
|
||||
*/
|
||||
@@ -86,6 +109,20 @@ public class DdlWrite {
|
||||
return applyDropDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or returns the DdlAlterTable statement for <code>tablename</code>.
|
||||
*
|
||||
* Note: All alters on a particular table are sorted in natural order in the ddl script. This allows optimizing the alters by
|
||||
* merging them or doing a reorg table after altering is done.
|
||||
*
|
||||
* @param tableName the table name
|
||||
* @param factory the factory to construct a new object
|
||||
* @return
|
||||
*/
|
||||
public DdlAlterTable applyAlterTable(String tableName, Function<String, DdlAlterTable> factory) {
|
||||
return applyAlterTables.computeIfAbsent(tableName, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
|
||||
* <p>
|
||||
@@ -96,20 +133,6 @@ public class DdlWrite {
|
||||
return applyForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that apply history-view DDL is written to.
|
||||
*/
|
||||
public DdlBuffer applyHistoryView() {
|
||||
return applyHistoryView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that apply history-trigger DDL is written to.
|
||||
*/
|
||||
public DdlBuffer applyHistoryTrigger() {
|
||||
return applyHistoryTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer used for the 'drop all DDL' for dropping foreign keys and associated indexes.
|
||||
*/
|
||||
@@ -124,4 +147,61 @@ public class DdlWrite {
|
||||
return dropAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the apply ddl to the target.
|
||||
*/
|
||||
public void writeApply(Appendable target) throws IOException {
|
||||
if (!applyDropDependencies.isEmpty()) {
|
||||
target.append("-- drop dependencies\n");
|
||||
target.append(applyDropDependencies.getBuffer());
|
||||
}
|
||||
if (!apply.isEmpty()) {
|
||||
target.append("-- apply changes\n");
|
||||
target.append(apply.getBuffer());
|
||||
}
|
||||
if (!applyAlterTables.isEmpty()) {
|
||||
target.append("-- apply alter tables\n");
|
||||
for (DdlAlterTable alterTable : applyAlterTables.values()) {
|
||||
alterTable.write(target);
|
||||
}
|
||||
}
|
||||
if (!applyPostAlter.isEmpty()) {
|
||||
target.append("-- apply post alter\n");
|
||||
target.append(applyPostAlter.getBuffer());
|
||||
}
|
||||
if (!applyForeignKeys.isEmpty()) {
|
||||
target.append("-- foreign keys and indices\n");
|
||||
target.append(applyForeignKeys.getBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the drop all ddl to the target.
|
||||
*/
|
||||
public void writeDropAll(Appendable target) throws IOException {
|
||||
if (!dropAllForeignKeys.isEmpty()) {
|
||||
target.append("-- drop all foreign keys\n");
|
||||
target.append(dropAllForeignKeys.getBuffer());
|
||||
}
|
||||
if (!dropAll.isEmpty()) {
|
||||
target.append("-- drop all\n");
|
||||
target.append(dropAll.getBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all create statements. Mainly used for unit-tests
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
writeDropAll(sb);
|
||||
writeApply(sb);
|
||||
} catch (IOException e) {
|
||||
// can not happen
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+88
-46
@@ -1,13 +1,20 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -17,16 +24,13 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
|
||||
public AbstractHanaDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.addColumn = "add (";
|
||||
this.addColumnSuffix = ")";
|
||||
this.alterColumn = "alter (";
|
||||
this.alterColumnSuffix = ")";
|
||||
this.columnDropDefault = " default null";
|
||||
this.columnSetDefault = " default";
|
||||
this.columnSetNotnull = " not null";
|
||||
this.addColumn = "add";
|
||||
this.alterColumn = "alter";
|
||||
this.columnDropDefault = "default null";
|
||||
this.columnSetDefault = "default";
|
||||
this.columnSetNotnull = "not null";
|
||||
this.columnSetNull = " null";
|
||||
this.dropColumn = "drop (";
|
||||
this.dropColumnSuffix = ")";
|
||||
this.dropColumn = "drop";
|
||||
this.dropConstraintIfExists = "drop constraint ";
|
||||
this.dropIndexIfExists = "drop index ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
@@ -38,7 +42,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnBaseAttributes(AlterColumn alter) {
|
||||
public void alterColumn(DdlWrite writer, AlterColumn alter) {
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String currentType = alter.getCurrentType();
|
||||
@@ -51,49 +55,21 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
: (alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue());
|
||||
String defaultValueClause = (defaultValue == null || defaultValue.isEmpty()) ? "" : " default " + defaultValue;
|
||||
|
||||
DdlBuffer buffer = new BaseDdlBuffer();
|
||||
if (!isConvertible(currentType, type)) {
|
||||
// add an intermediate conversion if possible
|
||||
if (isNumberType(currentType)) {
|
||||
// numbers can always be converted to decimal
|
||||
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
|
||||
.append(" decimal ").append(notnullClause).append(alterColumnSuffix)
|
||||
.endOfStatement();
|
||||
alterTable(writer, tableName).append(alterColumn, columnName).append("decimal").append(notnullClause);
|
||||
|
||||
} else if (isStringType(currentType)) {
|
||||
// strings can always be converted to nclob
|
||||
// Note: we do not add default clause here to avoid error[SAP DBTech JDBC: [336]: invalid default value:
|
||||
// default value cannot be created on column of data type NCLOB
|
||||
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
|
||||
.append(" nclob").append(notnullClause).append(alterColumnSuffix)
|
||||
.endOfStatement();
|
||||
alterTable(writer, tableName).append(alterColumn, columnName).append("nclob").append(notnullClause);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
|
||||
.append(" ").append(type).append(defaultValueClause).append(notnullClause).append(alterColumnSuffix);
|
||||
|
||||
return buffer.getBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DdlHandler createDdlHandler(DatabaseConfig config) {
|
||||
return new HanaDdlHandler(config, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
return null;
|
||||
alterTable(writer, tableName).append(alterColumn, columnName).append(type).append(defaultValueClause).append(notnullClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -140,9 +116,8 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
* foreign keys. That's why we call a user stored procedure here
|
||||
*/
|
||||
@Override
|
||||
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) {
|
||||
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')")
|
||||
.endOfStatement();
|
||||
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
|
||||
alterTable(writer, tableName).raw("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,4 +191,71 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
return type != null
|
||||
&& (type.startsWith("varchar") || type.startsWith("nvarchar") || "clob".equals(type) || "nclob".equals(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
|
||||
return writer.applyAlterTable(tableName, HanaAlterTableWrite::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins alter table commands and add open/closing brackets for the alter statements
|
||||
*/
|
||||
private static class HanaAlterTableWrite extends BaseAlterTableWrite {
|
||||
|
||||
public HanaAlterTableWrite(String tableName) {
|
||||
super(tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
|
||||
List<AlterCmd> newCmds = new ArrayList<>();
|
||||
Map<String, List<AlterCmd>> batches = new LinkedHashMap<>();
|
||||
Set<String> columns = new HashSet<>();
|
||||
for (AlterCmd cmd : cmds) {
|
||||
switch (cmd.getOperation()) {
|
||||
case "add":
|
||||
case "alter":
|
||||
case "drop":
|
||||
if (cmd.getColumn() != null && !columns.add(cmd.getColumn())) {
|
||||
// column already seen
|
||||
flushBatches(newCmds, batches);
|
||||
columns.clear();
|
||||
}
|
||||
batches.computeIfAbsent(cmd.getOperation(), k -> new ArrayList<>()).add(cmd);
|
||||
break;
|
||||
default:
|
||||
flushBatches(newCmds, batches);
|
||||
columns.clear();
|
||||
newCmds.add(cmd);
|
||||
}
|
||||
}
|
||||
flushBatches(newCmds, batches);
|
||||
return newCmds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges add/alter/drop commands into one statement.
|
||||
*/
|
||||
private void flushBatches(List<AlterCmd> newCmds, Map<String, List<AlterCmd>> batches) {
|
||||
for (Entry<String, List<AlterCmd>> entry : batches.entrySet()) {
|
||||
AlterCmd raw = newRawCommand("alter table ").append(tableName()).append(" ")
|
||||
.append(entry.getKey()).append(" (");
|
||||
List<AlterCmd> cmds = entry.getValue();
|
||||
for (int i = 0; i < cmds.size(); i++) {
|
||||
AlterCmd cmd = cmds.get(i);
|
||||
if (i > 0) {
|
||||
raw.append(",\n ");
|
||||
}
|
||||
raw.append(cmd.getColumn());
|
||||
if (!cmd.getAlternation().isEmpty()) {
|
||||
raw.append(" ").append(cmd.getAlternation());
|
||||
}
|
||||
}
|
||||
raw.append(")");
|
||||
newCmds.add(raw);
|
||||
}
|
||||
batches.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
|
||||
/**
|
||||
* Contains alter statements per table.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public class BaseAlterTableWrite implements DdlAlterTable {
|
||||
|
||||
protected static final String RAW_OPERATION = "$RAW";
|
||||
|
||||
public class AlterCmd {
|
||||
// the command (e.g. "alter", "modify"
|
||||
private final String operation;
|
||||
// the affected column (note: each column can only be altered once on MariaDB)
|
||||
private final String column;
|
||||
|
||||
private final DdlBuffer alternationBuffer = new BaseDdlBuffer() {
|
||||
@Override
|
||||
public DdlBuffer endOfStatement() {
|
||||
throw new UnsupportedOperationException();
|
||||
};
|
||||
};
|
||||
|
||||
protected AlterCmd(String operation, String column) {
|
||||
this.operation = operation;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public AlterCmd append(String content) {
|
||||
alternationBuffer.append(content);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public String getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public String getAlternation() {
|
||||
return alternationBuffer.getBuffer();
|
||||
}
|
||||
|
||||
protected void write(Appendable target) throws IOException {
|
||||
if (operation.equals(RAW_OPERATION)) {
|
||||
// this is a raw command. e.g. an USP call. Must be done in the correct order
|
||||
// of all alter commands
|
||||
target.append(getAlternation());
|
||||
} else {
|
||||
target.append("alter table ").append(tableName).append(' ').append(operation);
|
||||
if (column != null) {
|
||||
target.append(' ').append(column);
|
||||
}
|
||||
if (!getAlternation().isEmpty()) {
|
||||
target.append(' ').append(getAlternation());
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
write(sb);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private final String tableName;
|
||||
|
||||
private List<AlterCmd> cmds = new ArrayList<>();
|
||||
|
||||
private boolean historyHandled;
|
||||
|
||||
public BaseAlterTableWrite(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String tableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
protected AlterCmd newRawCommand(String sql) {
|
||||
AlterCmd cmd = new AlterCmd(RAW_OPERATION, null);
|
||||
cmd.alternationBuffer.append(sql);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public AlterCmd newOperation(String operation, String column) {
|
||||
return new AlterCmd(operation, column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a statement. The statement is prefixed with "alter table TABLENAME" and may be batched, if platform supports this. The
|
||||
* returned StringBuilder can be used, to complete the statement
|
||||
*/
|
||||
@Override
|
||||
public DdlBuffer append(String operation, String column) {
|
||||
AlterCmd cmd = new AlterCmd(operation, column);
|
||||
cmds.add(cmd);
|
||||
return cmd.alternationBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DdlBuffer raw(String sql) {
|
||||
AlterCmd cmd = newRawCommand(sql);
|
||||
cmds.add(cmd);
|
||||
return cmd.alternationBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method can be overwritten to return a new list of commands. The given list must not be modified, but a new command list with
|
||||
* modified commands can be returned (e.g. to handle DB2 reorg or special syntax in Hana)
|
||||
*/
|
||||
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
|
||||
return cmds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the DDL to <code>target</code>.
|
||||
*/
|
||||
@Override
|
||||
public void write(Appendable target) throws IOException {
|
||||
for (AlterCmd cmd : postProcessCommands(Collections.unmodifiableList(cmds))) {
|
||||
cmd.write(target);
|
||||
target.append(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHistoryHandled() {
|
||||
return historyHandled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHistoryHandled() {
|
||||
historyHandled = true;
|
||||
}
|
||||
}
|
||||
+127
-160
@@ -11,7 +11,6 @@ import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.TableDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.IndexSet;
|
||||
import io.ebeaninternal.dbmigration.migration.AddColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.AddTableComment;
|
||||
@@ -34,9 +33,7 @@ import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.ebean.util.StringHelper.replace;
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
@@ -47,12 +44,6 @@ import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.s
|
||||
*/
|
||||
public class BaseTableDdl implements TableDdl {
|
||||
|
||||
enum HistorySupport {
|
||||
NONE,
|
||||
SQL2011,
|
||||
TRIGGER_BASED
|
||||
}
|
||||
|
||||
protected final DbConstraintNaming naming;
|
||||
|
||||
protected final NamingConvention namingConvention;
|
||||
@@ -68,15 +59,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected final List<UniqueConstraint> externalCompoundUnique = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Base tables that have associated history tables that need their triggers/functions regenerated as
|
||||
* columns have been added, removed, included or excluded.
|
||||
*/
|
||||
protected final Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<>();
|
||||
|
||||
private final boolean strictMode;
|
||||
|
||||
private final HistorySupport historySupport;
|
||||
private final boolean alterHistoryTables;
|
||||
|
||||
/**
|
||||
* Helper class that is used to execute the migration ddl before and after the migration action.
|
||||
@@ -127,29 +112,29 @@ public class BaseTableDdl implements TableDdl {
|
||||
after = getScriptsForPlatform(alter.getAfter());
|
||||
}
|
||||
|
||||
void writeBefore(DdlBuffer buffer) {
|
||||
void write(DdlWrite writer) {
|
||||
if (!before.isEmpty()) {
|
||||
buffer.end();
|
||||
}
|
||||
|
||||
if (!before.isEmpty() && withHistory) {
|
||||
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
|
||||
}
|
||||
for (String ddlScript : before) {
|
||||
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
|
||||
}
|
||||
}
|
||||
|
||||
void writeAfter(DdlBuffer buffer) {
|
||||
if (!after.isEmpty() && withHistory) {
|
||||
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
|
||||
}
|
||||
// here we run post migration scripts
|
||||
for (String ddlScript : after) {
|
||||
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
|
||||
writer.apply().end();
|
||||
if (withHistory) {
|
||||
writer.apply().append("-- NOTE: table has @History - special migration may be necessary").newLine();
|
||||
}
|
||||
for (String ddlScript : before) {
|
||||
writer.apply().appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
|
||||
}
|
||||
}
|
||||
// effective order in DDL.sql:
|
||||
// 'before' goes to apply-buffer
|
||||
// altered columns will be in the alterTable buffers.
|
||||
// 'after' goes to the post-alter-buffer
|
||||
if (!after.isEmpty()) {
|
||||
buffer.end();
|
||||
writer.applyPostAlter().append("-- NOTE: table has @History - special migration may be necessary").newLine();
|
||||
|
||||
// here we run post migration scripts
|
||||
for (String ddlScript : after) {
|
||||
writer.applyPostAlter().appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
|
||||
}
|
||||
|
||||
writer.applyPostAlter().end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,9 +182,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
this.strictMode = config.isDdlStrictMode();
|
||||
DbHistorySupport hist = platformDdl.getPlatform().getHistorySupport();
|
||||
if (hist == null) {
|
||||
this.historySupport = HistorySupport.NONE;
|
||||
this.alterHistoryTables = false;
|
||||
} else {
|
||||
this.historySupport = hist.isStandardsBased() ? HistorySupport.SQL2011 : HistorySupport.TRIGGER_BASED;
|
||||
this.alterHistoryTables = platformDdl.historyDdl.alterHistoryTables();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +233,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
if (platformDdl.isInlineForeignKeys()) {
|
||||
writeInlineForeignKeys(writer, createTable);
|
||||
writeInlineForeignKeys(apply, createTable);
|
||||
}
|
||||
apply.newLine().append(")");
|
||||
addTableStorageEngine(apply, createTable);
|
||||
@@ -340,7 +325,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
uqName = col.getUnique();
|
||||
}
|
||||
String[] columnNames = {col.getName()};
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames));
|
||||
String[] nullableColumns = Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames;
|
||||
writer.applyPostAlter().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
|
||||
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
|
||||
}
|
||||
|
||||
@@ -349,7 +335,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
String[] columnNames = split(constraint.getColumnNames());
|
||||
String[] nullableColumns = split(constraint.getNullableColumns());
|
||||
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
|
||||
writer.applyPostAlter().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
|
||||
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
|
||||
}
|
||||
}
|
||||
@@ -368,25 +354,25 @@ public class BaseTableDdl implements TableDdl {
|
||||
platformDdl.createWithHistory(writer, table);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKeys(DdlWrite writer, CreateTable createTable) {
|
||||
protected void writeInlineForeignKeys(DdlBuffer buffer, CreateTable createTable) {
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String references = column.getReferences();
|
||||
if (hasValue(references)) {
|
||||
writeInlineForeignKey(writer, column);
|
||||
writeInlineForeignKey(buffer, column);
|
||||
}
|
||||
}
|
||||
writeInlineCompoundForeignKeys(writer, createTable);
|
||||
writeInlineCompoundForeignKeys(buffer, createTable);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKey(DdlWrite writer, Column column) {
|
||||
protected void writeInlineForeignKey(DdlBuffer buffer, Column column) {
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column));
|
||||
writer.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
buffer.append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
|
||||
protected void writeInlineCompoundForeignKeys(DdlWrite writer, CreateTable createTable) {
|
||||
protected void writeInlineCompoundForeignKeys(DdlBuffer buffer, CreateTable createTable) {
|
||||
for (ForeignKey key : createTable.getForeignKey()) {
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
|
||||
writer.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
buffer.append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +544,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, CreateIndex index) {
|
||||
if (platformInclude(index.getPlatforms())) {
|
||||
writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
|
||||
writer.applyForeignKeys().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
|
||||
writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent())));
|
||||
}
|
||||
}
|
||||
@@ -566,7 +552,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropIndex dropIndex) {
|
||||
if (platformInclude(dropIndex.getPlatforms())) {
|
||||
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
|
||||
writer.applyDropDependencies()
|
||||
.appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,12 +561,14 @@ public class BaseTableDdl implements TableDdl {
|
||||
public void generate(DdlWrite writer, AddUniqueConstraint constraint) {
|
||||
if (platformInclude(constraint.getPlatforms())) {
|
||||
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
|
||||
writer.applyDropDependencies()
|
||||
.appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
|
||||
|
||||
} else {
|
||||
String[] cols = split(constraint.getColumnNames());
|
||||
String[] nullableColumns = split(constraint.getNullableColumns());
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
|
||||
writer.applyPostAlter()
|
||||
.appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,9 +576,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) {
|
||||
if (DdlHelp.isDropForeignKey(alterForeignKey.getColumnNames())) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName()));
|
||||
writer.applyDropDependencies().appendStatement(platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName()));
|
||||
} else {
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddForeignKey(writer.getOptions(), new WriteForeignKey(alterForeignKey)));
|
||||
writer.applyForeignKeys().appendStatement(platformDdl.alterTableAddForeignKey(writer.getOptions(), new WriteForeignKey(alterForeignKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,22 +608,13 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
@Override
|
||||
public void generateEpilog(DdlWrite writer) {
|
||||
if (!regenerateHistoryTriggers.isEmpty()) {
|
||||
platformDdl.lockTables(writer.applyHistoryTrigger(), regenerateHistoryTriggers.keySet());
|
||||
|
||||
for (HistoryTableUpdate update : this.regenerateHistoryTriggers.values()) {
|
||||
platformDdl.regenerateHistoryTriggers(writer, update);
|
||||
}
|
||||
|
||||
platformDdl.unlockTables(writer.applyHistoryTrigger(), regenerateHistoryTriggers.keySet());
|
||||
}
|
||||
platformDdl.generateEpilog(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AddTableComment addTableComment) {
|
||||
if (hasValue(addTableComment.getComment())) {
|
||||
platformDdl.addTableComment(writer.apply(), addTableComment.getName(), addTableComment.getComment());
|
||||
platformDdl.addTableComment(writer.applyPostAlter(), addTableComment.getName(), addTableComment.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,14 +626,16 @@ public class BaseTableDdl implements TableDdl {
|
||||
String tableName = addColumn.getTableName();
|
||||
List<Column> columns = addColumn.getColumn();
|
||||
for (Column column : columns) {
|
||||
alterTableAddColumn(writer.apply(), tableName, column, false, isTrue(addColumn.isWithHistory()));
|
||||
alterTableAddColumn(writer, tableName, column, false, isTrue(addColumn.isWithHistory()));
|
||||
}
|
||||
if (isTrue(addColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
|
||||
if (isTrue(addColumn.isWithHistory())) {
|
||||
platformDdl.regenerateHistoryTriggers(writer, tableName);
|
||||
// make same changes to the history table
|
||||
String historyTable = historyTable(tableName);
|
||||
for (Column column : columns) {
|
||||
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.ADD, column.getName());
|
||||
alterTableAddColumn(writer.apply(), historyTable, column, true, true);
|
||||
if (alterHistoryTables) {
|
||||
String historyTable = historyTable(tableName);
|
||||
for (Column column : columns) {
|
||||
alterTableAddColumn(writer, historyTable, column, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Column column : columns) {
|
||||
@@ -661,7 +643,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
writeForeignKey(writer, tableName, column);
|
||||
}
|
||||
}
|
||||
writer.apply().end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,14 +650,14 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropTable dropTable) {
|
||||
dropTable(writer.apply(), dropTable.getName());
|
||||
dropTable(writer.applyPostAlter(), dropTable.getName());
|
||||
if (hasValue(dropTable.getSequenceCol())
|
||||
&& platformDdl.getPlatform().getDbIdentity().isSupportsSequence()) {
|
||||
String sequenceName = dropTable.getSequenceName();
|
||||
if (!hasValue(sequenceName)) {
|
||||
sequenceName = namingConvention.getSequenceName(dropTable.getName(), dropTable.getSequenceCol());
|
||||
}
|
||||
dropSequence(writer.apply(), sequenceName);
|
||||
dropSequence(writer.applyPostAlter(), sequenceName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,14 +667,15 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropColumn dropColumn) {
|
||||
String tableName = dropColumn.getTableName();
|
||||
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
|
||||
alterTableDropColumn(writer, tableName, dropColumn.getColumnName());
|
||||
|
||||
if (isTrue(dropColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
|
||||
if (isTrue(dropColumn.isWithHistory())) {
|
||||
platformDdl.regenerateHistoryTriggers(writer, tableName);
|
||||
// also drop from the history table
|
||||
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.DROP, dropColumn.getColumnName());
|
||||
alterTableDropColumn(writer.apply(), historyTable(tableName), dropColumn.getColumnName());
|
||||
if (alterHistoryTables) {
|
||||
alterTableDropColumn(writer, historyTable(tableName), dropColumn.getColumnName());
|
||||
}
|
||||
}
|
||||
writer.apply().end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -702,12 +684,13 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AlterColumn alterColumn) {
|
||||
DdlMigrationHelp ddlHelp = new DdlMigrationHelp(alterColumn);
|
||||
ddlHelp.writeBefore(writer.apply());
|
||||
ddlHelp.write(writer);
|
||||
|
||||
if (isTrue(alterColumn.isHistoryExclude())) {
|
||||
regenerateHistoryTriggers(alterColumn.getTableName(), HistoryTableUpdate.Change.EXCLUDE, alterColumn.getColumnName());
|
||||
} else if (isFalse(alterColumn.isHistoryExclude())) {
|
||||
regenerateHistoryTriggers(alterColumn.getTableName(), HistoryTableUpdate.Change.INCLUDE, alterColumn.getColumnName());
|
||||
if (alterColumn.isHistoryExclude() != null) {
|
||||
// CHECKME should we drop a small comment, if historyExclude changes, as not all DB systems will support this
|
||||
// writer.apply().append("-- historyExclude of ").append(alterColumn.getTableName()).append(".").append(alterColumn.getColumnName())
|
||||
// .append(" altered to ").append(String.valueOf(alterColumn.isHistoryExclude())).end();
|
||||
platformDdl.regenerateHistoryTriggers(writer, alterColumn.getTableName());
|
||||
}
|
||||
|
||||
if (hasValue(alterColumn.getDropForeignKey())) {
|
||||
@@ -739,31 +722,21 @@ public class BaseTableDdl implements TableDdl {
|
||||
// drop constraint before altering type etc
|
||||
dropCheckConstraint(writer, alterColumn, alterColumn.getCheckConstraintName());
|
||||
}
|
||||
boolean alterBaseAttributes = false;
|
||||
if (hasValue(alterColumn.getType())) {
|
||||
alterColumnType(writer, alterColumn);
|
||||
alterBaseAttributes = true;
|
||||
}
|
||||
if (hasValue(alterColumn.getDefaultValue())) {
|
||||
alterColumnDefaultValue(writer, alterColumn);
|
||||
alterBaseAttributes = true;
|
||||
}
|
||||
if (alterColumn.isNotnull() != null) {
|
||||
alterColumnNotnull(writer, alterColumn);
|
||||
alterBaseAttributes = true;
|
||||
}
|
||||
if (alterBaseAttributes) {
|
||||
alterColumnBaseAttributes(writer, alterColumn);
|
||||
|
||||
if (hasValue(alterColumn.getType())
|
||||
|| hasValue(alterColumn.getDefaultValue())
|
||||
|| alterColumn.isNotnull() != null) {
|
||||
alterColumn(writer, alterColumn);
|
||||
}
|
||||
|
||||
if (alterCheckConstraint) {
|
||||
// add constraint last (after potential type change)
|
||||
addCheckConstraint(writer, alterColumn);
|
||||
}
|
||||
ddlHelp.writeAfter(writer.apply());
|
||||
}
|
||||
|
||||
private void alterColumnComment(DdlWrite writer, AlterColumn alterColumn) {
|
||||
platformDdl.addColumnComment(writer.apply(), alterColumn.getTableName(), alterColumn.getColumnName(), alterColumn.getComment());
|
||||
platformDdl.addColumnComment(writer.applyPostAlter(), alterColumn.getTableName(), alterColumn.getColumnName(), alterColumn.getComment());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -774,76 +747,72 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the base table that we need to regenerate the history triggers on.
|
||||
* alter all the base attributes (type/default/notnull) of the column together.
|
||||
* Some platforms (like mysql/sqlserver/hana) must do that in one statement,
|
||||
* other platforms may use several statements for altering one of the base
|
||||
* attributes.
|
||||
*/
|
||||
protected void regenerateHistoryTriggers(String baseTableName, HistoryTableUpdate.Change change, String column) {
|
||||
HistoryTableUpdate update = regenerateHistoryTriggers.computeIfAbsent(baseTableName, HistoryTableUpdate::new);
|
||||
update.add(change, column);
|
||||
}
|
||||
protected void alterColumn(DdlWrite writer, AlterColumn alter) {
|
||||
platformDdl.alterColumn(writer, alter);
|
||||
|
||||
/**
|
||||
* This is mysql specific - alter all the base attributes of the column together.
|
||||
* Will be called, if there is a type, dbdefault or notnull change.
|
||||
*/
|
||||
protected void alterColumnBaseAttributes(DdlWrite writer, AlterColumn alter) {
|
||||
String ddl = platformDdl.alterColumnBaseAttributes(alter);
|
||||
if (hasValue(ddl)) {
|
||||
writer.apply().appendStatement(ddl);
|
||||
|
||||
if (isTrue(alter.isWithHistory()) && alter.getType() != null && historySupport == HistorySupport.TRIGGER_BASED) {
|
||||
// mysql and sql server column type change allowing nulls in the history table column
|
||||
regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName());
|
||||
AlterColumn alterHistoryColumn = new AlterColumn();
|
||||
alterHistoryColumn.setTableName(historyTable(alter.getTableName()));
|
||||
alterHistoryColumn.setColumnName(alter.getColumnName());
|
||||
alterHistoryColumn.setType(alter.getType());
|
||||
String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
|
||||
|
||||
// write the apply to history table
|
||||
writer.apply().appendStatement(histColumnDdl);
|
||||
if (isTrue(alter.isWithHistory())) {
|
||||
// we will apply only type changes or notNull -> null transition
|
||||
boolean isNull = Boolean.FALSE.equals(alter.isNotnull());
|
||||
boolean applyToHistory = alter.getType() != null || isNull;
|
||||
boolean syncExact = platformDdl.getPlatform().isPlatform(Platform.DB2);
|
||||
// DB2 needs exact sync for notnull/null
|
||||
if (syncExact && alter.isNotnull() != null) {
|
||||
applyToHistory = true;
|
||||
}
|
||||
if (applyToHistory) {
|
||||
platformDdl.regenerateHistoryTriggers(writer, alter.getTableName());
|
||||
if (alterHistoryTables) {
|
||||
AlterColumn alterHistoryColumn = new AlterColumn();
|
||||
alterHistoryColumn.setTableName(historyTable(alter.getTableName()));
|
||||
alterHistoryColumn.setColumnName(alter.getColumnName());
|
||||
// ignore default value (not needed on history tables)
|
||||
alterHistoryColumn.setCurrentType(alter.getCurrentType());
|
||||
alterHistoryColumn.setType(alter.getType());
|
||||
if (syncExact) {
|
||||
alterHistoryColumn.setCurrentNotnull(alter.isCurrentNotnull());
|
||||
alterHistoryColumn.setNotnull(alter.isNotnull());
|
||||
} else if (isNull) {
|
||||
// do transition from notNull to null
|
||||
alterHistoryColumn.setCurrentNotnull(Boolean.TRUE);
|
||||
alterHistoryColumn.setNotnull(Boolean.FALSE);
|
||||
} else {
|
||||
// assume that the column contains null values from the past (required for platforms like mysql/sqlserver/hana)
|
||||
alterHistoryColumn.setCurrentNotnull(Boolean.FALSE);
|
||||
}
|
||||
platformDdl.alterColumn(writer, alterHistoryColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) {
|
||||
writer.apply().appendStatement(platformDdl.alterColumnDefaultValue(alter.getTableName(), alter.getColumnName(), alter.getDefaultValue()));
|
||||
}
|
||||
|
||||
protected void dropCheckConstraint(DdlWrite writer, AlterColumn alter, String constraintName) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
|
||||
writer.applyDropDependencies()
|
||||
.appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
|
||||
}
|
||||
|
||||
protected void addCheckConstraint(DdlWrite writer, AlterColumn alter) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
|
||||
writer.applyPostAlter()
|
||||
.appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
|
||||
}
|
||||
|
||||
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) {
|
||||
writer.apply().appendStatement(platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull()));
|
||||
}
|
||||
|
||||
protected void alterColumnType(DdlWrite writer, AlterColumn alter) {
|
||||
String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
|
||||
if (hasValue(ddl)) {
|
||||
writer.apply().appendStatement(ddl);
|
||||
if (isTrue(alter.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
|
||||
regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName());
|
||||
// apply same type change to matching column in the history table
|
||||
ddl = platformDdl.alterColumnType(historyTable(alter.getTableName()), alter.getColumnName(), alter.getType());
|
||||
writer.apply().appendStatement(ddl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) {
|
||||
alterTableAddForeignKey(writer.getOptions(), writer.apply(), new WriteForeignKey(alterColumn));
|
||||
alterTableAddForeignKey(writer.getOptions(), writer.applyForeignKeys(), new WriteForeignKey(alterColumn));
|
||||
}
|
||||
|
||||
protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
|
||||
writer.applyDropDependencies()
|
||||
.appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
|
||||
}
|
||||
|
||||
protected void alterColumnDropUniqueConstraint(DdlWrite writer, AlterColumn alter) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
|
||||
writer.applyDropDependencies()
|
||||
.appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
|
||||
}
|
||||
|
||||
protected void alterColumnAddUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) {
|
||||
@@ -857,31 +826,29 @@ public class BaseTableDdl implements TableDdl {
|
||||
protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName) {
|
||||
String[] cols = {alter.getColumnName()};
|
||||
boolean notNull = alter.isNotnull() != null ? alter.isNotnull() : Boolean.TRUE.equals(alter.isNotnull());
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
|
||||
writer.applyPostAlter()
|
||||
.appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
|
||||
|
||||
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, alter.getTableName()));
|
||||
}
|
||||
|
||||
|
||||
protected void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) {
|
||||
platformDdl.alterTableDropColumn(buffer, tableName, columnName);
|
||||
protected void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
|
||||
platformDdl.alterTableDropColumn(writer, tableName, columnName);
|
||||
}
|
||||
|
||||
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, boolean withHistory) {
|
||||
protected void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, boolean withHistory) {
|
||||
DdlMigrationHelp help = new DdlMigrationHelp(tableName, column, withHistory);
|
||||
if (!onHistoryTable) {
|
||||
help.writeBefore(buffer);
|
||||
help.write(writer);
|
||||
}
|
||||
|
||||
platformDdl.alterTableAddColumn(buffer, tableName, column, onHistoryTable, help.getDefaultValue());
|
||||
platformDdl.alterTableAddColumn(writer, tableName, column, onHistoryTable, help.getDefaultValue());
|
||||
final String comment = column.getComment();
|
||||
if (comment != null && !comment.isEmpty()) {
|
||||
platformDdl.addColumnComment(buffer, tableName, column.getName(), comment);
|
||||
platformDdl.addColumnComment(writer.applyPostAlter(), tableName, column.getName(), comment);
|
||||
}
|
||||
|
||||
if (!onHistoryTable) {
|
||||
help.writeAfter(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isFalse(Boolean value) {
|
||||
|
||||
+1
-5
@@ -14,6 +14,7 @@ public class ClickHouseDdl extends PlatformDdl {
|
||||
super(platform);
|
||||
this.includeStorageEngine = true;
|
||||
this.identitySuffix = "";
|
||||
this.columnNotNull = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,11 +69,6 @@ public class ClickHouseDdl extends PlatformDdl {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeColumnNotNull(DdlBuffer buffer) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
|
||||
// do nothing
|
||||
|
||||
+149
-6
@@ -1,7 +1,14 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.annotation.ConstraintMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.Column;
|
||||
|
||||
/**
|
||||
* DB2 platform specific DDL.
|
||||
@@ -12,12 +19,13 @@ public class DB2Ddl extends PlatformDdl {
|
||||
super(platform);
|
||||
this.dropTableIfExists = "drop table ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
this.dropConstraintIfExists = "drop constraint";
|
||||
this.dropIndexIfExists = "drop index ";
|
||||
this.dropConstraintIfExists = "NOT USED";
|
||||
this.dropIndexIfExists = "NOT USED";
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
this.columnSetNull = "drop not null";
|
||||
this.columnSetType = "set data type ";
|
||||
this.inlineUniqueWhenNullable = false;
|
||||
this.historyDdl = new Db2HistoryDdl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,7 +38,7 @@ public class DB2Ddl extends PlatformDdl {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("create unique index ");
|
||||
sb.append(uqName).append(" on ").append(tableName).append('(');
|
||||
sb.append(maxConstraintName(uqName)).append(" on ").append(tableName).append('(');
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
if (i > 0) {
|
||||
@@ -43,8 +51,143 @@ public class DB2Ddl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) {
|
||||
// do nothing, no on update clause for db2
|
||||
public void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, String defaultValue) {
|
||||
|
||||
String convertedType = convert(column.getType());
|
||||
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, column.getName());
|
||||
buffer.append(convertedType);
|
||||
|
||||
// Add default value also to history table if it is not excluded
|
||||
if (defaultValue != null) {
|
||||
buffer.append(" default ");
|
||||
buffer.append(defaultValue);
|
||||
}
|
||||
|
||||
if (isTrue(column.isNotnull())) {
|
||||
buffer.appendWithSpace(columnNotNull);
|
||||
}
|
||||
// DB2 History table must match exact!
|
||||
if (!onHistoryTable) {
|
||||
// check constraints cannot be added in one statement for h2
|
||||
if (!StringHelper.isNull(column.getCheckConstraint())) {
|
||||
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint());
|
||||
writer.applyPostAlter().appendStatement(ddl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public String alterTableDropForeignKey(String tableName, String fkName) {
|
||||
return alterTableDropConstraint(tableName, fkName);
|
||||
};
|
||||
|
||||
@Override
|
||||
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
|
||||
return alterTableDropConstraint(tableName, uniqueConstraintName)
|
||||
+ "\n" + dropIndex(uniqueConstraintName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableDropConstraint(String tableName, String constraintName) {
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
sb.append("delimiter $$\n")
|
||||
.append("begin\n")
|
||||
.append("if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = '")
|
||||
.append(maxConstraintName(constraintName).toUpperCase())
|
||||
.append("' and tabname = '").append(lowerTableName(tableName).toUpperCase()).append("') then\n")
|
||||
|
||||
.append(" prepare stmt from 'alter table ").append(lowerTableName(tableName))
|
||||
.append(" drop constraint ").append(maxConstraintName(constraintName)).append("';\n")
|
||||
|
||||
.append(" execute stmt;\n")
|
||||
.append("end if;\n")
|
||||
.append("end$$");
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
sb.append("delimiter $$\n")
|
||||
.append("begin\n")
|
||||
.append("if exists (select indname from syscat.indexes where indschema = current_schema and indname = '")
|
||||
.append(maxConstraintName(indexName).toUpperCase()).append("') then\n")
|
||||
.append(" prepare stmt from 'drop index ").append(maxConstraintName(indexName)).append("';\n")
|
||||
.append(" execute stmt;\n")
|
||||
.append("end if;\n")
|
||||
.append("end$$");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropSequence(String sequenceName) {
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
sb.append("delimiter $$\n");
|
||||
sb.append("begin\n");
|
||||
sb.append("if exists (select seqschema from syscat.sequences where seqschema = current_schema and seqname = '")
|
||||
.append(maxConstraintName(sequenceName).toUpperCase()).append("') then\n");
|
||||
sb.append(" prepare stmt from 'drop sequence ").append(maxConstraintName(sequenceName)).append("';\n");
|
||||
sb.append(" execute stmt;\n");
|
||||
sb.append("end if;\n");
|
||||
sb.append("end$$");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
|
||||
return writer.applyAlterTable(tableName, Db2AlterTableWrite::new);
|
||||
};
|
||||
static class Db2AlterTableWrite extends BaseAlterTableWrite {
|
||||
|
||||
public Db2AlterTableWrite(String tableName) {
|
||||
super(tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
|
||||
List<AlterCmd> ret = new ArrayList<>(cmds.size() + 1);
|
||||
boolean requiresReorg = false;
|
||||
for (AlterCmd cmd : cmds) {
|
||||
ret.add(cmd);
|
||||
if (!requiresReorg && checkReorg(cmd)) {
|
||||
requiresReorg = true;
|
||||
}
|
||||
}
|
||||
if (requiresReorg) {
|
||||
ret.add(newRawCommand("call sysproc.admin_cmd('reorg table " + tableName() + "')"));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* determine, if we need a reorg.
|
||||
*
|
||||
* See: https://www.ibm.com/docs/en/db2/11.5?topic=statements-alter-table The following is the full list of REORG-recommended
|
||||
* ALTER statements that cause a version change and place the table into a REORG-pending state:
|
||||
* <ul>
|
||||
* <li>DROP COLUMN
|
||||
* <li>ALTER COLUMN SET NOT NULL
|
||||
* <li>ALTER COLUMN DROP NOT NULL
|
||||
* <li>ALTER COLUMN SET DATA TYPE, except in the following situations:<br>
|
||||
* Increasing the length of a VARCHAR or VARGRAPHIC column<br>
|
||||
* Decreasing the length of a VARCHAR or VARGRAPHIC column without truncating trailing blanks from existing data, when no indexes
|
||||
* exist on the column
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
private boolean checkReorg(AlterCmd cmd) {
|
||||
switch (cmd.getOperation()) {
|
||||
case "drop column":
|
||||
return true;
|
||||
case "alter column":
|
||||
String alter = cmd.getAlternation();
|
||||
return alter.equals("set not null")
|
||||
|| alter.equals("drop not default")
|
||||
|| alter.startsWith("set data type"); // note: altering varchar length only is not detected here
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
/**
|
||||
* DB2 History support.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public class Db2HistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
private String systemPeriodStart;
|
||||
private String systemPeriodEnd;
|
||||
private String transactionId;
|
||||
private PlatformDdl platformDdl;
|
||||
private String historySuffix;
|
||||
|
||||
@Override
|
||||
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
|
||||
this.systemPeriodStart = config.getAsOfSysPeriod() + "_start";
|
||||
this.systemPeriodEnd = config.getAsOfSysPeriod() + "_end";
|
||||
this.transactionId = config.getAsOfSysPeriod() + "_txn"; // required for DB2
|
||||
this.platformDdl = platformDdl;
|
||||
this.historySuffix = config.getHistoryTableSuffix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWithHistory(DdlWrite writer, MTable table) {
|
||||
String tableName = table.getName();
|
||||
String historyTableName = tableName + historySuffix;
|
||||
|
||||
DdlBuffer apply = writer.applyPostAlter();
|
||||
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine();
|
||||
|
||||
// create history table
|
||||
Collection<MColumn> cols = table.allColumns();
|
||||
for (MColumn column : cols) {
|
||||
if (!column.isDraftOnly()) {
|
||||
writeColumnDefinition(apply, column.getName(), column.getType(), column.isNotnull() || column.isPrimaryKey());
|
||||
apply.append(",").newLine();
|
||||
}
|
||||
}
|
||||
writeColumnDefinition(apply, systemPeriodStart, "timestamp(12)", true);
|
||||
apply.append(",").newLine();
|
||||
writeColumnDefinition(apply, systemPeriodEnd, "timestamp(12)", true);
|
||||
apply.append(",").newLine();
|
||||
writeColumnDefinition(apply, transactionId, "timestamp(12)", false);
|
||||
apply.newLine().append(")").endOfStatement();
|
||||
|
||||
// enable system versioning
|
||||
addSysPeriodColumns(writer, tableName);
|
||||
enableSystemVersioning(apply, tableName);
|
||||
platformDdl.alterTable(writer, tableName).setHistoryHandled();
|
||||
|
||||
// drop all: We do not drop columns here, as the whole table will be dropped
|
||||
disableSystemVersioning(writer.dropAll(), tableName);
|
||||
writer.dropAll().append("drop table ").append(historyTableName).endOfStatement();
|
||||
}
|
||||
|
||||
void addSysPeriodColumns(DdlWrite writer, String baseTable) {
|
||||
platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodStart, "timestamp(12) not null generated always as row begin", null);
|
||||
platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodEnd, "timestamp(12) not null generated always as row end", null);
|
||||
platformDdl.alterTableAddColumn(writer, baseTable, transactionId, "timestamp(12) generated always as transaction start id", null);
|
||||
platformDdl.alterTable(writer, baseTable).append("add period system_time", null)
|
||||
.append("(").append(systemPeriodStart).append(",").append(systemPeriodEnd).append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
|
||||
dropHistoryTable(writer, dropHistoryTable.getBaseTable(), dropHistoryTable.getBaseTable() + historySuffix);
|
||||
}
|
||||
|
||||
protected void dropHistoryTable(DdlWrite writer, String baseTable, String historyTable) {
|
||||
disableSystemVersioning(writer.apply(), baseTable);
|
||||
writer.apply().append("alter table ").append(baseTable).append(" drop period system_time").endOfStatement();
|
||||
|
||||
// drop the period & period columns
|
||||
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodStart);
|
||||
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodEnd);
|
||||
platformDdl.alterTableDropColumn(writer, baseTable, transactionId);
|
||||
|
||||
// drop the history table
|
||||
writer.applyPostAlter().append("drop table ").append(historyTable).endOfStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
|
||||
MTable table = writer.getTable(addHistoryTable.getBaseTable());
|
||||
if (table == null) {
|
||||
throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)");
|
||||
}
|
||||
createWithHistory(writer, table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alterHistoryTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, String tableName) {
|
||||
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table.isWithHistory() && !alter.isHistoryHandled()) {
|
||||
disableSystemVersioning(writer.apply(), tableName);
|
||||
enableSystemVersioning(writer.applyPostAlter(), tableName);
|
||||
alter.setHistoryHandled();
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, boolean isNotNull) {
|
||||
|
||||
String platformType = platformDdl.convert(type);
|
||||
buffer.append(" ").append(platformDdl.lowerColumnName(columnName));
|
||||
buffer.append(" ").append(platformType);
|
||||
if (isNotNull) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
}
|
||||
|
||||
public void disableSystemVersioning(DdlBuffer apply, String tableName) {
|
||||
apply.append("alter table ").append(tableName).append(" drop versioning").endOfStatement();
|
||||
}
|
||||
|
||||
public void enableSystemVersioning(DdlBuffer apply, String tableName) {
|
||||
apply.append("alter table ").append(tableName).append(" add versioning use history table ").append(tableName).append(historySuffix).endOfStatement();
|
||||
}
|
||||
|
||||
}
|
||||
+66
-81
@@ -2,6 +2,7 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
@@ -46,40 +47,6 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
this.sysPeriodEnd = sysPeriod + "_end";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, HistoryTableUpdate update) {
|
||||
|
||||
MTable table = writer.getTable(update.getBaseTable());
|
||||
if (table == null) {
|
||||
throw new IllegalStateException("MTable " + update.getBaseTable() + " not found in writer? (required for history DDL)");
|
||||
}
|
||||
updateTriggers(writer, table, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the existing triggers/stored procedures/views for history table support given the included columns.
|
||||
*/
|
||||
protected abstract void updateHistoryTriggers(DbTriggerUpdate triggerUpdate);
|
||||
|
||||
/**
|
||||
* Process the HistoryTableUpdate which can result in changes to the apply, rollback
|
||||
* and drop scripts.
|
||||
*/
|
||||
protected void updateTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) {
|
||||
|
||||
writer.applyHistoryTrigger().append("-- changes: ").append(update.description()).newLine();
|
||||
|
||||
updateHistoryTriggers(createDbTriggerUpdate(writer, table));
|
||||
}
|
||||
|
||||
protected DbTriggerUpdate createDbTriggerUpdate(DdlWrite writer, MTable table) {
|
||||
|
||||
List<String> columns = columnNamesForApply(table);
|
||||
String baseTableName = table.getName();
|
||||
String historyTableName = historyTableName(baseTableName);
|
||||
return new DbTriggerUpdate(baseTableName, historyTableName, writer, columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
|
||||
|
||||
@@ -87,7 +54,10 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
// drop in appropriate order
|
||||
dropTriggers(writer.applyDropDependencies(), baseTable);
|
||||
dropHistoryTableEtc(writer.applyDropDependencies(), baseTable);
|
||||
dropWithHistoryView(writer.applyDropDependencies(), baseTable);
|
||||
dropHistoryTable(writer.applyDropDependencies(), baseTable);
|
||||
|
||||
dropSysPeriodColumns(writer, baseTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,23 +76,51 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
public void createWithHistory(DdlWrite writer, MTable table) {
|
||||
|
||||
String baseTable = table.getName();
|
||||
String whenCreatedColumn = table.getWhenCreatedColumn();
|
||||
|
||||
addSysPeriodColumns(writer, baseTable, table.getWhenCreatedColumn());
|
||||
createHistoryTable(writer.applyPostAlter(), table);
|
||||
|
||||
createWithHistoryView(writer.applyPostAlter(), table.getName());
|
||||
createTriggers(writer.applyPostAlter(), baseTable, columnNamesForApply(table));
|
||||
writer.applyPostAlter().end();
|
||||
|
||||
// drop all scripts
|
||||
dropTriggers(writer.dropAll(), baseTable);
|
||||
dropHistoryTableEtc(writer.dropAll(), baseTable);
|
||||
dropWithHistoryView(writer.dropAll(), baseTable);
|
||||
dropHistoryTable(writer.dropAll(), baseTable);
|
||||
// no need to dropSysPeriodColumns as whole table will be deleted soon
|
||||
|
||||
addHistoryTable(writer, table, whenCreatedColumn);
|
||||
createStoredFunction(writer, table);
|
||||
createTriggers(writer, table);
|
||||
}
|
||||
|
||||
protected abstract void createTriggers(DdlWrite writer, MTable table);
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, String tableName) {
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table != null && table.isWithHistory()) {
|
||||
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
|
||||
if (!alter.isHistoryHandled()) {
|
||||
// this code effectively disables history support before the table alter and enables it again
|
||||
// immediately after the table alter. As all alters per table are altogether now, this can done here
|
||||
dropTriggers(writer.apply(), tableName);
|
||||
dropWithHistoryView(writer.apply(), tableName);
|
||||
// here are the alter commands
|
||||
createWithHistoryView(writer.applyPostAlter(), tableName);
|
||||
createTriggers(writer.applyPostAlter(), tableName, columnNamesForApply(table));
|
||||
|
||||
alter.setHistoryHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add a history trigger to the buffer. The config
|
||||
*
|
||||
* @param buffer
|
||||
* @param table
|
||||
*/
|
||||
protected abstract void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames);
|
||||
|
||||
protected abstract void dropTriggers(DdlBuffer buffer, String baseTable);
|
||||
|
||||
protected void createStoredFunction(DdlWrite writer, MTable table) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
protected String normalise(String tableName) {
|
||||
return constraintNaming.normaliseTable(tableName);
|
||||
@@ -152,22 +150,19 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
String baseTableName = table.getName();
|
||||
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
|
||||
addSysPeriodColumns(apply, baseTableName, whenCreatedColumn);
|
||||
createHistoryTable(apply, table);
|
||||
createWithHistoryView(apply, baseTableName);
|
||||
addSysPeriodColumns(writer, baseTableName, whenCreatedColumn);
|
||||
createHistoryTable(writer.applyPostAlter(), table);
|
||||
createWithHistoryView(writer.applyPostAlter(), baseTableName);
|
||||
}
|
||||
|
||||
protected void addSysPeriodColumns(DdlBuffer apply, String baseTableName, String whenCreatedColumn) {
|
||||
|
||||
apply.append("alter table ").append(baseTableName).append(" add column ")
|
||||
.append(sysPeriodStart).append(" ").append(sysPeriodType).append(" default ").append(now).endOfStatement();
|
||||
apply.append("alter table ").append(baseTableName).append(" add column ")
|
||||
.append(sysPeriodEnd).append(" ").append(sysPeriodType).endOfStatement();
|
||||
protected void addSysPeriodColumns(DdlWrite writer, String baseTableName, String whenCreatedColumn) {
|
||||
|
||||
platformDdl.alterTableAddColumn(writer, baseTableName, sysPeriodStart, sysPeriodType, now);
|
||||
platformDdl.alterTableAddColumn(writer, baseTableName, sysPeriodEnd, sysPeriodType, null);
|
||||
if (whenCreatedColumn != null) {
|
||||
apply.append("update ").append(baseTableName).append(" set ").append(sysPeriodStart).append(" = ").append(whenCreatedColumn).endOfStatement();
|
||||
writer.applyPostAlter()
|
||||
.append("update ").append(baseTableName).append(" set ").append(sysPeriodStart).append(" = ").append(whenCreatedColumn).endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,22 +205,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
.append("create view ").append(baseTableName).append(viewSuffix)
|
||||
.append(" as select * from ").append(baseTableName)
|
||||
.append(" union all select * from ").append(baseTableName).append(historySuffix)
|
||||
.endOfStatement().end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For postgres/h2/mysql we need to drop and recreate the view. Well, we could add columns to the end of the view
|
||||
* but otherwise we need to drop and create it.
|
||||
*/
|
||||
protected void recreateHistoryView(DbTriggerUpdate update) {
|
||||
|
||||
DdlBuffer buffer = update.dropDependencyBuffer();
|
||||
// we need to drop the view early/first before any changes to the tables etc
|
||||
buffer.append("drop view if exists ").append(update.getBaseTable()).append(viewSuffix).endOfStatement();
|
||||
|
||||
// recreate the view after all ddl modifications - the view requires ALL columns, also the historyExclude ones.
|
||||
createWithHistoryView(update.historyViewBuffer(), update.getBaseTable());
|
||||
.endOfStatement();
|
||||
}
|
||||
|
||||
protected void appendSysPeriodColumns(DdlBuffer apply, String prefix) {
|
||||
@@ -233,21 +213,22 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
appendColumnName(apply, prefix, sysPeriodEnd);
|
||||
}
|
||||
|
||||
protected void dropHistoryTableEtc(DdlBuffer buffer, String baseTableName) {
|
||||
|
||||
buffer.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement();
|
||||
dropSysPeriodColumns(buffer, baseTableName);
|
||||
buffer.append("drop table ").append(baseTableName).append(historySuffix).endOfStatement().end();
|
||||
protected void dropWithHistoryView(DdlBuffer apply, String baseTableName) {
|
||||
apply.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement();
|
||||
}
|
||||
|
||||
protected void dropSysPeriodColumns(DdlBuffer buffer, String baseTableName) {
|
||||
platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodStart);
|
||||
platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodEnd);
|
||||
protected void dropHistoryTable(DdlBuffer apply, String baseTableName) {
|
||||
apply.append("drop table ").append(baseTableName).append(historySuffix).endOfStatement().end();
|
||||
}
|
||||
|
||||
protected void appendInsertIntoHistory(DdlBuffer buffer, String historyTable, List<String> columns) {
|
||||
protected void dropSysPeriodColumns(DdlWrite writer, String baseTableName) {
|
||||
platformDdl.alterTableDropColumn(writer, baseTableName, sysPeriodStart);
|
||||
platformDdl.alterTableDropColumn(writer, baseTableName, sysPeriodEnd);
|
||||
}
|
||||
|
||||
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
|
||||
protected void appendInsertIntoHistory(DdlBuffer buffer, String baseTable, List<String> columns) {
|
||||
|
||||
buffer.append(" insert into ").append(baseTable).append(historySuffix).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
|
||||
appendColumnNames(buffer, columns, "");
|
||||
buffer.append(") values (OLD.").append(sysPeriodStart).append(", ").append(sysPeriodEndValue).append(",");
|
||||
appendColumnNames(buffer, columns, "OLD.");
|
||||
@@ -285,4 +266,8 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
return table.allHistoryColumns(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alterHistoryTables() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DB trigger update when a change occurs on a table with history.
|
||||
*/
|
||||
public class DbTriggerUpdate {
|
||||
|
||||
private final String baseTableName;
|
||||
|
||||
private final String historyTableName;
|
||||
|
||||
private final DdlWrite writer;
|
||||
|
||||
private final List<String> columns;
|
||||
|
||||
public DbTriggerUpdate(String baseTableName, String historyTableName, DdlWrite writer, List<String> columns) {
|
||||
this.baseTableName = baseTableName;
|
||||
this.historyTableName = historyTableName;
|
||||
this.writer = writer;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate buffer for the current mode.
|
||||
*/
|
||||
public DdlBuffer historyViewBuffer() {
|
||||
return writer.applyHistoryView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate buffer for the current mode.
|
||||
*/
|
||||
public DdlBuffer historyTriggerBuffer() {
|
||||
return writer.applyHistoryTrigger();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the appropriate drop dependency buffer for the current mode.
|
||||
*/
|
||||
public DdlBuffer dropDependencyBuffer() {
|
||||
return writer.applyDropDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table name.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the history table name.
|
||||
*/
|
||||
public String getHistoryTable() {
|
||||
return historyTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the included columns.
|
||||
*/
|
||||
public List<String> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-14
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
/**
|
||||
* H2 history support using DB triggers to maintain a history table.
|
||||
@@ -23,18 +23,8 @@ public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTriggers(DdlWrite writer, MTable table) {
|
||||
String baseTableName = table.getName();
|
||||
DdlBuffer apply = writer.applyHistoryTrigger();
|
||||
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHistoryTriggers(DbTriggerUpdate update) {
|
||||
recreateHistoryView(update);
|
||||
DdlBuffer buffer = update.historyTriggerBuffer();
|
||||
dropTriggers(buffer, update.getBaseTable());
|
||||
addCreateTrigger(buffer, updateTriggerName(update.getBaseTable()), update.getBaseTable());
|
||||
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
|
||||
addCreateTrigger(buffer, updateTriggerName(baseTable), baseTable);
|
||||
}
|
||||
|
||||
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable) {
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler;
|
||||
|
||||
public class HanaDdlHandler extends BaseDdlHandler {
|
||||
|
||||
public HanaDdlHandler(DatabaseConfig config, PlatformDdl platformDdl) {
|
||||
super(config, platformDdl, new HanaTableDdl(config, platformDdl));
|
||||
}
|
||||
}
|
||||
+20
-36
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
@@ -9,9 +10,6 @@ import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
@@ -19,8 +17,6 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
private String systemPeriodEnd;
|
||||
private PlatformDdl platformDdl;
|
||||
private String historySuffix;
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
private Map<String, String> createdHistoryTables = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
|
||||
@@ -34,10 +30,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
public void createWithHistory(DdlWrite writer, MTable table) {
|
||||
String tableName = table.getName();
|
||||
String historyTableName = tableName + historySuffix;
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
if (apply.isEmpty()) {
|
||||
createdHistoryTables.clear();
|
||||
}
|
||||
DdlBuffer apply = writer.applyPostAlter();
|
||||
|
||||
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine();
|
||||
|
||||
@@ -64,9 +57,8 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
apply.append("alter table ").append(tableName).append(" add period for system_time(").append(systemPeriodStart)
|
||||
.append(",").append(systemPeriodEnd).append(")").endOfStatement();
|
||||
|
||||
enableSystemVersioning(apply, tableName, historyTableName, true, false);
|
||||
|
||||
createdHistoryTables.put(tableName, historyTableName);
|
||||
enableSystemVersioning(apply, tableName, true);
|
||||
platformDdl.alterTable(writer, tableName).setHistoryHandled();
|
||||
|
||||
dropHistoryTable(writer.dropAll(), tableName, historyTableName);
|
||||
}
|
||||
@@ -101,8 +93,19 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) {
|
||||
// nothing to do
|
||||
public boolean alterHistoryTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, String tableName) {
|
||||
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table.isWithHistory() && !alter.isHistoryHandled()) {
|
||||
disableSystemVersioning(writer.apply(), tableName);
|
||||
enableSystemVersioning(writer.applyPostAlter(), tableName, false);
|
||||
alter.setHistoryHandled();
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue,
|
||||
@@ -123,34 +126,15 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
public void disableSystemVersioning(DdlBuffer apply, String tableName) {
|
||||
disableSystemVersioning(apply, tableName, false);
|
||||
apply.append("alter table ").append(tableName).append(" drop system versioning").endOfStatement();
|
||||
}
|
||||
|
||||
public void disableSystemVersioning(DdlBuffer apply, String tableName, boolean uniqueStatement) {
|
||||
apply.append("alter table ").append(tableName).append(" drop system versioning");
|
||||
if (uniqueStatement) {
|
||||
// needed for the DB migration test to prevent the statement from being filtered
|
||||
// out as a duplicate
|
||||
apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */");
|
||||
}
|
||||
apply.endOfStatement();
|
||||
}
|
||||
|
||||
public void enableSystemVersioning(DdlBuffer apply, String tableName, String historyTableName, boolean validated,
|
||||
boolean uniqueStatement) {
|
||||
apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(historyTableName);
|
||||
public void enableSystemVersioning(DdlBuffer apply, String tableName, boolean validated) {
|
||||
apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(tableName).append(historySuffix);
|
||||
if (!validated) {
|
||||
apply.append(" not validated");
|
||||
}
|
||||
if (uniqueStatement) {
|
||||
// needed for the DB migration test to prevent the statement from being filtered
|
||||
// out as a duplicate
|
||||
apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */");
|
||||
}
|
||||
apply.endOfStatement();
|
||||
}
|
||||
|
||||
public boolean isSystemVersioningEnabled(String tableName) {
|
||||
return !createdHistoryTables.containsKey(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.PropertiesWrapper;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.Column;
|
||||
import io.ebeaninternal.dbmigration.migration.DropColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class HanaTableDdl extends BaseTableDdl {
|
||||
|
||||
private final HanaHistoryDdl historyDdl;
|
||||
private final boolean generateUniqueDdl;
|
||||
|
||||
public HanaTableDdl(DatabaseConfig config, PlatformDdl platformDdl) {
|
||||
super(config, platformDdl);
|
||||
this.historyDdl = (HanaHistoryDdl) platformDdl.historyDdl;
|
||||
if (config.getProperties() != null) {
|
||||
PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "hana", config.getProperties(), config.getClassLoadConfig());
|
||||
this.generateUniqueDdl = wrapper.getBoolean("generateUniqueDdl", false);
|
||||
} else {
|
||||
this.generateUniqueDdl = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) {
|
||||
// done in alterColumnBaseAttributes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AddColumn addColumn) {
|
||||
String tableName = addColumn.getTableName();
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table == null) {
|
||||
super.generate(writer, addColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
historyDdl.disableSystemVersioning(writer.apply(), table.getName(), this.generateUniqueDdl);
|
||||
}
|
||||
|
||||
super.generate(writer, addColumn);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
// make same changes to the history table
|
||||
String historyTable = historyTable(tableName);
|
||||
List<Column> columns = addColumn.getColumn();
|
||||
for (Column column : columns) {
|
||||
alterTableAddColumn(writer.apply(), historyTable, column, true, true);
|
||||
}
|
||||
|
||||
historyDdl.enableSystemVersioning(writer.apply(), table.getName(), historyTable, false, this.generateUniqueDdl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AlterColumn alterColumn) {
|
||||
String tableName = alterColumn.getTableName();
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table == null) {
|
||||
super.generate(writer, alterColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl);
|
||||
}
|
||||
|
||||
super.generate(writer, alterColumn);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
// make same changes to the history table
|
||||
String historyTable = historyTable(tableName);
|
||||
if (hasValue(alterColumn.getType()) || hasValue(alterColumn.getDefaultValue()) || alterColumn.isNotnull() != null) {
|
||||
AlterColumn alterHistoryColumn = new AlterColumn();
|
||||
alterHistoryColumn.setTableName(historyTable);
|
||||
alterHistoryColumn.setColumnName(alterColumn.getColumnName());
|
||||
alterHistoryColumn.setType(alterColumn.getType());
|
||||
alterHistoryColumn.setDefaultValue(alterColumn.getDefaultValue());
|
||||
alterHistoryColumn.setNotnull(alterColumn.isNotnull());
|
||||
alterHistoryColumn.setCurrentType(alterColumn.getCurrentType());
|
||||
alterHistoryColumn.setCurrentDefaultValue(alterColumn.getCurrentDefaultValue());
|
||||
alterHistoryColumn.setCurrentNotnull(alterColumn.isCurrentNotnull());
|
||||
String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
|
||||
|
||||
// write the apply to history table
|
||||
writer.apply().append(histColumnDdl).endOfStatement();
|
||||
}
|
||||
|
||||
historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropColumn dropColumn) {
|
||||
String tableName = dropColumn.getTableName();
|
||||
MTable table = writer.getTable(tableName);
|
||||
if (table == null) {
|
||||
super.generate(writer, dropColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl);
|
||||
}
|
||||
|
||||
super.generate(writer, dropColumn);
|
||||
|
||||
if (manageSystemVersioning) {
|
||||
// also drop from the history table
|
||||
String historyTable = historyTable(tableName);
|
||||
alterTableDropColumn(writer.apply(), historyTable, dropColumn.getColumnName());
|
||||
|
||||
historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bean holding comments relating to a history table that needs to have it's
|
||||
* associated triggers/function updated due to columns added/dropped/included
|
||||
* or excluded.
|
||||
*/
|
||||
public class HistoryTableUpdate {
|
||||
|
||||
/**
|
||||
* Column change type.
|
||||
*/
|
||||
public enum Change {
|
||||
ADD,
|
||||
DROP,
|
||||
INCLUDE,
|
||||
EXCLUDE,
|
||||
ALTER
|
||||
}
|
||||
|
||||
private static class Column {
|
||||
|
||||
final Change change;
|
||||
|
||||
final String column;
|
||||
|
||||
public Column(Change change, String column) {
|
||||
this.change = change;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description();
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return change.name().toLowerCase() + " " + column;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final String baseTable;
|
||||
|
||||
private final List<Column> columnChanges = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Construct with a given base table name.
|
||||
*/
|
||||
public HistoryTableUpdate(String baseTable) {
|
||||
this.baseTable = baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of the changes that cause the history trigger/function
|
||||
* to be regenerated (added, included, excluded and dropped columns).
|
||||
*/
|
||||
public String description() {
|
||||
return columnChanges.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment for column added, dropped, included or excluded.
|
||||
*/
|
||||
public void add(Change change, String column) {
|
||||
columnChanges.add(new Column(change, column));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base table name.
|
||||
*/
|
||||
public String getBaseTable() {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
}
|
||||
+15
-7
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
@@ -12,9 +13,11 @@ import io.ebeaninternal.dbmigration.model.MTable;
|
||||
*/
|
||||
public class MariaDbHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
private PlatformDdl platformDdl;
|
||||
|
||||
@Override
|
||||
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
|
||||
// do nothing
|
||||
this.platformDdl = platformDdl;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -24,8 +27,7 @@ public class MariaDbHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
private void enableSystemVersioning(DdlWrite writer, String baseTable) {
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
apply.append("alter table ").append(baseTable).append(" add system versioning").endOfStatement();
|
||||
platformDdl.alterTable(writer, baseTable).append("add system versioning", null);
|
||||
|
||||
DdlBuffer drop = writer.dropAll();
|
||||
drop.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
|
||||
@@ -34,8 +36,7 @@ public class MariaDbHistoryDdl implements PlatformHistoryDdl {
|
||||
@Override
|
||||
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
|
||||
String baseTable = dropHistoryTable.getBaseTable();
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
apply.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
|
||||
platformDdl.alterTable(writer, baseTable).append("drop system versioning", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,7 +46,14 @@ public class MariaDbHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) {
|
||||
// do nothing
|
||||
public void updateTriggers(DdlWrite writer, String tableName) {
|
||||
MTable table = writer.getTable(tableName);
|
||||
// For MariaDB we need to enable system_versioning_alter_history only once
|
||||
// per DDL script. This info is stored in the virtual "__$HISTORY_FLAG__" table
|
||||
DdlAlterTable history = platformDdl.alterTable(writer, "__$HISTORY_FLAG__");
|
||||
if (table != null && table.isWithHistory() && !history.isHistoryHandled()) {
|
||||
writer.apply().appendStatement("SET @@system_versioning_alter_history = 1");
|
||||
history.setHistoryHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-63
@@ -3,11 +3,10 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.Column;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* MySql specific DDL.
|
||||
*/
|
||||
@@ -21,7 +20,7 @@ public class MySqlDdl extends PlatformDdl {
|
||||
|
||||
public MySqlDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.alterColumn = "modify";
|
||||
this.alterColumn = "alter";
|
||||
this.dropUniqueConstraint = "drop index";
|
||||
this.historyDdl = new MySqlHistoryDdl();
|
||||
this.inlineComments = true;
|
||||
@@ -37,11 +36,11 @@ public class MySqlDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alterTableDropColumn(final DdlBuffer buffer, final String tableName, final String columnName) {
|
||||
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
|
||||
if (this.useMigrationStoredProcedures) {
|
||||
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')").endOfStatement();
|
||||
alterTable(writer, tableName).raw("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')");
|
||||
} else {
|
||||
super.alterTableDropColumn(buffer, tableName, columnName);
|
||||
super.alterTableDropColumn(writer, tableName, columnName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,38 +90,31 @@ public class MySqlDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue);
|
||||
return "alter table " + tableName + " alter " + columnName + " " + suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnBaseAttributes(AlterColumn alter) {
|
||||
if (alter.getType() == null && alter.isNotnull() == null) {
|
||||
// No type change or notNull change
|
||||
// defaultValue change already handled in alterColumnDefaultValue
|
||||
return null;
|
||||
}
|
||||
public void alterColumn(DdlWrite writer, AlterColumn alter) {
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
|
||||
return "alter table " + tableName + " modify " + columnName + " " + type + notnullClause;
|
||||
if (alter.getType() == null && alter.isNotnull() == null) {
|
||||
// No type change or notNull change -> handle default value change
|
||||
if (hasValue(alter.getDefaultValue())) {
|
||||
alterColumnDefault(writer, alter);
|
||||
}
|
||||
} else {
|
||||
// we must regenerate whole statement -> read altered and current value
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String defaultValue = alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue();
|
||||
|
||||
DdlBuffer buffer = alterTable(writer, tableName).append("modify", columnName);
|
||||
buffer.append(type);
|
||||
if (notnull) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
if (hasValue(defaultValue) && !DdlHelp.isDropDefault(defaultValue)) {
|
||||
buffer.append(" default ").append(convertDefaultValue(defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,32 +154,4 @@ public class MySqlDdl extends PlatformDdl {
|
||||
// alter comment currently not supported as it requires to repeat whole column definition
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Locks all tables for triggers that have to be updated.
|
||||
*/
|
||||
@Override
|
||||
public void lockTables(DdlBuffer buffer, Collection<String> tables) {
|
||||
if (!tables.isEmpty()) {
|
||||
buffer.append("lock tables ");
|
||||
int i = 0;
|
||||
for (String table : tables) {
|
||||
if (i > 0) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
buffer.append(table).append(" write");
|
||||
i++;
|
||||
}
|
||||
buffer.endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks all tables for triggers that have to be updated.
|
||||
*/
|
||||
@Override
|
||||
public void unlockTables(DdlBuffer buffer, Collection<String> tables) {
|
||||
buffer.append("unlock tables").endOfStatement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-26
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
/**
|
||||
* MySql history support using DB triggers to maintain a history table.
|
||||
@@ -18,49 +18,36 @@ public class MySqlHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
buffer.append("drop trigger ").append(deleteTriggerName(baseTable)).endOfStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTriggers(DdlWrite writer, MTable table) {
|
||||
|
||||
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
|
||||
|
||||
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
|
||||
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHistoryTriggers(DbTriggerUpdate update) {
|
||||
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
|
||||
|
||||
recreateHistoryView(update);
|
||||
buffer.append("lock tables ").append(baseTable).append(" write").endOfStatement();
|
||||
addBeforeUpdate(buffer, updateTriggerName(baseTable), baseTable, columnNames);
|
||||
addBeforeDelete(buffer, deleteTriggerName(baseTable), baseTable, columnNames);
|
||||
buffer.appendStatement("unlock tables");
|
||||
|
||||
DdlBuffer buffer = update.historyTriggerBuffer();
|
||||
String baseTable = update.getBaseTable();
|
||||
|
||||
dropTriggers(buffer, baseTable);
|
||||
addBeforeUpdate(updateTriggerName(baseTable), update);
|
||||
addBeforeDelete(deleteTriggerName(baseTable), update);
|
||||
}
|
||||
|
||||
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) {
|
||||
private void addBeforeUpdate(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
apply
|
||||
.append("delimiter $$").newLine()
|
||||
.append("create trigger ").append(triggerName).append(" before update on ").append(update.getBaseTable())
|
||||
.append("create trigger ").append(triggerName).append(" before update on ").append(tableName)
|
||||
.append(" for each row begin").newLine();
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
appendInsertIntoHistory(apply, tableName, columnNames);
|
||||
apply
|
||||
.append(" set NEW.").append(sysPeriod).append("_start = now(6)").endOfStatement()
|
||||
.append("end$$").newLine();
|
||||
}
|
||||
|
||||
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) {
|
||||
private void addBeforeDelete(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
apply
|
||||
.append("delimiter $$").newLine()
|
||||
.append("create trigger ").append(triggerName).append(" before delete on ").append(update.getBaseTable())
|
||||
.append("create trigger ").append(triggerName).append(" before delete on ").append(tableName)
|
||||
.append(" for each row begin").newLine();
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
appendInsertIntoHistory(apply, tableName, columnNames);
|
||||
apply.append("end$$").newLine();
|
||||
}
|
||||
|
||||
|
||||
-4
@@ -32,8 +32,4 @@ public class NoHistorySupportDdl implements PlatformHistoryDdl {
|
||||
// does nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, HistoryTableUpdate update) {
|
||||
// does nothing
|
||||
}
|
||||
}
|
||||
|
||||
+14
-29
@@ -1,8 +1,9 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
/**
|
||||
* NuoDB history support using DB triggers to maintain a history table.
|
||||
@@ -22,48 +23,32 @@ public class NuoDbHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTriggers(DdlWrite writer, MTable table) {
|
||||
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
|
||||
|
||||
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
|
||||
|
||||
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
|
||||
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
|
||||
addBeforeUpdate(buffer, updateTriggerName(baseTable), baseTable, columnNames);
|
||||
addBeforeDelete(buffer, deleteTriggerName(baseTable), baseTable, columnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHistoryTriggers(DbTriggerUpdate update) {
|
||||
private void addBeforeUpdate(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
|
||||
|
||||
recreateHistoryView(update);
|
||||
addTriggerStart(triggerName, tableName, apply, " before update for each row as ");
|
||||
|
||||
DdlBuffer buffer = update.historyTriggerBuffer();
|
||||
String baseTable = update.getBaseTable();
|
||||
|
||||
dropTriggers(buffer, baseTable);
|
||||
addBeforeUpdate(updateTriggerName(baseTable), update);
|
||||
addBeforeDelete(deleteTriggerName(baseTable), update);
|
||||
}
|
||||
|
||||
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
addTriggerStart(triggerName, update, apply, " before update for each row as ");
|
||||
apply.append(" NEW.sys_period_start = greatest(current_timestamp, date_add(OLD.sys_period_start, interval 1 microsecond))").endOfStatement();
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
appendInsertIntoHistory(apply, tableName, columnNames);
|
||||
addEndTrigger(apply);
|
||||
}
|
||||
|
||||
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) {
|
||||
private void addBeforeDelete(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
addTriggerStart(triggerName, update, apply, " before delete for each row as");
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
addTriggerStart(triggerName, tableName, apply, " before delete for each row as");
|
||||
appendInsertIntoHistory(apply, tableName, columnNames);
|
||||
addEndTrigger(apply);
|
||||
}
|
||||
|
||||
private void addTriggerStart(String triggerName, DbTriggerUpdate update, DdlBuffer apply, String s) {
|
||||
private void addTriggerStart(String triggerName, String baseTable, DdlBuffer apply, String s) {
|
||||
apply
|
||||
.append("delimiter $$").newLine()
|
||||
.append("create or replace trigger ").append(triggerName).append(" for ").append(update.getBaseTable())
|
||||
.append("create or replace trigger ").append(triggerName).append(" for ").append(baseTable)
|
||||
.append(s).newLine();
|
||||
}
|
||||
|
||||
|
||||
+72
-64
@@ -18,7 +18,6 @@ import io.ebeaninternal.dbmigration.migration.Column;
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -77,16 +76,12 @@ public class PlatformDdl {
|
||||
|
||||
protected String alterColumn = "alter column";
|
||||
|
||||
protected String alterColumnSuffix = "";
|
||||
|
||||
protected String dropUniqueConstraint = "drop constraint";
|
||||
|
||||
protected String addConstraint = "add constraint";
|
||||
|
||||
protected String addColumn = "add column";
|
||||
|
||||
protected String addColumnSuffix = "";
|
||||
|
||||
protected String columnSetType = "";
|
||||
|
||||
protected String columnSetDefault = "set default";
|
||||
@@ -97,14 +92,14 @@ public class PlatformDdl {
|
||||
|
||||
protected String columnSetNull = "set null";
|
||||
|
||||
protected String columnNotNull = "not null";
|
||||
|
||||
protected String updateNullWithDefault = "update ${table} set ${column} = ${default} where ${column} is null";
|
||||
|
||||
protected String createTable = "create table";
|
||||
|
||||
protected String dropColumn = "drop column";
|
||||
|
||||
protected String dropColumnSuffix = "";
|
||||
|
||||
protected String addForeignKeySkipCheck = "";
|
||||
|
||||
protected String uniqueIndex = "unique";
|
||||
@@ -272,20 +267,13 @@ public class PlatformDdl {
|
||||
}
|
||||
}
|
||||
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
|
||||
writeColumnNotNull(buffer);
|
||||
buffer.appendWithSpace(columnNotNull);
|
||||
}
|
||||
|
||||
// add check constraints later as we really want to give them a nice name
|
||||
// so that the database can potentially provide a nice SQL error
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for platform overriding (e.g. ClickHouse).
|
||||
*/
|
||||
protected void writeColumnNotNull(DdlBuffer buffer) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the check constraint.
|
||||
*/
|
||||
@@ -375,8 +363,8 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Regenerate the history triggers (or function) due to a column being added/dropped/excluded or included.
|
||||
*/
|
||||
public void regenerateHistoryTriggers(DdlWrite writer, HistoryTableUpdate update) {
|
||||
historyDdl.updateTriggers(writer, update);
|
||||
public void regenerateHistoryTriggers(DdlWrite writer, String tableName) {
|
||||
historyDdl.updateTriggers(writer, tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,13 +526,11 @@ public class PlatformDdl {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, String defaultValue) {
|
||||
public void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, String defaultValue) {
|
||||
|
||||
String convertedType = convert(column.getType());
|
||||
|
||||
buffer.append("alter table ").append(tableName)
|
||||
.append(" ").append(addColumn).append(" ").append(column.getName())
|
||||
.append(" ").append(convertedType);
|
||||
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, column.getName());
|
||||
buffer.append(convertedType);
|
||||
|
||||
// Add default value also to history table if it is not excluded
|
||||
if (defaultValue != null) {
|
||||
@@ -556,28 +542,35 @@ public class PlatformDdl {
|
||||
|
||||
if (!onHistoryTable) {
|
||||
if (isTrue(column.isNotnull())) {
|
||||
writeColumnNotNull(buffer);
|
||||
buffer.appendWithSpace(columnNotNull);
|
||||
}
|
||||
buffer.append(addColumnSuffix);
|
||||
buffer.endOfStatement();
|
||||
|
||||
// check constraints cannot be added in one statement for h2
|
||||
if (!StringHelper.isNull(column.getCheckConstraint())) {
|
||||
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint());
|
||||
if (hasValue(ddl)) {
|
||||
buffer.append(ddl).endOfStatement();
|
||||
}
|
||||
writer.applyPostAlter().appendStatement(ddl);
|
||||
}
|
||||
} else {
|
||||
buffer.append(addColumnSuffix);
|
||||
buffer.endOfStatement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) {
|
||||
buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName)
|
||||
.append(dropColumnSuffix).endOfStatement();
|
||||
/**
|
||||
* This method is used from DbTriggerBasedHistoryDdl to add the sysPeriodColumns.
|
||||
*/
|
||||
public void alterTableAddColumn(DdlWrite writer, String tableName, String columnName, String columnType, String defaultValue) {
|
||||
|
||||
String convertedType = convert(columnType);
|
||||
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, columnName);
|
||||
buffer.append(convertedType);
|
||||
|
||||
if (defaultValue != null) {
|
||||
buffer.append(" default ");
|
||||
buffer.append(defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
|
||||
alterTable(writer, tableName).append(dropColumn, columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -592,22 +585,27 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Alter a column type.
|
||||
* <p>
|
||||
* Note that that MySql and SQL Server instead use alterColumnBaseAttributes()
|
||||
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type) + alterColumnSuffix;
|
||||
protected void alterColumnType(DdlWrite writer, AlterColumn alter) {
|
||||
alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName())
|
||||
.append(columnSetType).append(convert(alter.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a column adding or removing the not null constraint.
|
||||
* <p>
|
||||
* Note that that MySql, SQL Server, and HANA instead use alterColumnBaseAttributes()
|
||||
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
String suffix = notnull ? columnSetNotnull : columnSetNull;
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix;
|
||||
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) {
|
||||
DdlBuffer buffer = alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName());
|
||||
if (Boolean.TRUE.equals(alter.isNotnull())) {
|
||||
buffer.append(columnSetNotnull);
|
||||
} else {
|
||||
buffer.append(columnSetNull);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,22 +617,46 @@ public class PlatformDdl {
|
||||
|
||||
/**
|
||||
* Alter column setting the default value.
|
||||
* <p>
|
||||
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue);
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix;
|
||||
protected void alterColumnDefault(DdlWrite writer, AlterColumn alter) {
|
||||
DdlBuffer buffer = alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName());
|
||||
if (DdlHelp.isDropDefault(alter.getDefaultValue())) {
|
||||
buffer.append(columnDropDefault);
|
||||
} else {
|
||||
buffer.append(columnSetDefault).appendWithSpace(convertDefaultValue(alter.getDefaultValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter column setting both the type and not null constraint.
|
||||
* Alter column setting (type, default value and not null constraint).
|
||||
* <p>
|
||||
* Used by MySql, SQL Server, and HANA as these require both column attributes to be set together.
|
||||
* Used by MySql, SQL Server, and HANA as these require all column attributes to
|
||||
* be set together.
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnBaseAttributes(AlterColumn alter) {
|
||||
// by default do nothing, only used by mysql, sql server, and HANA as they can only
|
||||
// modify the column with the full column definition
|
||||
return null;
|
||||
public void alterColumn(DdlWrite writer, AlterColumn alter) {
|
||||
|
||||
if (hasValue(alter.getType())) {
|
||||
alterColumnType(writer, alter);
|
||||
}
|
||||
|
||||
if (hasValue(alter.getDefaultValue())) {
|
||||
alterColumnDefault(writer, alter);
|
||||
}
|
||||
|
||||
if (alter.isNotnull() != null) {
|
||||
alterColumnNotnull(writer, alter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or replace a new DdlAlterTable for given tableName.
|
||||
*/
|
||||
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
|
||||
return writer.applyAlterTable(tableName, BaseAlterTableWrite::new);
|
||||
}
|
||||
|
||||
protected void appendColumns(String[] columns, StringBuilder buffer) {
|
||||
@@ -757,20 +779,6 @@ public class PlatformDdl {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mysql-specific: Locks all tables for triggers that have to be updated.
|
||||
*/
|
||||
public void lockTables(DdlBuffer buffer, Collection<String> tables) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Mysql-specific: Unlocks all tables for triggers that have to be updated.
|
||||
*/
|
||||
public void unlockTables(DdlBuffer buffer, Collection<String> tables) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database-specific "create table" command prefix. For HANA this is
|
||||
* either "create column table" or "create row table", for all other databases
|
||||
|
||||
+14
-2
@@ -32,7 +32,19 @@ public interface PlatformHistoryDdl {
|
||||
void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable);
|
||||
|
||||
/**
|
||||
* Regenerate the history triggers/stored function due to column added/dropped/included or excluded.
|
||||
* Returns true, if alters on the live tables should be applied also to the history tables. This is required for DbTriggerBased
|
||||
* histories or on platforms like Hana, which are not SQL2011 history compatible (at least from DDL perspective)
|
||||
*/
|
||||
void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable);
|
||||
default boolean alterHistoryTables() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate the history triggers/stored function due to column added/dropped/included or excluded.
|
||||
*
|
||||
* Note: This function may be called multiple times for the same table.
|
||||
*/
|
||||
default void updateTriggers(DdlWrite writer, String tableName) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -2,6 +2,8 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
|
||||
/**
|
||||
* Postgres specific DDL.
|
||||
@@ -56,7 +58,10 @@ public class PostgresDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
return super.alterColumnType(tableName, columnName, type) + " using " + columnName + "::" + convert(type);
|
||||
protected void alterColumnType(DdlWrite writer, AlterColumn alter) {
|
||||
String type = convert(alter.getType());
|
||||
alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName())
|
||||
.append(columnSetType).append(type)
|
||||
.append(" using ").append(alter.getColumnName()).append("::").append(type);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-30
@@ -29,14 +29,11 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
* Use Postgres range type rather than start and end timestamps.
|
||||
*/
|
||||
@Override
|
||||
protected void addSysPeriodColumns(DdlBuffer apply, String baseTableName, String whenCreatedColumn) {
|
||||
apply
|
||||
.append("alter table ").append(baseTableName)
|
||||
.append(" add column ").append(sysPeriod).append(" tstzrange not null default tstzrange(").append(now).append(", null)")
|
||||
.endOfStatement();
|
||||
|
||||
protected void addSysPeriodColumns(DdlWrite writer, String baseTableName, String whenCreatedColumn) {
|
||||
platformDdl.alterTableAddColumn(writer, baseTableName, sysPeriod, "tstzrange not null", "tstzrange(" + now + ", null)");
|
||||
if (whenCreatedColumn != null) {
|
||||
apply.append("update ").append(baseTableName).append(" set ")
|
||||
writer.applyPostAlter()
|
||||
.append("update ").append(baseTableName).append(" set ")
|
||||
.append(sysPeriod).append(" = tstzrange(").append(whenCreatedColumn).append(", null)").endOfStatement();
|
||||
}
|
||||
}
|
||||
@@ -47,18 +44,16 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropSysPeriodColumns(DdlBuffer buffer, String baseTableName) {
|
||||
buffer.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriod).endOfStatement();
|
||||
protected void dropSysPeriodColumns(DdlWrite writer, String baseTableName) {
|
||||
platformDdl.alterTableDropColumn(writer, baseTableName, sysPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTriggers(DdlWrite writer, MTable table) {
|
||||
String baseTableName = table.getName();
|
||||
protected void createTriggers(DdlBuffer buffer, String baseTableName, List<String> columnNames) {
|
||||
String procedureName = procedureName(baseTableName);
|
||||
String triggerName = triggerName(baseTableName);
|
||||
|
||||
DdlBuffer apply = writer.applyHistoryTrigger();
|
||||
apply
|
||||
createOrReplaceFunction(buffer, procedureName, historyTableName(baseTableName), columnNames);
|
||||
buffer
|
||||
.append("create trigger ").append(triggerName).newLine()
|
||||
.append(" before update or delete on ").append(baseTableName).newLine()
|
||||
.append(" for each row execute procedure ").append(procedureName).append("();").newLine().newLine();
|
||||
@@ -103,22 +98,6 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
apply.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createStoredFunction(DdlWrite writer, MTable table) {
|
||||
String procedureName = procedureName(table.getName());
|
||||
String historyTable = historyTableName(table.getName());
|
||||
|
||||
List<String> columnNames = columnNamesForApply(table);
|
||||
createOrReplaceFunction(writer.applyHistoryTrigger(), procedureName, historyTable, columnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHistoryTriggers(DbTriggerUpdate update) {
|
||||
String procedureName = procedureName(update.getBaseTable());
|
||||
recreateHistoryView(update);
|
||||
createOrReplaceFunction(update.historyTriggerBuffer(), procedureName, update.getHistoryTable(), update.getColumns());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendInsertIntoHistory(DdlBuffer buffer, String historyTable, List<String> columns) {
|
||||
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriod).append(",");
|
||||
|
||||
+25
-10
@@ -1,8 +1,13 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
|
||||
/**
|
||||
* SQLite platform specific DDL.
|
||||
@@ -59,18 +64,28 @@ public class SQLiteDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
return "-- not supported: " + super.alterColumnDefaultValue(tableName, columnName, defaultValue);
|
||||
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
|
||||
return writer.applyAlterTable(tableName, SQLiteAlterTableWrite::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
return "-- not supported: " + super.alterColumnType(tableName, columnName, type);
|
||||
}
|
||||
static class SQLiteAlterTableWrite extends BaseAlterTableWrite {
|
||||
public SQLiteAlterTableWrite(String tableName) {
|
||||
super(tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
return "-- not supported: " + super.alterColumnNotnull(tableName, columnName, notnull);
|
||||
@Override
|
||||
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
|
||||
List<AlterCmd> ret = new ArrayList<AlterCmd>();
|
||||
for (AlterCmd cmd : cmds) {
|
||||
switch (cmd.getOperation()) {
|
||||
case "alter column":
|
||||
ret.add(newRawCommand("-- not supported: " + cmd));
|
||||
break;
|
||||
default:
|
||||
ret.add(cmd);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+67
-54
@@ -11,6 +11,12 @@ import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
*/
|
||||
public class SqlServerDdl extends PlatformDdl {
|
||||
|
||||
private static final String CONSTRAINT = "C";
|
||||
private static final String UNIQUE_CONSTRAINT = "UQ";
|
||||
private static final String USER_TABLE = "U";
|
||||
private static final String FOREIGN_KEY = "F";
|
||||
private static final String SEQUENCE_OBJECT = "SO";
|
||||
|
||||
public SqlServerDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.identitySuffix = " identity(1,1)";
|
||||
@@ -31,12 +37,7 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
|
||||
@Override
|
||||
public String dropTable(String tableName) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("IF OBJECT_ID('");
|
||||
buffer.append(tableName);
|
||||
buffer.append("', 'U') IS NOT NULL drop table ");
|
||||
buffer.append(tableName);
|
||||
return buffer.toString();
|
||||
return ifObjectExists(tableName, USER_TABLE) + "drop table " + tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,12 +47,12 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
if (pos != -1) {
|
||||
objectId = tableName.substring(0, pos + 1) + fkName;
|
||||
}
|
||||
return "IF OBJECT_ID('" + objectId + "', 'F') IS NOT NULL " + super.alterTableDropForeignKey(tableName, fkName);
|
||||
return ifObjectExists(objectId, FOREIGN_KEY) + super.alterTableDropForeignKey(tableName, fkName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropSequence(String sequenceName) {
|
||||
return "IF OBJECT_ID('" + sequenceName + "', 'SO') IS NOT NULL drop sequence " + sequenceName;
|
||||
return ifObjectExists(sequenceName, SEQUENCE_OBJECT) + "drop sequence " + sequenceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,12 +72,11 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// issues#233
|
||||
String start = "create unique nonclustered index " + uqName + " on " + tableName + "(";
|
||||
StringBuilder sb = new StringBuilder(start);
|
||||
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
sb.append("create unique nonclustered index ").append(uqName).append(" on ").append(tableName).append('(');
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(columns[i]);
|
||||
}
|
||||
@@ -91,11 +91,9 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
|
||||
@Override
|
||||
public String alterTableDropConstraint(String tableName, String constraintName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("IF (OBJECT_ID('").append(constraintName).append("', 'C') IS NOT NULL) ");
|
||||
sb.append(super.alterTableDropConstraint(tableName, constraintName));
|
||||
return sb.toString();
|
||||
return ifObjectExists(maxConstraintName(constraintName), CONSTRAINT) + super.alterTableDropConstraint(tableName, constraintName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a unique constraint from the table (Sometimes this is an index).
|
||||
*/
|
||||
@@ -103,10 +101,12 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(dropIndex(uniqueConstraintName, tableName)).append(";\n");
|
||||
sb.append("IF (OBJECT_ID('").append(maxConstraintName(uniqueConstraintName)).append("', 'UQ') IS NOT NULL) ");
|
||||
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
|
||||
|
||||
sb.append(ifObjectExists(maxConstraintName(uniqueConstraintName), UNIQUE_CONSTRAINT))
|
||||
.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and return the create sequence DDL.
|
||||
*/
|
||||
@@ -133,50 +133,53 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
|
||||
protected void alterColumnDefault(DdlWrite writer, AlterColumn alter) {
|
||||
// Unfortunately, the SqlServer creates default values with a random name.
|
||||
// You can specify a name in DDL, but this does not work in conjunction with
|
||||
// temporal tables in certain cases. So we have to delete the constraint with
|
||||
// a rather complex statement.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (DdlHelp.isDropDefault(defaultValue)) {
|
||||
sb.append("EXEC usp_ebean_drop_default_constraint ").append(tableName).append(", ").append(columnName);
|
||||
} else {
|
||||
sb.append("alter table ").append(tableName);
|
||||
sb.append(" add default ").append(convertDefaultValue(defaultValue)).append(" for ").append(columnName);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnBaseAttributes(AlterColumn alter) {
|
||||
if (alter.getType() == null && alter.isNotnull() == null) {
|
||||
// No type change or notNull change
|
||||
// defaultValue change already handled in alterColumnDefaultValue
|
||||
return null;
|
||||
}
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + type + notnullClause;
|
||||
String defaultValue = alter.getDefaultValue();
|
||||
if (DdlHelp.isDropDefault(defaultValue)) {
|
||||
execUspDropDefaultConstraint(writer, tableName, columnName);
|
||||
} else {
|
||||
execUspDropDefaultConstraint(writer, tableName, columnName);
|
||||
setDefaultValue(writer, tableName, columnName, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
public void alterColumn(DdlWrite writer, AlterColumn alter) {
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
if (alter.getType() == null && alter.isNotnull() == null) {
|
||||
// No type change or notNull change
|
||||
if (hasValue(alter.getDefaultValue())) {
|
||||
alterColumnDefault(writer, alter);
|
||||
}
|
||||
} else {
|
||||
// we must regenerate whole statement -> read altered and current value
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String defaultValue = alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue();
|
||||
if (hasValue(defaultValue)) {
|
||||
// default value present -> drop default constraint before altering
|
||||
execUspDropDefaultConstraint(writer, tableName, columnName);
|
||||
}
|
||||
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
}
|
||||
DdlBuffer buffer = alterTable(writer, tableName).append(alterColumn, columnName);
|
||||
buffer.append(type);
|
||||
if (notnull) {
|
||||
buffer.append(" not null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
|
||||
// can't alter itself - done in alterColumnBaseAttributes()
|
||||
return null;
|
||||
// re add - default constraint
|
||||
if (hasValue(defaultValue) && !DdlHelp.isDropDefault(defaultValue)) {
|
||||
setDefaultValue(writer, tableName, columnName, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,9 +205,8 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
* (constraints, default values, indices and foreign keys). That's why we call a user stored procedure here
|
||||
*/
|
||||
@Override
|
||||
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) {
|
||||
|
||||
buffer.append("EXEC usp_ebean_drop_column ").append(tableName).append(", ").append(columnName).endOfStatement();
|
||||
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
|
||||
alterTable(writer, tableName).raw("EXEC usp_ebean_drop_column ").append(tableName).append(", ").append(columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,4 +248,15 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
.endOfStatement();
|
||||
}
|
||||
|
||||
public static String ifObjectExists(String object, String objectType) {
|
||||
return "IF OBJECT_ID('" + object + "', '" + objectType + "') IS NOT NULL ";
|
||||
}
|
||||
|
||||
private void execUspDropDefaultConstraint(DdlWrite writer, String tableName, String columnName) {
|
||||
alterTable(writer, tableName).raw("EXEC usp_ebean_drop_default_constraint " + tableName + ", " + columnName);
|
||||
}
|
||||
|
||||
private void setDefaultValue(DdlWrite writer, String tableName, String columnName, String defaultValue) {
|
||||
alterTable(writer, tableName).append("add default " + convertDefaultValue(defaultValue) + " for", columnName);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-20
@@ -1,9 +1,11 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
@@ -42,7 +44,7 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
private void enableSystemVersioning(DdlWrite writer, String baseTable) {
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
DdlBuffer apply = writer.applyPostAlter();
|
||||
apply.append("alter table ").append(baseTable).newLine()
|
||||
.append(" add ").append(systemPeriodStart).append(" datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(),").newLine()
|
||||
.append(" ").append(systemPeriodEnd).append(" datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999',").newLine()
|
||||
@@ -59,20 +61,25 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
|
||||
@Override
|
||||
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
|
||||
String baseTable = dropHistoryTable.getBaseTable();
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
apply.append("-- dropping history support for ").append(baseTable).endOfStatement();
|
||||
// drop default constraints
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName(baseTable);
|
||||
alter.setDefaultValue(DdlHelp.DROP_DEFAULT);
|
||||
alter.setColumnName(systemPeriodStart);
|
||||
platformDdl.alterColumn(writer, alter);
|
||||
alter.setColumnName(systemPeriodEnd);
|
||||
platformDdl.alterColumn(writer, alter);
|
||||
|
||||
apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodStart, DdlHelp.DROP_DEFAULT)).endOfStatement();
|
||||
apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodEnd, DdlHelp.DROP_DEFAULT)).endOfStatement();
|
||||
// switch of versioning & period
|
||||
// switch of versioning & period - must be done before altering
|
||||
DdlBuffer apply = writer.apply();
|
||||
apply.append("-- dropping history support for ").append(baseTable).endOfStatement();
|
||||
apply.append("alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
|
||||
apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement();
|
||||
// now drop tables & columns
|
||||
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodStart).endOfStatement();
|
||||
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodEnd).endOfStatement();
|
||||
apply.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
|
||||
apply.end();
|
||||
// now drop tables & columns, they will go to alter table/post alter buffers
|
||||
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodStart);
|
||||
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodEnd);
|
||||
writer.applyPostAlter().appendStatement(platformDdl.dropTable(baseTable + "_history"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,15 +89,19 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) {
|
||||
// SQL Server 2016 does not need triggers
|
||||
DdlBuffer apply = writer.applyHistoryView();
|
||||
String baseTableName = baseTable.getBaseTable();
|
||||
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = off (history_table=")
|
||||
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
|
||||
apply.append("-- history migration goes here").newLine();
|
||||
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = on (history_table=")
|
||||
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
|
||||
|
||||
public void updateTriggers(DdlWrite writer, String tableName) {
|
||||
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
|
||||
writer.getTable(tableName);
|
||||
if (!alter.isHistoryHandled()) {
|
||||
// SQL Server 2016 does not need triggers
|
||||
DdlBuffer apply = writer.apply();
|
||||
apply.append("-- alter table ").append(tableName).append(" set (system_versioning = off (history_table=")
|
||||
.append(getHistoryTable(tableName)).append("))").endOfStatement();
|
||||
apply.append("-- history migration goes here").newLine();
|
||||
apply.append("-- alter table ").append(tableName).append(" set (system_versioning = on (history_table=")
|
||||
.append(getHistoryTable(tableName)).append("))").endOfStatement();
|
||||
}
|
||||
alter.setHistoryHandled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-6
@@ -16,6 +16,7 @@ import io.ebeaninternal.extraddl.model.ExtraDdl;
|
||||
import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
@@ -127,10 +128,13 @@ public class CurrentModel {
|
||||
if (jaxbPresent) {
|
||||
addExtraDdl(ddl, ExtraDdlXmlReader.readBuiltin(), "-- init script ");
|
||||
}
|
||||
ddl.append(writer.apply().getBuffer());
|
||||
ddl.append(writer.applyForeignKeys().getBuffer());
|
||||
ddl.append(writer.applyHistoryView().getBuffer());
|
||||
ddl.append(writer.applyHistoryTrigger().getBuffer());
|
||||
|
||||
try {
|
||||
writer.writeApply(ddl);
|
||||
} catch (IOException e) { // should not happen on StringBuilder
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return ddl.toString();
|
||||
}
|
||||
|
||||
@@ -157,8 +161,11 @@ public class CurrentModel {
|
||||
if (ddlHeader != null && !ddlHeader.isEmpty()) {
|
||||
ddl.append(ddlHeader).append('\n');
|
||||
}
|
||||
ddl.append(writer.dropAllForeignKeys().getBuffer());
|
||||
ddl.append(writer.dropAll().getBuffer());
|
||||
try {
|
||||
writer.writeDropAll(ddl);
|
||||
} catch (IOException e) { // should not happen on StringBuilder
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return ddl.toString();
|
||||
}
|
||||
|
||||
|
||||
+1
-16
@@ -3,7 +3,6 @@ package io.ebeaninternal.dbmigration.model;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.util.IOUtils;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder;
|
||||
@@ -91,21 +90,7 @@ public class PlatformDdlWriter {
|
||||
if (header != null && !header.isEmpty()) {
|
||||
writer.append(header).append('\n');
|
||||
}
|
||||
// merge the apply buffers in the appropriate order
|
||||
prependDropDependencies(writer, ddl.applyDropDependencies());
|
||||
writer.append("-- apply changes\n");
|
||||
writer.append(ddl.apply().getBuffer());
|
||||
writer.append(ddl.applyForeignKeys().getBuffer());
|
||||
writer.append(ddl.applyHistoryView().getBuffer());
|
||||
writer.append(ddl.applyHistoryTrigger().getBuffer());
|
||||
}
|
||||
|
||||
private void prependDropDependencies(Writer writer, DdlBuffer buffer) throws IOException {
|
||||
if (!buffer.isEmpty()) {
|
||||
writer.append("-- drop dependencies\n");
|
||||
writer.append(buffer.getBuffer());
|
||||
writer.append("\n");
|
||||
}
|
||||
ddl.writeApply(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
-41
@@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
private static boolean useV1Syntax = Boolean.getBoolean("ebean.h2.useV1Syntax");
|
||||
|
||||
|
||||
private final DatabaseConfig serverConfig = new DatabaseConfig();
|
||||
|
||||
private DdlHandler handler(DatabasePlatform platform) {
|
||||
@@ -47,15 +47,15 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
DdlWrite writer = new DdlWrite();
|
||||
h2Handler().generate(writer, Helper.getAddColumn());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column added_to_foo varchar(20);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column added_to_foo varchar(20);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
sqlserverHandler().generate(writer, Helper.getAddColumn());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add added_to_foo nvarchar(20);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add added_to_foo nvarchar(20);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
hanaHandler().generate(writer, Helper.getAddColumn());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add ( added_to_foo nvarchar(20));\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add (added_to_foo nvarchar(20));\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,18 +63,17 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
DdlWrite writer = new DdlWrite();
|
||||
h2Handler().generate(writer, Helper.getAlterTableAddColumnWithCheckConstraint());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column status integer;\n"
|
||||
+ "alter table foo add constraint ck_ordering_status check ( status in (0,1));\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column status integer;\n"
|
||||
+ "-- apply post alter\nalter table foo add constraint ck_ordering_status check ( status in (0,1));\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
hanaHandler().generate(writer, Helper.getAlterTableAddColumnWithCheckConstraint());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add ( status integer);\n"
|
||||
+ "alter table foo add constraint ck_ordering_status check ( status in (0,1));\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add (status integer);\n"
|
||||
+ "-- apply post alter\nalter table foo add constraint ck_ordering_status check ( status in (0,1));\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the functionality of the Ebean {@literal @}DbArray extension during DDL
|
||||
* generation.
|
||||
* Test the functionality of the Ebean {@literal @}DbArray extension during DDL generation.
|
||||
*/
|
||||
@Test
|
||||
public void addColumn_dbarray() throws Exception {
|
||||
@@ -84,20 +83,20 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
DdlHandler postgresHandler = postgresHandler();
|
||||
postgresHandler.generate(writer, Helper.getAlterTableAddDbArrayColumn());
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_added_to_foo varchar[];\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_added_to_foo varchar[];\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
|
||||
DdlHandler sqlserverHandler = sqlserverHandler();
|
||||
sqlserverHandler.generate(writer, Helper.getAlterTableAddDbArrayColumn());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add dbarray_added_to_foo varchar(1000);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add dbarray_added_to_foo varchar(1000);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
|
||||
DdlHandler hanaHandler = hanaHandler();
|
||||
hanaHandler.generate(writer, Helper.getAlterTableAddDbArrayColumn());
|
||||
assertThat(writer.apply().getBuffer())
|
||||
.isEqualTo("alter table foo add ( dbarray_added_to_foo nvarchar(255) array);\n\n");
|
||||
assertThat(writer.toString())
|
||||
.isEqualTo("-- apply alter tables\nalter table foo add (dbarray_added_to_foo nvarchar(255) array);\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,24 +105,24 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
DdlWrite writer = new DdlWrite();
|
||||
|
||||
postgresHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnWithLength());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety varchar[];\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_ninety varchar[];\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
h2Handler().generate(writer, Helper.getAlterTableAddDbArrayColumnWithLength());
|
||||
if (useV1Syntax) {
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety array;\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_ninety array;\n");
|
||||
} else {
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety varchar array;\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_ninety varchar array;\n");
|
||||
}
|
||||
|
||||
writer = new DdlWrite();
|
||||
sqlserverHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnWithLength());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add dbarray_ninety varchar(90);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add dbarray_ninety varchar(90);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
hanaHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnWithLength());
|
||||
assertThat(writer.apply().getBuffer())
|
||||
.isEqualTo("alter table foo add ( dbarray_ninety nvarchar(255) array(90));\n\n");
|
||||
assertThat(writer.toString())
|
||||
.isEqualTo("-- apply alter tables\nalter table foo add (dbarray_ninety nvarchar(255) array(90));\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -131,31 +130,31 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
DdlWrite writer = new DdlWrite();
|
||||
postgresHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnIntegerWithLength());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer integer[];\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_integer integer[];\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
h2Handler().generate(writer, Helper.getAlterTableAddDbArrayColumnIntegerWithLength());
|
||||
if (useV1Syntax) {
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer array;\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_integer array;\n");
|
||||
} else {
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer integer array;\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add column dbarray_integer integer array;\n");
|
||||
}
|
||||
|
||||
writer = new DdlWrite();
|
||||
sqlserverHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnIntegerWithLength());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add dbarray_integer varchar(90);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add dbarray_integer varchar(90);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
sqlserverHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnInteger());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add dbarray_integer varchar(1000);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add dbarray_integer varchar(1000);\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
hanaHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnIntegerWithLength());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_integer integer array(90));\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add (dbarray_integer integer array(90));\n");
|
||||
|
||||
writer = new DdlWrite();
|
||||
hanaHandler().generate(writer, Helper.getAlterTableAddDbArrayColumnInteger());
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_integer integer array);\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo add (dbarray_integer integer array);\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,12 +165,12 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
DdlHandler handler = h2Handler();
|
||||
handler.generate(writer, Helper.getAlterTableAddColumn());
|
||||
|
||||
String buffer = writer.apply().getBuffer();
|
||||
assertThat(buffer).contains("alter table foo add column some_id integer;");
|
||||
String buffer = writer.toString();
|
||||
assertThat(buffer).contains("-- apply alter tables\nalter table foo add column some_id integer;");
|
||||
|
||||
String fkBuffer = writer.applyForeignKeys().getBuffer();
|
||||
assertThat(fkBuffer).contains(
|
||||
"alter table foo add constraint fk_foo_some_id foreign key (some_id) references bar (id) on delete restrict on update restrict;");
|
||||
"alter table foo add constraint fk_foo_some_id foreign key (some_id) references bar (id) on delete restrict on update restrict;");
|
||||
assertThat(fkBuffer).contains("create index idx_foo_some_id on foo (some_id);");
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo("");
|
||||
}
|
||||
@@ -184,7 +183,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
handler.generate(writer, Helper.getDropColumn());
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nalter table foo drop column col2;\n");
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo("");
|
||||
|
||||
writer = new DdlWrite();
|
||||
@@ -192,7 +191,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
hanaHandler.generate(writer, Helper.getDropColumn());
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("CALL usp_ebean_drop_column('foo', 'col2');\n\n");
|
||||
assertThat(writer.toString()).isEqualTo("-- apply alter tables\nCALL usp_ebean_drop_column('foo', 'col2');\n");
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo("");
|
||||
}
|
||||
|
||||
@@ -204,9 +203,9 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
handler.generate(writer, Helper.getCreateTable());
|
||||
|
||||
String createTableDDL = Helper.asText(this, "/assert/create-table.txt");
|
||||
String createTableDDL = Helper.asText(this, "/assert/drop-create-table.txt");
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo(createTableDDL);
|
||||
assertThat(writer.toString()).isEqualTo(createTableDDL);
|
||||
assertThat(writer.dropAll().getBuffer().trim()).isEqualTo("drop table if exists foo;");
|
||||
|
||||
writer = new DdlWrite();
|
||||
@@ -214,9 +213,9 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
hanaHandler.generate(writer, Helper.getCreateTable());
|
||||
|
||||
String createColumnTableDDL = Helper.asText(this, "/assert/create-column-table.txt");
|
||||
String createColumnTableDDL = Helper.asText(this, "/assert/drop-create-column-table.txt");
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo(createColumnTableDDL);
|
||||
assertThat(writer.toString()).isEqualTo(createColumnTableDDL);
|
||||
assertThat(writer.dropAll().getBuffer().trim()).isEqualTo("drop table foo cascade;");
|
||||
}
|
||||
|
||||
@@ -230,9 +229,12 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
String apply = Helper.asText(this, "/assert/BaseDdlHandlerTest/baseApply.sql");
|
||||
String rollbackLast = Helper.asText(this, "/assert/BaseDdlHandlerTest/baseDropAll.sql");
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
writer.writeApply(sb);
|
||||
assertThat(sb.toString()).isEqualTo(apply);
|
||||
sb = new StringBuilder();
|
||||
writer.writeDropAll(sb);
|
||||
assertThat(sb.toString()).isEqualTo(rollbackLast);
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@@ -251,7 +253,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
String apply = Helper.asText(this, "/assert/changeset-apply.txt");
|
||||
String rollbackLast = Helper.asText(this, "/assert/changeset-dropAll.txt");
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(writer.toString()).isEqualTo(apply);
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
}
|
||||
|
||||
@@ -272,7 +274,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
String rollbackFirst = Helper.asText(this, "/assert/changeset-pg-rollbackFirst.sql");
|
||||
String rollbackLast = Helper.asText(this, "/assert/changeset-pg-rollbackLast.sql");
|
||||
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(writer.toString()).isEqualTo(apply);
|
||||
assertThat(writer.applyForeignKeys().getBuffer()).isEqualTo(applyLast);
|
||||
assertThat(writer.dropAllForeignKeys().getBuffer()).isEqualTo(rollbackFirst);
|
||||
assertThat(writer.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
|
||||
+12
-13
@@ -39,7 +39,7 @@ public class BaseTableDdlTest {
|
||||
|
||||
ddlGen.generate(writer, alterColumn);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.toString();
|
||||
assertThat(ddl).contains("alter table mytab drop constraint if exists ck_mytab_acol");
|
||||
assertThat(ddl).contains("alter table mytab add constraint ck_mytab_acol check (acol in ('A','B'))");
|
||||
}
|
||||
@@ -55,9 +55,9 @@ public class BaseTableDdlTest {
|
||||
column.setName("col_name");
|
||||
column.setType("varchar(20)");
|
||||
|
||||
ddlGen.alterTableAddColumn(writer.apply(), "mytable", column, false, false);
|
||||
ddlGen.alterTableAddColumn(writer, "mytable", column, false, false);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.toString();
|
||||
assertThat(ddl).contains("alter table mytable add col_name varchar2(20)");
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ public class BaseTableDdlTest {
|
||||
column.setName("col_name");
|
||||
column.setType("varchar(20)");
|
||||
|
||||
ddlGen.alterTableAddColumn(writer.apply(), "mytable", column, false, false);
|
||||
ddlGen.alterTableAddColumn(writer, "mytable", column, false, false);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.toString();
|
||||
assertThat(ddl).contains("alter table mytable add column col_name String");
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class BaseTableDdlTest {
|
||||
|
||||
ddlGen.generate(writer, alterColumn);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.applyPostAlter().getBuffer();
|
||||
assertThat(ddl).contains("comment on column mytab.acol is 'my comment'");
|
||||
}
|
||||
|
||||
@@ -105,11 +105,10 @@ public class BaseTableDdlTest {
|
||||
column.setComment("some comment");
|
||||
column.setType("int");
|
||||
|
||||
ddl.alterTableAddColumn(writer.apply(), "my_table", column, false, false);
|
||||
assertEquals(
|
||||
"alter table my_table add column my_column int;\n" +
|
||||
"comment on column my_table.my_column is 'some comment';\n",
|
||||
writer.apply().getBuffer());
|
||||
ddl.alterTableAddColumn(writer, "my_table", column, false, false);
|
||||
assertEquals("-- apply alter tables\nalter table my_table add column my_column int;\n"
|
||||
+ "-- apply post alter\ncomment on column my_table.my_column is 'some comment';\n",
|
||||
writer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -125,7 +124,7 @@ public class BaseTableDdlTest {
|
||||
|
||||
ddlGen.generate(writer, addTableComment);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.applyPostAlter().getBuffer();
|
||||
assertThat(ddl).contains("comment on table mytab is 'my comment'");
|
||||
}
|
||||
|
||||
@@ -142,7 +141,7 @@ public class BaseTableDdlTest {
|
||||
|
||||
ddlGen.generate(writer, addTableComment);
|
||||
|
||||
String ddl = writer.apply().getBuffer();
|
||||
String ddl = writer.applyPostAlter().getBuffer();
|
||||
assertThat(ddl).contains("alter table mytab comment = 'my comment'");
|
||||
}
|
||||
|
||||
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder;
|
||||
import io.ebeaninternal.dbmigration.model.CurrentModel;
|
||||
import io.ebeaninternal.dbmigration.model.MConfiguration;
|
||||
import io.ebeaninternal.dbmigration.model.ModelContainer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class H2HistoryDdlTest {
|
||||
|
||||
@Test
|
||||
public void testRegenerateHistoryTriggers() throws Exception {
|
||||
|
||||
SpiEbeanServer ebeanServer = (SpiEbeanServer) DB.getDefault();
|
||||
|
||||
HistoryTableUpdate update = new HistoryTableUpdate("c_user");
|
||||
update.add(HistoryTableUpdate.Change.ADD, "one");
|
||||
update.add(HistoryTableUpdate.Change.DROP, "two");
|
||||
|
||||
|
||||
CurrentModel currentModel = new CurrentModel(ebeanServer);
|
||||
ModelContainer modelContainer = currentModel.read();
|
||||
DdlWrite writer = new DdlWrite(new MConfiguration(), modelContainer, new DdlOptions());
|
||||
|
||||
H2Platform h2Platform = new H2Platform();
|
||||
PlatformDdl h2Ddl = PlatformDdlBuilder.create(h2Platform);
|
||||
h2Ddl.configure(ebeanServer.config());
|
||||
h2Ddl.regenerateHistoryTriggers(writer, update);
|
||||
|
||||
assertThat(writer.applyHistoryView().isEmpty()).isFalse();
|
||||
assertThat(writer.applyHistoryTrigger().isEmpty()).isFalse();
|
||||
assertThat(writer.applyHistoryView().getBuffer())
|
||||
.contains("create view")
|
||||
.doesNotContain("create trigger");
|
||||
assertThat(writer.applyHistoryTrigger().getBuffer())
|
||||
.contains("add one")
|
||||
.contains("create trigger")
|
||||
.doesNotContain("create view");
|
||||
assertThat(writer.dropAll().isEmpty()).isTrue();
|
||||
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -13,8 +13,8 @@ public class HanaDdlTest {
|
||||
public void alterTableDropColumn() {
|
||||
HanaColumnStoreDdl ddl = new HanaColumnStoreDdl(new HanaPlatform());
|
||||
DdlWrite writer = new DdlWrite();
|
||||
ddl.alterTableDropColumn(writer.apply(), "my_table", "my_column");
|
||||
assertEquals("CALL usp_ebean_drop_column('my_table', 'my_column');\n", writer.apply().getBuffer());
|
||||
ddl.alterTableDropColumn(writer, "my_table", "my_column");
|
||||
assertEquals("-- apply alter tables\nCALL usp_ebean_drop_column('my_table', 'my_column');\n", writer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -33,7 +33,9 @@ public class HanaDdlTest {
|
||||
column.setCheckConstraintName("check_constraint");
|
||||
column.setHistoryExclude(Boolean.TRUE);
|
||||
column.setIdentity(Boolean.TRUE);
|
||||
ddl.alterTableAddColumn(writer.apply(), "my_table", column, false, "1");
|
||||
assertEquals("alter table my_table add ( my_column int default 1 not null);\nalter table my_table add constraint check_constraint CHECK(my_column > 0);\n", writer.apply().getBuffer());
|
||||
ddl.alterTableAddColumn(writer, "my_table", column, false, "1");
|
||||
assertEquals(
|
||||
"-- apply alter tables\nalter table my_table add (my_column int default 1 not null);\n-- apply post alter\nalter table my_table add constraint check_constraint CHECK(my_column > 0);\n",
|
||||
writer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class HistoryTableUpdateTest {
|
||||
|
||||
@Test
|
||||
public void testDescription() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.ADD, "two");
|
||||
upd.add(HistoryTableUpdate.Change.DROP, "four");
|
||||
|
||||
assertThat(upd.description()).isEqualTo("[add two, drop four]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDescription_withIncludeExclude() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.ADD, "two");
|
||||
upd.add(HistoryTableUpdate.Change.INCLUDE, "five");
|
||||
upd.add(HistoryTableUpdate.Change.EXCLUDE, "six");
|
||||
upd.add(HistoryTableUpdate.Change.DROP, "four");
|
||||
|
||||
assertThat(upd.description()).isEqualTo("[add two, include five, exclude six, drop four]");
|
||||
}
|
||||
|
||||
}
|
||||
+428
-164
@@ -3,6 +3,7 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.db2.DB2LuwPlatform;
|
||||
import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebean.config.dbplatform.hana.HanaPlatform;
|
||||
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
|
||||
@@ -14,12 +15,11 @@ import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterForeignKey;
|
||||
import io.ebeaninternal.dbmigration.migration.Column;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
|
||||
public class PlatformDdl_AlterColumnTest {
|
||||
|
||||
@@ -31,229 +31,424 @@ public class PlatformDdl_AlterColumnTest {
|
||||
private final PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform());
|
||||
private final PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform());
|
||||
private final PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform());
|
||||
private final PlatformDdl db2Ddl = PlatformDdlBuilder.create(new DB2LuwPlatform());
|
||||
|
||||
private final SoftAssertions softly = new SoftAssertions();
|
||||
|
||||
{
|
||||
DatabaseConfig serverConfig = DB.getDefault().pluginApi().config();
|
||||
sqlServerDdl.configure(serverConfig);
|
||||
}
|
||||
|
||||
AlterColumn alterNotNull() {
|
||||
AlterColumn alterColumn = new AlterColumn();
|
||||
alterColumn.setTableName("mytab");
|
||||
alterColumn.setColumnName("acol");
|
||||
alterColumn.setCurrentType("varchar(5)");
|
||||
alterColumn.setNotnull(Boolean.TRUE);
|
||||
|
||||
return alterColumn;
|
||||
@AfterEach
|
||||
void assertAll() {
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertArrayType_default() {
|
||||
assertThat(mysqlDdl.convertArrayType("varchar[](90)")).isEqualTo("varchar(90)");
|
||||
assertThat(mysqlDdl.convertArrayType("integer[](60)")).isEqualTo("varchar(60)");
|
||||
assertThat(mysqlDdl.convertArrayType("varchar[]")).isEqualTo("varchar(1000)");
|
||||
assertThat(mysqlDdl.convertArrayType("integer[]")).isEqualTo("varchar(1000)");
|
||||
softly.assertThat(mysqlDdl.convertArrayType("varchar[](90)")).isEqualTo("varchar(90)");
|
||||
softly.assertThat(mysqlDdl.convertArrayType("integer[](60)")).isEqualTo("varchar(60)");
|
||||
softly.assertThat(mysqlDdl.convertArrayType("varchar[]")).isEqualTo("varchar(1000)");
|
||||
softly.assertThat(mysqlDdl.convertArrayType("integer[]")).isEqualTo("varchar(1000)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertArrayType_h2() {
|
||||
if (useV1Syntax) {
|
||||
assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("array");
|
||||
assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("array");
|
||||
assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("array");
|
||||
assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("array");
|
||||
} else {
|
||||
assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("varchar array");
|
||||
assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("integer array");
|
||||
assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("varchar array");
|
||||
assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("integer array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("varchar array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("integer array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("varchar array");
|
||||
softly.assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("integer array");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertArrayType_postgres() {
|
||||
assertThat(pgDdl.convertArrayType("varchar[](90)")).isEqualTo("varchar[]");
|
||||
assertThat(pgDdl.convertArrayType("integer[](60)")).isEqualTo("integer[]");
|
||||
assertThat(pgDdl.convertArrayType("varchar[]")).isEqualTo("varchar[]");
|
||||
assertThat(pgDdl.convertArrayType("integer[]")).isEqualTo("integer[]");
|
||||
softly.assertThat(pgDdl.convertArrayType("varchar[](90)")).isEqualTo("varchar[]");
|
||||
softly.assertThat(pgDdl.convertArrayType("integer[](60)")).isEqualTo("integer[]");
|
||||
softly.assertThat(pgDdl.convertArrayType("varchar[]")).isEqualTo("varchar[]");
|
||||
softly.assertThat(pgDdl.convertArrayType("integer[]")).isEqualTo("integer[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertArrayType_hana() {
|
||||
assertThat(hanaDdl.convertArrayType("varchar[](90)")).isEqualTo("nvarchar(255) array(90)");
|
||||
assertThat(hanaDdl.convertArrayType("integer[](60)")).isEqualTo("integer array(60)");
|
||||
assertThat(hanaDdl.convertArrayType("varchar[]")).isEqualTo("nvarchar(255) array");
|
||||
assertThat(hanaDdl.convertArrayType("integer[]")).isEqualTo("integer array");
|
||||
softly.assertThat(hanaDdl.convertArrayType("varchar[](90)")).isEqualTo("nvarchar(255) array(90)");
|
||||
softly.assertThat(hanaDdl.convertArrayType("integer[](60)")).isEqualTo("integer array(60)");
|
||||
softly.assertThat(hanaDdl.convertArrayType("varchar[]")).isEqualTo("nvarchar(255) array");
|
||||
softly.assertThat(hanaDdl.convertArrayType("integer[]")).isEqualTo("integer array");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnBaseAttributes() {
|
||||
|
||||
AlterColumn alterColumn = alterNotNull();
|
||||
assertNull(h2Ddl.alterColumnBaseAttributes(alterColumn));
|
||||
assertNull(pgDdl.alterColumnBaseAttributes(alterColumn));
|
||||
assertNull(oraDdl.alterColumnBaseAttributes(alterColumn));
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(5)");
|
||||
alter.setCurrentDefaultValue("'ho'");
|
||||
alter.setCurrentNotnull(Boolean.FALSE);
|
||||
|
||||
String sql = mysqlDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab modify acol varchar(5) not null", sql);
|
||||
// alter all attributes
|
||||
alter.setNotnull(Boolean.TRUE); // -> alter to not null
|
||||
alter.setDefaultValue("'hi'"); // and set default
|
||||
alter.setType("varchar(50)"); // and alter type
|
||||
|
||||
sql = sqlServerDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab alter column acol nvarchar(5) not null", sql);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol varchar(50);\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n"
|
||||
+ "alter table mytab alter column acol set not null;\n");
|
||||
|
||||
sql = hanaDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab alter ( acol nvarchar(5) not null)", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol type varchar(50) using acol::varchar(50);\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n"
|
||||
+ "alter table mytab alter column acol set not null;\n");
|
||||
|
||||
alterColumn.setNotnull(Boolean.FALSE);
|
||||
sql = mysqlDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab modify acol varchar(5)", sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar2(50);\n"
|
||||
+ "alter table mytab modify acol default 'hi';\n"
|
||||
+ "alter table mytab modify acol not null;\n");
|
||||
|
||||
sql = hanaDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab alter ( acol nvarchar(5))", sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar(50) not null default 'hi';\n");
|
||||
|
||||
alterColumn.setNotnull(null);
|
||||
alterColumn.setType("varchar(100)");
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n"
|
||||
+ "alter table mytab alter column acol nvarchar(50) not null;\n"
|
||||
+ "alter table mytab add default 'hi' for acol;\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab modify acol varchar(100)", sql);
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(50) default 'hi' not null);\n");
|
||||
|
||||
sql = hanaDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab alter ( acol nvarchar(100))", sql);
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set data type varchar(50);\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n"
|
||||
+ "alter table mytab alter column acol set not null;\n"
|
||||
+ "call sysproc.admin_cmd('reorg table mytab');\n");
|
||||
|
||||
alterColumn.setCurrentNotnull(Boolean.TRUE);
|
||||
sql = mysqlDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab modify acol varchar(100) not null", sql);
|
||||
//
|
||||
alter.setCurrentNotnull(Boolean.TRUE);
|
||||
alter.setNotnull(Boolean.FALSE);
|
||||
alter.setDefaultValue("DROP DEFAULT");
|
||||
alter.setType(null); // do not alter type
|
||||
|
||||
sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n"
|
||||
+ "alter table mytab alter column acol set null;\n");
|
||||
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n"
|
||||
+ "alter table mytab alter column acol drop not null;\n");
|
||||
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol default null;\n"
|
||||
+ "alter table mytab modify acol null;\n");
|
||||
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar(5);\n");
|
||||
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n"
|
||||
+ "alter table mytab alter column acol nvarchar(5);\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(5) default null);\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n"
|
||||
+ "alter table mytab alter column acol drop not null;\n");
|
||||
|
||||
sql = hanaDdl.alterColumnBaseAttributes(alterColumn);
|
||||
assertEquals("alter table mytab alter ( acol nvarchar(100) not null)", sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnType() {
|
||||
|
||||
String sql = h2Ddl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertEquals("alter table mytab alter column acol varchar(20)", sql);
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("integer");
|
||||
alter.setType("varchar(20)");
|
||||
|
||||
sql = pgDdl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertEquals("alter table mytab alter column acol type varchar(20) using acol::varchar(20)", sql);
|
||||
sql = pgDdl.alterColumnType("mytab", "acol", "bigint");
|
||||
assertEquals("alter table mytab alter column acol type bigint using acol::bigint", sql);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol varchar(20);\n");
|
||||
|
||||
sql = oraDdl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertEquals("alter table mytab modify acol varchar2(20)", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol type varchar(20) using acol::varchar(20);\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertNull(sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar2(20);\n");
|
||||
|
||||
sql = sqlServerDdl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertNull(sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar(20);\n");
|
||||
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol nvarchar(20);\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20));\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set data type varchar(20);\n"
|
||||
// Note, this reorg may be not necessary when only length attribute is alterd
|
||||
// but this is currently not implemented.
|
||||
+ "call sysproc.admin_cmd('reorg table mytab');\n");
|
||||
|
||||
alter.setType("bigint");
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol type bigint using acol::bigint;\n");
|
||||
|
||||
alter.setCurrentType("bigint");
|
||||
alter.setType("integer");
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol decimal);\n"
|
||||
+ "alter table mytab alter (acol integer);\n");
|
||||
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setType("varchar(10)");
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nclob);\n"
|
||||
+ "alter table mytab alter (acol nvarchar(10));\n");
|
||||
|
||||
sql = hanaDdl.alterColumnType("mytab", "acol", "varchar(20)");
|
||||
assertNull(sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnNotnull() {
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setCurrentNotnull(Boolean.FALSE);
|
||||
alter.setNotnull(Boolean.TRUE);
|
||||
|
||||
String sql = h2Ddl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertEquals("alter table mytab alter column acol set not null", sql);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set not null;\n");
|
||||
|
||||
sql = pgDdl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertEquals("alter table mytab alter column acol set not null", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set not null;\n");
|
||||
|
||||
sql = oraDdl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertEquals("alter table mytab modify acol not null", sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol not null;\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertNull(sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar(20) not null;\n");
|
||||
|
||||
sql = sqlServerDdl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertNull(sql);
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol nvarchar(20) not null;\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20) not null);\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set not null;\n"
|
||||
+ "call sysproc.admin_cmd('reorg table mytab');\n");
|
||||
|
||||
sql = hanaDdl.alterColumnNotnull("mytab", "acol", true);
|
||||
assertNull(sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnNull() {
|
||||
|
||||
String sql = h2Ddl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertEquals("alter table mytab alter column acol set null", sql);
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setCurrentDefaultValue("'hi'");
|
||||
alter.setCurrentNotnull(Boolean.TRUE);
|
||||
|
||||
sql = pgDdl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertEquals("alter table mytab alter column acol drop not null", sql);
|
||||
alter.setNotnull(Boolean.FALSE);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set null;\n");
|
||||
|
||||
sql = oraDdl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertEquals("alter table mytab modify acol null", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop not null;\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertNull(sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol null;\n");
|
||||
|
||||
sql = sqlServerDdl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertNull(sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol varchar(20) default 'hi';\n");
|
||||
|
||||
sql = hanaDdl.alterColumnNotnull("mytab", "acol", false);
|
||||
assertNull(sql);
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n"
|
||||
+ "alter table mytab alter column acol nvarchar(20);\n"
|
||||
+ "alter table mytab add default 'hi' for acol;\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20) default 'hi');\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop not null;\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnDefaultValue() {
|
||||
public void testAlterColumnAddDefaultValue() {
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setCurrentNotnull(Boolean.TRUE);
|
||||
alter.setDefaultValue("'hi'");
|
||||
|
||||
String sql = h2Ddl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
assertEquals("alter table mytab alter column acol set default 'hi'", sql);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
|
||||
sql = pgDdl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
assertEquals("alter table mytab alter column acol set default 'hi'", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
|
||||
sql = oraDdl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
assertEquals("alter table mytab modify acol default 'hi'", sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol default 'hi';\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
assertEquals("alter table mytab alter acol set default 'hi'", sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter acol set default 'hi';\n");
|
||||
|
||||
sql = sqlServerDdl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
assertEquals("alter table mytab add default 'hi' for acol", sql);
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n"
|
||||
+ "alter table mytab add default 'hi' for acol;\n");
|
||||
|
||||
boolean exceptionCaught = false;
|
||||
try {
|
||||
hanaDdl.alterColumnDefaultValue("mytab", "acol", "'hi'");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
exceptionCaught = true;
|
||||
}
|
||||
assertTrue(exceptionCaught);
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20) default 'hi' not null);\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnChangeDefaultValue() {
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setCurrentNotnull(Boolean.TRUE);
|
||||
alter.setDefaultValue("'ho'");
|
||||
alter.setDefaultValue("'hi'");
|
||||
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol default 'hi';\n");
|
||||
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter acol set default 'hi';\n");
|
||||
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n"
|
||||
+ "alter table mytab add default 'hi' for acol;\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20) default 'hi' not null);\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol set default 'hi';\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterColumnDropDefault() {
|
||||
|
||||
String sql = h2Ddl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
assertEquals("alter table mytab alter column acol drop default", sql);
|
||||
AlterColumn alter = new AlterColumn();
|
||||
alter.setTableName("mytab");
|
||||
alter.setColumnName("acol");
|
||||
alter.setCurrentType("varchar(20)");
|
||||
alter.setCurrentNotnull(Boolean.TRUE);
|
||||
alter.setCurrentDefaultValue("'hi'");
|
||||
alter.setDefaultValue("DROP DEFAULT");
|
||||
|
||||
sql = pgDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
assertEquals("alter table mytab alter column acol drop default", sql);
|
||||
String sql = alterColumn(h2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n");
|
||||
|
||||
sql = oraDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
assertEquals("alter table mytab modify acol default null", sql);
|
||||
sql = alterColumn(pgDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n");
|
||||
|
||||
sql = mysqlDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
assertEquals("alter table mytab alter acol drop default", sql);
|
||||
sql = alterColumn(oraDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab modify acol default null;\n");
|
||||
|
||||
sql = sqlServerDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
assertEquals("EXEC usp_ebean_drop_default_constraint mytab, acol", sql);
|
||||
sql = alterColumn(mysqlDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter acol drop default;\n");
|
||||
|
||||
sql = alterColumn(sqlServerDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "EXEC usp_ebean_drop_default_constraint mytab, acol;\n");
|
||||
|
||||
sql = alterColumn(hanaDdl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter (acol nvarchar(20) default null not null);\n");
|
||||
|
||||
sql = alterColumn(db2Ddl, alter);
|
||||
softly.assertThat(sql).isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table mytab alter column acol drop default;\n");
|
||||
|
||||
boolean exceptionCaught = false;
|
||||
try {
|
||||
hanaDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
exceptionCaught = true;
|
||||
}
|
||||
assertTrue(exceptionCaught);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oracle_alterTableAddColumn() {
|
||||
DdlWrite writer = new DdlWrite();
|
||||
oraDdl.alterTableAddColumn(writer.apply(), "my_table", simpleColumn(), false, "1");
|
||||
assertThat(writer.apply().getBuffer()).isEqualTo("alter table my_table add my_column int default 1 not null;\n");
|
||||
oraDdl.alterTableAddColumn(writer, "my_table", simpleColumn(), false, "1");
|
||||
softly.assertThat(writer.toString())
|
||||
.isEqualTo("-- apply alter tables\n"
|
||||
+ "alter table my_table add my_column int default 1 not null;\n");
|
||||
}
|
||||
|
||||
private Column simpleColumn() {
|
||||
@@ -267,79 +462,148 @@ public class PlatformDdl_AlterColumnTest {
|
||||
|
||||
@Test
|
||||
public void useIdentityType_h2() {
|
||||
assertEquals(h2Ddl.useIdentityType(null), IdType.IDENTITY);
|
||||
assertEquals(h2Ddl.useIdentityType(IdType.SEQUENCE), IdType.SEQUENCE);
|
||||
assertEquals(h2Ddl.useIdentityType(IdType.IDENTITY), IdType.IDENTITY);
|
||||
assertEquals(h2Ddl.useIdentityType(IdType.GENERATOR), IdType.GENERATOR);
|
||||
assertEquals(h2Ddl.useIdentityType(IdType.EXTERNAL), IdType.EXTERNAL);
|
||||
softly.assertThat(h2Ddl.useIdentityType(null)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(h2Ddl.useIdentityType(IdType.SEQUENCE)).isEqualTo(IdType.SEQUENCE);
|
||||
softly.assertThat(h2Ddl.useIdentityType(IdType.IDENTITY)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(h2Ddl.useIdentityType(IdType.GENERATOR)).isEqualTo(IdType.GENERATOR);
|
||||
softly.assertThat(h2Ddl.useIdentityType(IdType.EXTERNAL)).isEqualTo(IdType.EXTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentityType_postgres() {
|
||||
assertEquals(pgDdl.useIdentityType(IdType.GENERATOR), IdType.GENERATOR);
|
||||
assertEquals(pgDdl.useIdentityType(IdType.EXTERNAL), IdType.EXTERNAL);
|
||||
softly.assertThat(pgDdl.useIdentityType(IdType.GENERATOR)).isEqualTo(IdType.GENERATOR);
|
||||
softly.assertThat(pgDdl.useIdentityType(IdType.EXTERNAL)).isEqualTo(IdType.EXTERNAL);
|
||||
|
||||
assertEquals(pgDdl.useIdentityType(null), IdType.IDENTITY);
|
||||
assertEquals(pgDdl.useIdentityType(IdType.SEQUENCE), IdType.SEQUENCE);
|
||||
assertEquals(pgDdl.useIdentityType(IdType.IDENTITY), IdType.IDENTITY);
|
||||
softly.assertThat(pgDdl.useIdentityType(null)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(pgDdl.useIdentityType(IdType.SEQUENCE)).isEqualTo(IdType.SEQUENCE);
|
||||
softly.assertThat(pgDdl.useIdentityType(IdType.IDENTITY)).isEqualTo(IdType.IDENTITY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentityType_mysql() {
|
||||
|
||||
assertEquals(mysqlDdl.useIdentityType(null), IdType.IDENTITY);
|
||||
assertEquals(mysqlDdl.useIdentityType(IdType.SEQUENCE), IdType.IDENTITY);
|
||||
assertEquals(mysqlDdl.useIdentityType(IdType.IDENTITY), IdType.IDENTITY);
|
||||
assertEquals(mysqlDdl.useIdentityType(IdType.GENERATOR), IdType.GENERATOR);
|
||||
assertEquals(mysqlDdl.useIdentityType(IdType.EXTERNAL), IdType.EXTERNAL);
|
||||
softly.assertThat(mysqlDdl.useIdentityType(null)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(mysqlDdl.useIdentityType(IdType.SEQUENCE)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(mysqlDdl.useIdentityType(IdType.IDENTITY)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(mysqlDdl.useIdentityType(IdType.GENERATOR)).isEqualTo(IdType.GENERATOR);
|
||||
softly.assertThat(mysqlDdl.useIdentityType(IdType.EXTERNAL)).isEqualTo(IdType.EXTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentityType_oracle() {
|
||||
|
||||
assertEquals(oraDdl.useIdentityType(null), IdType.IDENTITY);
|
||||
assertEquals(oraDdl.useIdentityType(IdType.SEQUENCE), IdType.SEQUENCE);
|
||||
assertEquals(oraDdl.useIdentityType(IdType.IDENTITY), IdType.IDENTITY);
|
||||
assertEquals(oraDdl.useIdentityType(IdType.GENERATOR), IdType.GENERATOR);
|
||||
assertEquals(oraDdl.useIdentityType(IdType.EXTERNAL), IdType.EXTERNAL);
|
||||
softly.assertThat(oraDdl.useIdentityType(null)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(oraDdl.useIdentityType(IdType.SEQUENCE)).isEqualTo(IdType.SEQUENCE);
|
||||
softly.assertThat(oraDdl.useIdentityType(IdType.IDENTITY)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(oraDdl.useIdentityType(IdType.GENERATOR)).isEqualTo(IdType.GENERATOR);
|
||||
softly.assertThat(oraDdl.useIdentityType(IdType.EXTERNAL)).isEqualTo(IdType.EXTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentityType_hana() {
|
||||
|
||||
assertEquals(hanaDdl.useIdentityType(null), IdType.IDENTITY);
|
||||
assertEquals(hanaDdl.useIdentityType(IdType.SEQUENCE), IdType.IDENTITY);
|
||||
assertEquals(hanaDdl.useIdentityType(IdType.IDENTITY), IdType.IDENTITY);
|
||||
assertEquals(hanaDdl.useIdentityType(IdType.GENERATOR), IdType.GENERATOR);
|
||||
assertEquals(hanaDdl.useIdentityType(IdType.EXTERNAL), IdType.EXTERNAL);
|
||||
softly.assertThat(hanaDdl.useIdentityType(null)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(hanaDdl.useIdentityType(IdType.SEQUENCE)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(hanaDdl.useIdentityType(IdType.IDENTITY)).isEqualTo(IdType.IDENTITY);
|
||||
softly.assertThat(hanaDdl.useIdentityType(IdType.GENERATOR)).isEqualTo(IdType.GENERATOR);
|
||||
softly.assertThat(hanaDdl.useIdentityType(IdType.EXTERNAL)).isEqualTo(IdType.EXTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendForeignKeySuffix_when_defaults() {
|
||||
assertThat(alterFkey(null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
softly.assertThat(alterFkey(h2Ddl, null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
softly.assertThat(alterFkey(pgDdl, null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
softly.assertThat(alterFkey(mysqlDdl, null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
softly.assertThat(alterFkey(oraDdl, null, null)).isEqualTo("");
|
||||
softly.assertThat(alterFkey(sqlServerDdl, null, null)).isEqualTo("");
|
||||
softly.assertThat(alterFkey(hanaDdl, null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
softly.assertThat(alterFkey(db2Ddl, null, null)).isEqualTo(" on delete restrict on update restrict");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendForeignKeySuffix_when_RestrictSetNull() {
|
||||
assertThat(alterFkey("RESTRICT", "SET_NULL")).isEqualTo(" on delete restrict on update set null");
|
||||
softly.assertThat(alterFkey(h2Ddl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on delete restrict on update set null");
|
||||
|
||||
softly.assertThat(alterFkey(pgDdl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on delete restrict on update set null");
|
||||
|
||||
softly.assertThat(alterFkey(mysqlDdl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on delete restrict on update set null");
|
||||
|
||||
softly.assertThat(alterFkey(oraDdl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo("");
|
||||
|
||||
softly.assertThat(alterFkey(sqlServerDdl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on update set null");
|
||||
|
||||
softly.assertThat(alterFkey(hanaDdl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on delete restrict on update set null");
|
||||
|
||||
softly.assertThat(alterFkey(db2Ddl, "RESTRICT", "SET_NULL"))
|
||||
.isEqualTo(" on delete restrict on update set null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendForeignKeySuffix_when_SetNullRestrict() {
|
||||
assertThat(alterFkey("SET_NULL", "RESTRICT")).isEqualTo(" on delete set null on update restrict");
|
||||
softly.assertThat(alterFkey(h2Ddl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null on update restrict");
|
||||
|
||||
softly.assertThat(alterFkey(pgDdl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null on update restrict");
|
||||
|
||||
softly.assertThat(alterFkey(mysqlDdl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null on update restrict");
|
||||
|
||||
softly.assertThat(alterFkey(oraDdl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null");
|
||||
|
||||
softly.assertThat(alterFkey(sqlServerDdl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null");
|
||||
|
||||
softly.assertThat(alterFkey(hanaDdl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null on update restrict");
|
||||
|
||||
softly.assertThat(alterFkey(db2Ddl, "SET_NULL", "RESTRICT"))
|
||||
.isEqualTo(" on delete set null on update restrict");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendForeignKeySuffix_when_SetDefaultCascade() {
|
||||
assertThat(alterFkey("SET_DEFAULT", "CASCADE")).isEqualTo(" on delete set default on update cascade");
|
||||
softly.assertThat(alterFkey(h2Ddl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
|
||||
softly.assertThat(alterFkey(pgDdl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
|
||||
softly.assertThat(alterFkey(mysqlDdl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
|
||||
softly.assertThat(alterFkey(oraDdl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo("");
|
||||
|
||||
softly.assertThat(alterFkey(sqlServerDdl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
|
||||
softly.assertThat(alterFkey(hanaDdl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
|
||||
softly.assertThat(alterFkey(db2Ddl, "SET_DEFAULT", "CASCADE"))
|
||||
.isEqualTo(" on delete set default on update cascade");
|
||||
}
|
||||
|
||||
private String alterFkey(String onDelete, String onUpdate) {
|
||||
private String alterColumn(PlatformDdl ddl, AlterColumn alterColumn) {
|
||||
DdlWrite write = new DdlWrite();
|
||||
ddl.alterColumn(write, alterColumn);
|
||||
return write.toString();
|
||||
}
|
||||
|
||||
private String alterFkey(PlatformDdl ddl, String onDelete, String onUpdate) {
|
||||
AlterForeignKey afk = new AlterForeignKey();
|
||||
afk.setOnDelete(onDelete);
|
||||
afk.setOnUpdate(onUpdate);
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
h2Ddl.appendForeignKeySuffix(new WriteForeignKey(afk), buffer);
|
||||
ddl.appendForeignKeySuffix(new WriteForeignKey(afk), buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class PlatformDdl_dropUniqueConstraintTest {
|
||||
sql = sqlServerDdl.alterTableDropUniqueConstraint("mytab", "uq_name");
|
||||
assertEquals(
|
||||
"IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mytab','U') AND name = 'uq_name') drop index uq_name ON mytab;\n"
|
||||
+ "IF (OBJECT_ID('uq_name', 'UQ') IS NOT NULL) alter table mytab drop constraint uq_name",
|
||||
+ "IF OBJECT_ID('uq_name', 'UQ') IS NOT NULL alter table mytab drop constraint uq_name",
|
||||
sql);
|
||||
|
||||
sql = mysqlDdl.alterTableDropUniqueConstraint("mytab", "uq_name");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
-- apply changes
|
||||
create table foo (
|
||||
col1 varchar(4) generated by default as identity not null,
|
||||
col2 varchar(30) not null,
|
||||
@@ -6,7 +7,6 @@ create table foo (
|
||||
);
|
||||
comment on table foo is 'comment';
|
||||
|
||||
-- apply alter tables
|
||||
alter table foo add column added_to_foo varchar(20);
|
||||
|
||||
alter table foo drop column col2;
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
-- drop all
|
||||
drop table if exists foo;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ create table ckey_parent (
|
||||
constraint pk_ckey_parent primary key (one_key,two_key)
|
||||
);
|
||||
|
||||
-- foreign keys and indices
|
||||
create index ix_ckey_detail_parent on ckey_detail (one_key,two_key);
|
||||
alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict;
|
||||
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ create table phones (
|
||||
constraint pk_phones primary key (id)
|
||||
);
|
||||
|
||||
-- foreign keys and indices
|
||||
create index ix_phones_person_id on phones (person_id);
|
||||
alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict;
|
||||
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ create table phones (
|
||||
constraint pk_phones primary key (id)
|
||||
);
|
||||
|
||||
-- foreign keys and indices
|
||||
create index ix_phones_person_id on phones (person_id);
|
||||
alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict not valid;
|
||||
|
||||
|
||||
+4
@@ -1,3 +1,7 @@
|
||||
-- drop all
|
||||
drop table foo cascade;
|
||||
|
||||
-- apply changes
|
||||
create column table foo (
|
||||
col1 nvarchar(4) generated by default as identity not null,
|
||||
col2 nvarchar(30) not null,
|
||||
+4
@@ -1,3 +1,7 @@
|
||||
-- drop all
|
||||
drop table if exists foo;
|
||||
|
||||
-- apply changes
|
||||
create table foo (
|
||||
col1 varchar(4) generated by default as identity not null,
|
||||
col2 varchar(30) not null,
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean external mapping api</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.15.1</tag>
|
||||
<tag>ebean-parent-12.16.0</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean external mapping xml</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -59,21 +59,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1-SNAPSHOT</version>
|
||||
<version>12.16.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1-SNAPSHOT</version>
|
||||
<version>12.16.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -44,14 +44,14 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.15.1-SNAPSHOT</version>
|
||||
<version>12.16.0-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+6
-13
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean postgis</name>
|
||||
@@ -14,7 +14,7 @@
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
|
||||
<properties>
|
||||
<postgis.jdbc.version>2.2.1</postgis.jdbc.version>
|
||||
<postgis.jdbc.version>2.5.1</postgis.jdbc.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<dependency>
|
||||
<groupId>net.postgis</groupId>
|
||||
<artifactId>postgis-jdbc</artifactId>
|
||||
<version>[${postgis.jdbc.version}]</version>
|
||||
<version>${postgis.jdbc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- expected to be provided -->
|
||||
@@ -64,17 +64,10 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -88,7 +81,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import org.postgis.Geometry;
|
||||
import org.postgis.GeometryBuilder;
|
||||
import org.postgis.PGgeometry;
|
||||
import org.postgis.PGgeometryLW;
|
||||
import org.postgis.binary.BinaryParser;
|
||||
import org.postgresql.util.PGobject;
|
||||
|
||||
import java.io.DataInput;
|
||||
@@ -51,7 +53,7 @@ abstract class ScalarTypePgisBase<T extends Geometry> implements ScalarType<T> {
|
||||
return (T) ((PGgeometry) object).getGeometry();
|
||||
|
||||
} else if (object instanceof PGobject) {
|
||||
return (T) PGgeometry.geomFromString(((PGobject) object).getValue());
|
||||
return (T) GeometryBuilder.geomFromString(((PGobject) object).getValue(), new BinaryParser(), false);
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException("Could not convert from " + object.getClass() + " to " + cls);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean querybean</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -56,28 +56,28 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+7
-7
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
@@ -22,42 +22,42 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean test</name>
|
||||
@@ -29,14 +29,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.15.1</version>
|
||||
<version>12.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -233,7 +233,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -235,6 +235,9 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
case SQLSERVER17: // these DBs are 'standard based' so they also do not support HistoryExclude
|
||||
case MARIADB:
|
||||
case HANA:
|
||||
case DB2LUW:
|
||||
case DB2FORI: // not yet tested
|
||||
case DB2ZOS: // not yet tested
|
||||
assertThat(versions2.get(0).getDiff().toString()).as("using platform: %s, versions2:%s", server().platform(), versions2)
|
||||
.contains("testString=foo2,foo1")
|
||||
.contains("testString2=bar2,bar1");
|
||||
|
||||
+37
-14
@@ -4,17 +4,21 @@ import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import io.ebean.config.MdcBackgroundExecutorWrapper;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class DefaultBackgroundExecutorTest {
|
||||
|
||||
@Test
|
||||
public void submit_callable() throws Exception {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 2, "test");
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 2, "test", null);
|
||||
|
||||
final Future<String> future0 = es.submit(() -> "Hello");
|
||||
final Future<String> future1 = es.submit(() -> "There");
|
||||
@@ -39,7 +43,7 @@ public class DefaultBackgroundExecutorTest {
|
||||
public void shutdown_slowCallable_expect_interrupted() throws Exception {
|
||||
|
||||
int shutdownWaitSecs = 1;
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, shutdownWaitSecs, "test");
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, shutdownWaitSecs, "test", null);
|
||||
|
||||
final Future<String> future2 = es.submit(() -> {
|
||||
try {
|
||||
@@ -61,7 +65,7 @@ public class DefaultBackgroundExecutorTest {
|
||||
@Disabled("test takes long time")
|
||||
public void shutdown_when_running_expect_waitAndNiceShutdown() {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 20, "test");
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 20, "test", null);
|
||||
|
||||
es.execute(new RunFor(3000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
@@ -74,7 +78,7 @@ public class DefaultBackgroundExecutorTest {
|
||||
@Disabled("test takes long time")
|
||||
public void shutdown_when_rougeRunnable_expect_InterruptedException() {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test", null);
|
||||
|
||||
es.execute(new RunFor(300000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
@@ -85,12 +89,12 @@ public class DefaultBackgroundExecutorTest {
|
||||
|
||||
@Test
|
||||
public void wrapWithNoMDC() {
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test", null);
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
es.wrapMDC(() -> {
|
||||
es.wrap(() -> {
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
});
|
||||
es.wrapMDC(() -> {
|
||||
es.wrap(() -> {
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
return "Callable";
|
||||
});
|
||||
@@ -98,25 +102,44 @@ public class DefaultBackgroundExecutorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapWithMDC_expect_() {
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
public void wrapWithMDC_expect_() throws Exception {
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test", new MdcBackgroundExecutorWrapper());
|
||||
// MDC has a copyOnThread map. So we must pass different values to check if the test will work
|
||||
MDC.clear();
|
||||
es.submit(()->{
|
||||
assertThat(MDC.get("hello")).isNull();
|
||||
}).get();
|
||||
|
||||
MDC.put("hello", "there");
|
||||
es.wrapMDC(() -> {
|
||||
es.wrap(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
});
|
||||
es.wrapMDC(() -> {
|
||||
}).run(); // will clear the MDC. But this should be OK
|
||||
|
||||
MDC.put("hello", "there");
|
||||
es.wrap(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
return "Callable";
|
||||
});
|
||||
}).call(); // will clear the MDC. But this should be OK
|
||||
|
||||
MDC.put("hello", "there");
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
es.execute(() -> {
|
||||
// the assertion is executed async, so it will only logged on console
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
latch.countDown();
|
||||
});
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
es.submit(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
return "Callable";
|
||||
});
|
||||
}).get();
|
||||
MDC.clear();
|
||||
|
||||
es.execute(()->{
|
||||
assertThat(MDC.get("hello")).isNull();
|
||||
});
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -9,7 +9,6 @@ class BasicProfileLocationTest {
|
||||
|
||||
@Test
|
||||
void obtain() {
|
||||
|
||||
DProfileLocation loc = new DTimedProfileLocation(12, "foo", MetricFactory.get().createTimedMetric("junk"));
|
||||
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
@@ -18,7 +17,7 @@ class BasicProfileLocationTest {
|
||||
assertThat(loc.fullLocation()).endsWith("invoke0(Native Method:12)");
|
||||
assertThat(loc.location()).isEqualTo("sun.reflect.NativeMethodAccessorImpl.invoke0");
|
||||
assertThat(loc.label()).isEqualTo("NativeMethodAccessorImpl.invoke0");
|
||||
} else if (javaVersion.startsWith("18")){
|
||||
} else if (javaVersion.startsWith("18") || javaVersion.startsWith("19")){
|
||||
assertThat(loc.fullLocation()).endsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)");
|
||||
assertThat(loc.location()).isEqualTo("java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke");
|
||||
assertThat(loc.label()).isEqualTo("DirectMethodHandleAccessor.invoke");
|
||||
@@ -31,7 +30,6 @@ class BasicProfileLocationTest {
|
||||
|
||||
@Test
|
||||
void basic_trimPackage() {
|
||||
|
||||
BasicProfileLocation loc = new BasicProfileLocation("com.foo.Bar.all");
|
||||
assertThat(loc.obtain()).isFalse();
|
||||
assertThat(loc.fullLocation()).isEqualTo("com.foo.Bar.all");
|
||||
@@ -41,7 +39,6 @@ class BasicProfileLocationTest {
|
||||
|
||||
@Test
|
||||
void basic_trimSinglePackage() {
|
||||
|
||||
BasicProfileLocation loc = new BasicProfileLocation("foo.Bar.all");
|
||||
assertThat(loc.obtain()).isFalse();
|
||||
assertThat(loc.fullLocation()).isEqualTo("foo.Bar.all");
|
||||
|
||||
@@ -2,11 +2,9 @@ package misc.migration.v1_1;
|
||||
|
||||
|
||||
import io.ebean.annotation.DbDefault;
|
||||
import io.ebean.annotation.DbMigration;
|
||||
import io.ebean.annotation.History;
|
||||
import io.ebean.annotation.HistoryExclude;
|
||||
import io.ebean.annotation.NotNull;
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
@@ -22,13 +20,6 @@ public class EHistory2 {
|
||||
Integer id;
|
||||
|
||||
@NotNull
|
||||
// see: https://mariadb.com/de/resources/blog/use-cases-for-mariadb-data-versioning/
|
||||
@DbMigration(preAlter = {
|
||||
"SET @@system_versioning_alter_history = 1",
|
||||
"update ${table} set ${column} = 'unknown' where ${column} is null"}, platforms = Platform.MARIADB)
|
||||
|
||||
// other platforms
|
||||
@DbMigration(preAlter = "update ${table} set ${column} = 'unknown' where ${column} is null")
|
||||
@DbDefault("unknown")
|
||||
String testString;
|
||||
|
||||
|
||||
@@ -8,13 +8,14 @@ import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.EBasicClobNoVer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestBasicClobNoVer extends BaseTestCase {
|
||||
class TestBasicClobNoVer extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
void test() {
|
||||
|
||||
EBasicClobNoVer entity = new EBasicClobNoVer();
|
||||
entity.setName("test");
|
||||
@@ -65,4 +66,36 @@ public class TestBasicClobNoVer extends BaseTestCase {
|
||||
assertThat(entity.getDescription()).isEqualTo("modified");
|
||||
}
|
||||
|
||||
@Test
|
||||
void refresh_withSoftDelete() {
|
||||
|
||||
EBasicClobNoVer bean = new EBasicClobNoVer();
|
||||
bean.setDescription("hello");
|
||||
DB.save(bean);
|
||||
|
||||
DB.refresh(bean);
|
||||
|
||||
LoggedSql.start();
|
||||
bean.children().forEach(System.out::println);
|
||||
List<String> sql = LoggedSql.stop();
|
||||
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains(" and t0.deleted =");
|
||||
}
|
||||
|
||||
@Test
|
||||
void largeValueInsert() {
|
||||
EBasicClobNoVer bean = new EBasicClobNoVer();
|
||||
bean.setDescription(largeContent());
|
||||
DB.save(bean);
|
||||
}
|
||||
|
||||
private String largeContent() {
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 1048577; i++) {
|
||||
sb.append((char) (random.nextInt(26) + 'a'));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.tests.cache;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.OCachedBean;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.config.BackgroundExecutorWrapper;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.MdcBackgroundExecutorWrapper;
|
||||
import io.ebeaninternal.server.cache.DefaultServerCachePlugin;
|
||||
|
||||
/**
|
||||
* Test class testing async/background cache updates in a multi-tenant environment.
|
||||
*/
|
||||
public class TestBeanCacheAsync extends BaseTestCase {
|
||||
|
||||
private final ThreadLocal<String> tenantId = new ThreadLocal<>();
|
||||
|
||||
class ThreadLocalTenantProvider implements CurrentTenantProvider {
|
||||
|
||||
@Override
|
||||
public Object currentId() {
|
||||
return tenantId.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy tenant info to the background thread.
|
||||
*/
|
||||
class TenantCopyBackgroundExecutorWrapper implements BackgroundExecutorWrapper {
|
||||
@Override
|
||||
public <T> Callable<T> wrap(Callable<T> task) {
|
||||
String tenant = tenantId.get(); // executed in current thread
|
||||
return () -> {
|
||||
tenantId.set(tenant); // executed in other thread
|
||||
try {
|
||||
return task.call();
|
||||
} finally {
|
||||
tenantId.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable wrap(Runnable task) {
|
||||
String tenant = tenantId.get();
|
||||
return () -> {
|
||||
tenantId.set(tenant);
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
tenantId.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findById_with_tenant() throws InterruptedException {
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName(DB.getDefault().name());
|
||||
config.loadFromProperties();
|
||||
config.setDataSource(DB.getDefault().dataSource());
|
||||
config.setReadOnlyDataSource(DB.getDefault().readOnlyDataSource());
|
||||
config.setDdlExtra(false);
|
||||
config.setDdlGenerate(false);
|
||||
config.setDdlRun(false);
|
||||
config.setDefaultServer(false);
|
||||
config.setRegister(false);
|
||||
config.setServerCachePlugin(new DefaultServerCachePlugin()); // disables foreground local caching (as it is done in Hz/Ignite)
|
||||
config.setCurrentTenantProvider(new ThreadLocalTenantProvider());
|
||||
config.setBackgroundExecutorWrapper(
|
||||
new MdcBackgroundExecutorWrapper().with(new TenantCopyBackgroundExecutorWrapper()));
|
||||
tenantId.set("4711");
|
||||
|
||||
Database db = DatabaseFactory.create(config);
|
||||
try {
|
||||
OCachedBean bean = new OCachedBean();
|
||||
bean.setName("findById");
|
||||
db.save(bean);
|
||||
|
||||
OCachedBean bean0 = db.find(OCachedBean.class, bean.getId());
|
||||
assertNotNull(bean0);
|
||||
assertThat(bean0.getName()).isEqualTo("findById");
|
||||
bean0.setName("findById2");
|
||||
db.save(bean0);
|
||||
|
||||
Thread.sleep(100); // TODO: can we block finds on that ID if a pending cache update is present?
|
||||
|
||||
bean0 = db.find(OCachedBean.class, bean.getId());
|
||||
assertNotNull(bean0);
|
||||
assertThat(bean0.getName()).isEqualTo("findById2");
|
||||
|
||||
} finally {
|
||||
db.shutdown(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,9 @@ package org.tests.model.basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class EBasicClobNoVer {
|
||||
@@ -18,6 +21,9 @@ public class EBasicClobNoVer {
|
||||
@Lob
|
||||
private String description;
|
||||
|
||||
@OneToMany
|
||||
private List<EBasicClobNoVerChild> children = new ArrayList<>();
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
@@ -41,4 +47,13 @@ public class EBasicClobNoVer {
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<EBasicClobNoVerChild> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public EBasicClobNoVer children(List<EBasicClobNoVerChild> children) {
|
||||
this.children = children;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.tests.model.basic;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class EBasicClobNoVerChild {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private final EBasicClobNoVer parent;
|
||||
|
||||
private final String child;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
public EBasicClobNoVerChild(EBasicClobNoVer parent, String child) {
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public Long id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public EBasicClobNoVerChild id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String child() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public boolean deleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public EBasicClobNoVerChild deleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -9,10 +9,10 @@ import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestMTOInheritNoDiscriminator extends BaseTestCase {
|
||||
class TestMTOInheritNoDiscriminator extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
void test() {
|
||||
|
||||
final TTruckHolder holder = setup();
|
||||
|
||||
@@ -31,7 +31,7 @@ public class TestMTOInheritNoDiscriminator extends BaseTestCase {
|
||||
|
||||
assertThat(sql).hasSize(1);
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertSql(sql.get(0)).contains("select t0.id, t0.name, t0.version, t2.type, t0.truck_plate_no, t0.basic_id, t1.id, t1.some_uid, t1.foo, t1.owner_id from ttruck_holder t0 join tcar t2 on t2.plate_no = t0.truck_plate_no left join ttruck_holder_item t1 on t1.owner_id = t0.id where t0.id = ? order by t0.id");
|
||||
assertSql(sql.get(0)).contains("select t0.id, t0.name, t0.version, t2.type, t0.truck_plate_no, t0.basic_id, t1.id, t1.some_uid, t1.foo, t1.owner_id from ttruck_holder t0 left join ttruck_holder_item t1 on t1.owner_id = t0.id join tcar t2 on t2.plate_no = t0.truck_plate_no where t0.id = ? order by t0.id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class TestHistoryExclude extends BaseTestCase {
|
||||
linkFound.getDocs().size();
|
||||
}
|
||||
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.DB2, Platform.COCKROACH})
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.COCKROACH})
|
||||
@Test
|
||||
public void testAsOfThenLazy() {
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public class TestHistoryInclude extends BaseTestCase {
|
||||
assertThat(linkFound.getDocs().size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.DB2, Platform.COCKROACH})
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.COCKROACH})
|
||||
@Test
|
||||
public void testAsOfThenLazy() {
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestHistoryOneToMany extends BaseTestCase {
|
||||
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.DB2, Platform.COCKROACH})
|
||||
@IgnorePlatform({Platform.ORACLE, Platform.COCKROACH})
|
||||
@Test
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.tests.model.join;
|
||||
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
@DiscriminatorValue("A")
|
||||
@Entity
|
||||
public class AccountAccess extends HAccess {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user