mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
73
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0f171b638 | ||
|
|
2bb52a9581 | ||
|
|
f1cf94365c | ||
|
|
a894924e96 | ||
|
|
680a11a532 | ||
|
|
605150de5c | ||
|
|
5ff44703cf | ||
|
|
99175bf679 | ||
|
|
acff330b37 | ||
|
|
df63eeaa8c | ||
|
|
07aa39c5de | ||
|
|
c51a1b07a4 | ||
|
|
bb56725b12 | ||
|
|
099adcf6cd | ||
|
|
05be24b8b2 | ||
|
|
7d98355d39 | ||
|
|
56562915bf | ||
|
|
07f4ad2500 | ||
|
|
22e43f5fa7 | ||
|
|
3127bc2154 | ||
|
|
8aa1ed6676 | ||
|
|
8a0dea1218 | ||
|
|
1e266a1532 | ||
|
|
57cfd25eb5 | ||
|
|
2bcce2e648 | ||
|
|
f6e45a6999 | ||
|
|
fa3de7158e | ||
|
|
792785dabe | ||
|
|
d0cd74b400 | ||
|
|
71d762ab97 | ||
|
|
e00713aa29 | ||
|
|
d70a49e105 | ||
|
|
159a9a8e54 | ||
|
|
db027eb030 | ||
|
|
ec55b2f096 | ||
|
|
b854943a86 | ||
|
|
8a263d243c | ||
|
|
0a4f93adc5 | ||
|
|
ffb11019fa | ||
|
|
6fcac27dfe | ||
|
|
71295077a5 | ||
|
|
ddbad284ad | ||
|
|
1fcec429b0 | ||
|
|
c6062fe93e | ||
|
|
d8d35b7dd9 | ||
|
|
590cd07d67 | ||
|
|
5cd74bc468 | ||
|
|
502b20be67 | ||
|
|
b3077d44f6 | ||
|
|
d4b35cb445 | ||
|
|
91e7540a39 | ||
|
|
06bd60aaf7 | ||
|
|
3db2a69312 | ||
|
|
5a983b9e0d | ||
|
|
ab7b34779a | ||
|
|
c7aad6078e | ||
|
|
ccfe9c39cd | ||
|
|
dbdac04883 | ||
|
|
1d369c002d | ||
|
|
5a1be81603 | ||
|
|
dee73da1aa | ||
|
|
a7dde87c5f | ||
|
|
60fadd448d | ||
|
|
0140d09007 | ||
|
|
da5604a38d | ||
|
|
937df1395c | ||
|
|
89c05007c2 | ||
|
|
4cc9278183 | ||
|
|
9841a2c03a | ||
|
|
74929472d9 | ||
|
|
e274a4c512 | ||
|
|
5d93c44475 | ||
|
|
63b802d0b8 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.1.5</version>
|
||||
<version>12.1.11</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-12.1.5</tag>
|
||||
<tag>ebean-12.1.11</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -118,25 +118,25 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.1</version>
|
||||
<version>6.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-types</artifactId>
|
||||
<version>1.3</version>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>4.6.1</version>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.1.1</version>
|
||||
<version>12.1.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -308,9 +308,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>2.1</version>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>mod-uuid</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -323,7 +323,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.1.5</version>
|
||||
<version>12.1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
@@ -384,23 +384,7 @@
|
||||
<configuration>
|
||||
<doctitle>Ebean 12</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</docletArtifact>
|
||||
<!-- for people using JDK11, our javadoc doclet isn't 11 compatible yet -->
|
||||
<javadocExecutable>${env.JAVA8_HOME}/bin/javadoc</javadocExecutable>
|
||||
<additionalparam>
|
||||
-Xdoclint:none
|
||||
-include-basedir ${project.basedir}
|
||||
-attributes "idseparator=-; project_name=${project.name}; \
|
||||
project_version=${project.version}; \
|
||||
project_desc=${project.description}"
|
||||
</additionalparam>
|
||||
<linksource>true</linksource>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
</configuration>
|
||||
|
||||
@@ -736,8 +736,11 @@ public class DB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlQuery().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlQuery(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlQuery createSqlQuery(String sql) {
|
||||
return sqlQuery(sql);
|
||||
}
|
||||
@@ -760,8 +763,11 @@ public class DB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlUpdate().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlUpdate(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return sqlUpdate(sql);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebean;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
@@ -465,8 +464,11 @@ public interface Database {
|
||||
SqlQuery sqlQuery(String sql);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlQuery().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlQuery(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
SqlQuery createSqlQuery(String sql);
|
||||
|
||||
/**
|
||||
@@ -485,8 +487,11 @@ public interface Database {
|
||||
SqlUpdate sqlUpdate(String sql);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to sqlUpdate().
|
||||
* <p>
|
||||
* This is an alias for {@link #sqlUpdate(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
SqlUpdate createSqlUpdate(String sql);
|
||||
|
||||
/**
|
||||
@@ -856,7 +861,7 @@ public interface Database {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -1051,7 +1056,6 @@ public interface Database {
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
int execute(CallableSql callableSql);
|
||||
|
||||
@@ -1299,7 +1303,7 @@ public interface Database {
|
||||
* public void run() {
|
||||
* User u1 = database.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
@@ -1348,7 +1352,7 @@ public interface Database {
|
||||
* User u1 = database.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -24,6 +24,8 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Ebean will be Deprecated - please migrate to use DB.
|
||||
* <p>
|
||||
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
|
||||
* <p>
|
||||
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
|
||||
@@ -462,7 +464,7 @@ public final class Ebean {
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -865,6 +867,8 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to DB.sqlQuery().
|
||||
* <p>
|
||||
* Create a SqlQuery for executing native sql
|
||||
* query statements.
|
||||
* <p>
|
||||
@@ -872,22 +876,24 @@ public final class Ebean {
|
||||
* annotation for examples.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlQuery createSqlQuery(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlQuery(sql);
|
||||
return serverMgr.getDefaultServer().sqlQuery(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to DB.sqlUpdate().
|
||||
* <p>
|
||||
* Create a sql update for executing native dml statements.
|
||||
* <p>
|
||||
* Use this to execute a Insert Update or Delete statement. The statement will
|
||||
* be native to the database and contain database table and column names.
|
||||
* </p>
|
||||
* <p>
|
||||
* See {@link SqlUpdate} for example usage.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return serverMgr.getDefaultServer().createSqlUpdate(sql);
|
||||
return serverMgr.getDefaultServer().sqlUpdate(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1193,7 +1199,7 @@ public final class Ebean {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
@@ -1245,7 +1251,7 @@ public final class Ebean {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -21,7 +21,7 @@ public class EbeanVersion {
|
||||
static {
|
||||
try {
|
||||
Properties prop = new Properties();
|
||||
try (InputStream in = Ebean.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
|
||||
if (in != null) {
|
||||
prop.load(in);
|
||||
in.close();
|
||||
|
||||
@@ -34,14 +34,14 @@ public class Expr {
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().eq(propertyName, value);
|
||||
return DB.getExpressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ne(propertyName, value);
|
||||
return DB.getExpressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ public class Expr {
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
return DB.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,28 +59,28 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression inRange(String propertyName, Object value1, Object value2) {
|
||||
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
return DB.getExpressionFactory().inRange(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
return DB.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
return DB.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().gt(propertyName, value);
|
||||
return DB.getExpressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,42 +88,42 @@ public class Expr {
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ge(propertyName, value);
|
||||
return DB.getExpressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().lt(propertyName, value);
|
||||
return DB.getExpressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().le(propertyName, value);
|
||||
return DB.getExpressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNull(propertyName);
|
||||
return DB.getExpressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotNull(propertyName);
|
||||
return DB.getExpressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().iexampleLike(example);
|
||||
return DB.getExpressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,14 +131,14 @@ public class Expr {
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example);
|
||||
return DB.getExpressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
return DB.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ public class Expr {
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().like(propertyName, value);
|
||||
return DB.getExpressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,14 +155,14 @@ public class Expr {
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ilike(propertyName, value);
|
||||
return DB.getExpressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().startsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,14 +170,14 @@ public class Expr {
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().endsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,14 +185,14 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
|
||||
return DB.getExpressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().contains(propertyName, value);
|
||||
return DB.getExpressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,42 +200,42 @@ public class Expr {
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
return DB.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are empty (have not existing elements).
|
||||
*/
|
||||
public static Expression isEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isEmpty(propertyName);
|
||||
return DB.getExpressionFactory().isEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For collection properties that are not empty (have existing elements).
|
||||
*/
|
||||
public static Expression isNotEmpty(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
|
||||
return DB.getExpressionFactory().isNotEmpty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, subQuery);
|
||||
return DB.getExpressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
return DB.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,14 +272,14 @@ public class Expr {
|
||||
* }</pre>
|
||||
*/
|
||||
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
return DB.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return Ebean.getExpressionFactory().idEq(value);
|
||||
return DB.getExpressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +292,7 @@ public class Expr {
|
||||
* @param propertyMap a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return Ebean.getExpressionFactory().allEq(propertyMap);
|
||||
return DB.getExpressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,7 +303,7 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return Ebean.getExpressionFactory().raw(raw, value);
|
||||
return DB.getExpressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,14 +314,14 @@ public class Expr {
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return Ebean.getExpressionFactory().raw(raw, values);
|
||||
return DB.getExpressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return Ebean.getExpressionFactory().raw(raw);
|
||||
return DB.getExpressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,7 +329,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().and(expOne, expTwo);
|
||||
return DB.getExpressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,7 +337,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().or(expOne, expTwo);
|
||||
return DB.getExpressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +345,7 @@ public class Expr {
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return Ebean.getExpressionFactory().not(exp);
|
||||
return DB.getExpressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,7 +353,7 @@ public class Expr {
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().conjunction(query);
|
||||
return DB.getExpressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,6 +361,6 @@ public class Expr {
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().disjunction(query);
|
||||
return DB.getExpressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public interface Filter<T> {
|
||||
* expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Refer to {@link Ebean#sort(List, String)} for more detail.
|
||||
* Refer to {@link DB#sort(List, String)} for more detail.
|
||||
* </p>
|
||||
*/
|
||||
Filter<T> sort(String sortByClause);
|
||||
|
||||
@@ -50,4 +50,13 @@ public interface ScriptRunner {
|
||||
*/
|
||||
void run(URL resource, Map<String, String> placeholderMap);
|
||||
|
||||
/**
|
||||
* Run the raw provided DDL or SQL script.
|
||||
*
|
||||
* @param name The name of the script for logging purposes
|
||||
* @param content The SQL content
|
||||
* @param useAutoCommit Set to true to use auto commit true and continue when any errors occur
|
||||
*/
|
||||
void runScript(String name, String content, boolean useAutoCommit);
|
||||
|
||||
}
|
||||
|
||||
@@ -126,8 +126,6 @@ public interface SqlUpdate {
|
||||
* {@link Transaction#setBatchMode(boolean)} and
|
||||
* {@link Transaction#setBatchSize(int)}.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
int execute();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* @see Database#currentTransaction()
|
||||
*/
|
||||
static Transaction current() {
|
||||
return Ebean.currentTransaction();
|
||||
return DB.currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,16 +12,16 @@ import java.util.concurrent.Callable;
|
||||
* <p>
|
||||
* This information matches the features of the Transactional annotation. You
|
||||
* can use it directly with Runnable or Callable via
|
||||
* {@link Ebean#execute(TxScope, Runnable)} or
|
||||
* {@link Ebean#executeCall(TxScope, Callable)}.
|
||||
* {@link DB#execute(TxScope, Runnable)} or
|
||||
* {@link DB#executeCall(TxScope, Callable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#execute(TxScope, Runnable)
|
||||
* @see Ebean#executeCall(TxScope, Callable)
|
||||
* @see DB#execute(TxScope, Runnable)
|
||||
* @see DB#executeCall(TxScope, Callable)
|
||||
*/
|
||||
public final class TxScope {
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.ValuePair;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
@@ -104,9 +105,6 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
/**
|
||||
* Create a intercept with a given entity.
|
||||
* <p>
|
||||
* Refer to agent ProxyConstructor.
|
||||
* </p>
|
||||
*/
|
||||
public EntityBeanIntercept(Object ownerBean) {
|
||||
this.owner = (EntityBean) ownerBean;
|
||||
@@ -821,14 +819,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
synchronized (this) {
|
||||
if (beanLoader == null) {
|
||||
BeanLoader serverLoader = (BeanLoader) Ebean.getServer(ebeanServerName);
|
||||
if (serverLoader == null) {
|
||||
throw new PersistenceException("Server [" + ebeanServerName + "] was not found?");
|
||||
final Database database = DB.byName(ebeanServerName);
|
||||
if (database == null) {
|
||||
throw new PersistenceException("Database [" + ebeanServerName + "] was not found?");
|
||||
}
|
||||
|
||||
// For stand alone reference bean or after deserialisation lazy load
|
||||
// using the ebeanServer. Synchronise only on the bean.
|
||||
loadBeanInternal(loadProperty, serverLoader);
|
||||
loadBeanInternal(loadProperty, database.getPluginApi());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.Database;
|
||||
|
||||
/**
|
||||
* BeanLoader used when single beans are loaded (which is usually not ideal / N+1).
|
||||
*/
|
||||
public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
protected final Database database;
|
||||
|
||||
SingleBeanLoader(Database database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return database.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Single bean lazy loaded when bean from L2 cache.
|
||||
*/
|
||||
public static class L2 extends SingleBeanLoader {
|
||||
public L2(Database database) {
|
||||
super(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBeanL2(ebi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single bean lazy loaded when a reference bean.
|
||||
*/
|
||||
public static class Ref extends SingleBeanLoader {
|
||||
public Ref(Database database) {
|
||||
super(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBeanRef(ebi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
@@ -93,7 +93,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
loader = (BeanCollectionLoader) DB.byName(ebeanServerName);
|
||||
}
|
||||
loader.loadMany(this, onlyIds);
|
||||
checkEmptyLazyLoad();
|
||||
|
||||
@@ -88,7 +88,6 @@ public class DbConstraintNaming {
|
||||
* Return the primary key constraint name.
|
||||
*/
|
||||
public String primaryKeyName(String tableName) {
|
||||
|
||||
return pkPrefix + normaliseTable(tableName) + pkSuffix;
|
||||
}
|
||||
|
||||
@@ -103,7 +102,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name associated with a foreign key constraint given multiple columns.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
@@ -112,7 +110,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name associated with a foreign key constraint given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
@@ -121,7 +118,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
@@ -130,7 +126,6 @@ public class DbConstraintNaming {
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
@@ -139,7 +134,6 @@ public class DbConstraintNaming {
|
||||
* Join the column names together with underscores.
|
||||
*/
|
||||
protected String joinColumnNames(String[] columns) {
|
||||
|
||||
if (columns.length == 1) {
|
||||
return normaliseColumn(columns[0]);
|
||||
}
|
||||
@@ -157,7 +151,6 @@ public class DbConstraintNaming {
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String columnName) {
|
||||
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
|
||||
}
|
||||
|
||||
@@ -165,7 +158,6 @@ public class DbConstraintNaming {
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix;
|
||||
}
|
||||
@@ -174,7 +166,6 @@ public class DbConstraintNaming {
|
||||
* Return the check constraint name.
|
||||
*/
|
||||
public String checkConstraintName(String tableName, String columnName) {
|
||||
|
||||
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,20 @@ public class DbConstraintNormalise {
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the column name by removing any quoted identifier characters.
|
||||
* Normalise the column name by removing any quoted identifier characters and formula brackets.
|
||||
*/
|
||||
public String normaliseColumn(String columnName) {
|
||||
|
||||
columnName = trimQuotes(columnName);
|
||||
columnName = trimBrackets(trimQuotes(columnName));
|
||||
if (lowerCaseColumns) {
|
||||
columnName = columnName.toLowerCase();
|
||||
}
|
||||
return columnName;
|
||||
}
|
||||
|
||||
private String trimBrackets(String value) {
|
||||
return value.replace("(","").replace(")","");
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower case the table name checking for quoted identifiers.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used by generated code to hold entity classes to register with Ebean.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ModuleInfo {
|
||||
|
||||
/**
|
||||
* Returns the entity classes with db name prefix.
|
||||
* <p>
|
||||
* The db name prefix is added to entity classes for non default databases.
|
||||
*/
|
||||
String[] entities() default {};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loads and returns entity classes to register with Ebean databases.
|
||||
*/
|
||||
public interface ModuleInfoLoader {
|
||||
|
||||
/**
|
||||
* Return the entity classes to register with the default DB.
|
||||
*/
|
||||
List<Class<?>> entityClasses();
|
||||
|
||||
/**
|
||||
* Return entity classes to register for a named DB (not default DB).
|
||||
*/
|
||||
List<Class<?>> entityClassesFor(String dbName);
|
||||
}
|
||||
@@ -17,6 +17,13 @@ public class PlatformConfig {
|
||||
|
||||
private boolean allQuotedIdentifiers;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
/**
|
||||
* Flag set when a supplied constraintNaming is used.
|
||||
*/
|
||||
private boolean customConstraintNaming;
|
||||
|
||||
/**
|
||||
* The database boolean true value (typically either 1, T, or Y).
|
||||
*/
|
||||
@@ -63,7 +70,7 @@ public class PlatformConfig {
|
||||
* Construct with defaults.
|
||||
*/
|
||||
public PlatformConfig() {
|
||||
|
||||
this.constraintNaming = new DbConstraintNaming();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +87,19 @@ public class PlatformConfig {
|
||||
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
|
||||
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
|
||||
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
|
||||
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
|
||||
}
|
||||
|
||||
public DbConstraintNaming getConstraintNaming() {
|
||||
return constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom database constraint naming convention.
|
||||
*/
|
||||
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
|
||||
this.customConstraintNaming = true;
|
||||
this.constraintNaming = constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +114,9 @@ public class PlatformConfig {
|
||||
*/
|
||||
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
|
||||
this.allQuotedIdentifiers = allQuotedIdentifiers;
|
||||
if (!customConstraintNaming) {
|
||||
this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -132,6 +132,15 @@ public class ServerConfig {
|
||||
|
||||
private TenantCatalogProvider tenantCatalogProvider;
|
||||
|
||||
/**
|
||||
* When true will load entity classes via ModuleInfoLoader.
|
||||
* <p>
|
||||
* NB: ModuleInfoLoader implementations are generated by querybean generator.
|
||||
* Having this on and registering entity classes means we don't need to manually
|
||||
* write that code or use classpath scanning to find entity classes.
|
||||
*/
|
||||
private boolean loadModuleInfo;
|
||||
|
||||
/**
|
||||
* List of interesting classes such as entities, embedded, ScalarTypes,
|
||||
* Listeners, Finders, Controllers etc.
|
||||
@@ -344,11 +353,6 @@ public class ServerConfig {
|
||||
*/
|
||||
private NamingConvention namingConvention = new UnderscoreNamingConvention();
|
||||
|
||||
/**
|
||||
* Naming convention used in DDL generation for primary keys, foreign keys etc.
|
||||
*/
|
||||
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
|
||||
|
||||
/**
|
||||
* Behaviour of updates in JDBC batch to by default include all properties.
|
||||
*/
|
||||
@@ -488,6 +492,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean collectQueryPlans;
|
||||
|
||||
/**
|
||||
* The default threshold in micros for collecting query plans.
|
||||
*/
|
||||
private long collectQueryPlanThresholdMicros = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* The time in millis used to determine when a query is alerted for being slow.
|
||||
*/
|
||||
@@ -1600,14 +1609,14 @@ public class ServerConfig {
|
||||
* Return the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public DbConstraintNaming getConstraintNaming() {
|
||||
return constraintNaming;
|
||||
return platformConfig.getConstraintNaming();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
|
||||
this.constraintNaming = constraintNaming;
|
||||
platformConfig.setConstraintNaming(constraintNaming);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2276,12 +2285,18 @@ public class ServerConfig {
|
||||
* server.
|
||||
*/
|
||||
public void addClass(Class<?> cls) {
|
||||
if (classes == null) {
|
||||
classes = new ArrayList<>();
|
||||
}
|
||||
classes.add(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the classes (typically entity classes).
|
||||
*/
|
||||
public void addAll(List<Class<?>> classList) {
|
||||
if (classList != null && !classList.isEmpty()) {
|
||||
classes.addAll(classList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a package to search for entities via class path search.
|
||||
* <p>
|
||||
@@ -2289,9 +2304,6 @@ public class ServerConfig {
|
||||
* </p>
|
||||
*/
|
||||
public void addPackage(String packageName) {
|
||||
if (packages == null) {
|
||||
packages = new ArrayList<>();
|
||||
}
|
||||
packages.add(packageName);
|
||||
}
|
||||
|
||||
@@ -2838,12 +2850,14 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
|
||||
collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
@@ -2962,20 +2976,20 @@ public class ServerConfig {
|
||||
return classes;
|
||||
}
|
||||
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
List<Class<?>> classList = new ArrayList<>();
|
||||
|
||||
String[] split = StringHelper.splitNames(classNames);
|
||||
for (String cn : split) {
|
||||
if (!"class".equalsIgnoreCase(cn)) {
|
||||
try {
|
||||
classes.add(Class.forName(cn));
|
||||
classList.add(Class.forName(cn));
|
||||
} catch (ClassNotFoundException e) {
|
||||
String msg = "Error registering class [" + cn + "] from [" + classNames + "]";
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
return classList;
|
||||
}
|
||||
|
||||
private List<String> getSearchList(String searchNames, List<String> defaultValue) {
|
||||
@@ -3229,6 +3243,20 @@ public class ServerConfig {
|
||||
this.collectQueryPlans = collectQueryPlans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan collection threshold in microseconds.
|
||||
*/
|
||||
public long getCollectQueryPlanThresholdMicros() {
|
||||
return collectQueryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query plan collection threshold in microseconds.
|
||||
*/
|
||||
public void setCollectQueryPlanThresholdMicros(long collectQueryPlanThresholdMicros) {
|
||||
this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if metrics should be dumped when the server is shutdown.
|
||||
*/
|
||||
@@ -3259,6 +3287,17 @@ public class ServerConfig {
|
||||
this.dumpMetricsOptions = dumpMetricsOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if entity classes should be loaded and registered via ModuleInfoLoader.
|
||||
* <p>
|
||||
* When false we either register entity classes via application code or use classpath
|
||||
* scanning to find and register entity classes.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isAutoLoadModuleInfo() {
|
||||
return loadModuleInfo && classes.isEmpty();
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -29,6 +29,8 @@ public class DbPlatformTypeMapping {
|
||||
|
||||
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
|
||||
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
private static final DbPlatformType CIDR_NATIVE = new DbPlatformType("cidr", false);
|
||||
private static final DbPlatformType CIDR_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
@SuppressWarnings("unused")
|
||||
@@ -110,6 +112,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_NATIVE);
|
||||
put(DbType.CIDR, CIDR_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
@@ -126,6 +129,7 @@ public class DbPlatformTypeMapping {
|
||||
// default to native UUID and override on platform configure()
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_VARCHAR);
|
||||
put(DbType.CIDR, CIDR_VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public enum DbType {
|
||||
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
INET(ExtraDbTypes.INET),
|
||||
CDIR(ExtraDbTypes.CDIR),
|
||||
CIDR(ExtraDbTypes.CIDR),
|
||||
|
||||
POINT(ExtraDbTypes.POINT),
|
||||
POLYGON(ExtraDbTypes.POLYGON),
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface ExtraDbTypes {
|
||||
int JSONBlob = 5005;
|
||||
|
||||
int INET = 5020;
|
||||
int CDIR = 5021;
|
||||
int CIDR = 5021;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CDIR, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("String", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,6 +65,8 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("json", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,8 +14,6 @@ public class Postgres8Platform extends PostgresPlatform {
|
||||
super();
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
this.columnAliasPrefix = "as c";
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
this.dbDefaultValue.setNow("current_timestamp");
|
||||
|
||||
@@ -51,7 +52,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("55P03")
|
||||
.addDuplicateKey("23505")
|
||||
.addDataIntegrity("23000","23502","23503","23514")
|
||||
.addDataIntegrity("23000", "23502", "23503", "23514")
|
||||
.addSerializableConflict("40001")
|
||||
.build();
|
||||
|
||||
@@ -63,6 +64,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
|
||||
dbTypeMap.put(DbType.CIDR, new DbPlatformType("cidr", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
@@ -127,7 +129,6 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
@Override
|
||||
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
|
||||
|
||||
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
|
||||
statement.setString(1, table);
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
@@ -138,18 +139,15 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return SQL using built in partition helper functions to create some initial partitions.
|
||||
*
|
||||
* <p>
|
||||
* Only use this if extra-ddl doesn't have some initial partitions defined (which it should).
|
||||
*/
|
||||
@Override
|
||||
public String tablePartitionInit(String tableName, PartitionMode mode, String property, String pkey) {
|
||||
if (property == null) {
|
||||
property = "";
|
||||
}
|
||||
if (pkey == null) {
|
||||
pkey = "";
|
||||
}
|
||||
return "select partition('" + mode.name().toLowerCase() + "','" + tableName + "','" + pkey + "','" + property + "',1);";
|
||||
// default partition required pg11 but this is only used for testing but bumped test docker container to pg11 by default
|
||||
return
|
||||
"create table " + tableName + "_default" + " partition of " + tableName + " default;\n" +
|
||||
"select partition('" + mode.name().toLowerCase() + "','" + tableName + "',1);";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.dbmigration;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -62,11 +62,28 @@ public interface DbMigration {
|
||||
*/
|
||||
void setPathToResources(String pathToResources);
|
||||
|
||||
/**
|
||||
* Set the path where migrations are generated to (which defaults to "dbmigration").
|
||||
* <p>
|
||||
* Normally we only use this when we use Ebean to generate the database migrations
|
||||
* and then use some other tool like FlywayDB to run the migrations.
|
||||
* <p>
|
||||
* Example: with <code>setMigrationPath("db/migration")</code> ... the migrations
|
||||
* are generated into <code>src/resources/db/migration</code>.
|
||||
* <p>
|
||||
* Note that if Ebean migration runner is used we should not use this method but
|
||||
* instead set the migrationPath via a property such that both the migration generator
|
||||
* and migration runner both use the same path.
|
||||
*
|
||||
* @param migrationPath The path that migrations are generated into.
|
||||
*/
|
||||
void setMigrationPath(String migrationPath);
|
||||
|
||||
/**
|
||||
* Set the server to use to determine the current model.
|
||||
* Typically this is not called explicitly.
|
||||
*/
|
||||
void setServer(EbeanServer ebeanServer);
|
||||
void setServer(Database database);
|
||||
|
||||
/**
|
||||
* Set the serverConfig to use. Typically this is not called explicitly.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.event;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Set;
|
||||
* Listen for bulk table events that occur.
|
||||
* <p>
|
||||
* These events can be triggered via
|
||||
* {@link Ebean#externalModification(String, boolean, boolean, boolean)} or
|
||||
* {@link DB#externalModification(String, boolean, boolean, boolean)} or
|
||||
* automatically determined from Ebean bulk update statements.
|
||||
*/
|
||||
public interface BulkTableEventListener {
|
||||
|
||||
@@ -33,11 +33,6 @@ public interface MetaInfoManager {
|
||||
*/
|
||||
List<MetricData> collectMetricsAsData();
|
||||
|
||||
/**
|
||||
* Collect query plans.
|
||||
*/
|
||||
List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request);
|
||||
|
||||
/**
|
||||
* Visit the metrics resetting and collecting/reporting as desired.
|
||||
*/
|
||||
@@ -54,4 +49,21 @@ public interface MetaInfoManager {
|
||||
*/
|
||||
void resetAllMetrics();
|
||||
|
||||
/**
|
||||
* Initiate query plan collection by turning on "bind capture" on matching query plans.
|
||||
* <p>
|
||||
* Also refer to ServerConfig collectQueryPlans that needs to be set to true
|
||||
* and collectQueryPlanThresholdMicros which is a global defaults that can also
|
||||
* initiate query plan capture.
|
||||
*
|
||||
* @return The query plans that have had bind capture turned on by this request.
|
||||
*/
|
||||
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest);
|
||||
|
||||
/**
|
||||
* Collect query plans in the foreground.
|
||||
*/
|
||||
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,4 @@ public interface MetaQueryMetric extends MetaTimedMetric {
|
||||
*/
|
||||
String getHash();
|
||||
|
||||
/**
|
||||
* Return true if this is the first metrics collection for this query.
|
||||
* <p>
|
||||
* This can be used to suppress including the SQL and location from metrics
|
||||
* content.
|
||||
* </p>
|
||||
*/
|
||||
boolean initialCollection();
|
||||
}
|
||||
|
||||
@@ -30,4 +30,13 @@ public interface MetaTimedMetric extends MetaMetric {
|
||||
* Return the mean execution time in micros.
|
||||
*/
|
||||
long getMean();
|
||||
|
||||
/**
|
||||
* Return true if this is the first metrics collection for this query.
|
||||
* <p>
|
||||
* This can be used to suppress including the SQL and location from metrics
|
||||
* content.
|
||||
* </p>
|
||||
*/
|
||||
boolean initialCollection();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Initiate query plan collection for plans by their hash or all query plans.
|
||||
*/
|
||||
public class QueryPlanInit {
|
||||
|
||||
private boolean all;
|
||||
|
||||
private Set<String> hashes = new HashSet<>();
|
||||
|
||||
private long thresholdMicros;
|
||||
|
||||
/**
|
||||
* Return true if this initiates bind collection on all query plans.
|
||||
*/
|
||||
public boolean isAll() {
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to initiate bind collection on all query plans.
|
||||
*/
|
||||
public void setAll(boolean all) {
|
||||
this.all = all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query execution time threshold which must be exceeded to initiate
|
||||
* query plan collection.
|
||||
*/
|
||||
public long getThresholdMicros() {
|
||||
return thresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query execution time threshold which must be exceeded to initiate
|
||||
* query plan collection.
|
||||
*/
|
||||
public void setThresholdMicros(long thresholdMicros) {
|
||||
this.thresholdMicros = thresholdMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query plan should be initiated based on it's hash.
|
||||
*/
|
||||
public boolean includeHash(String hash) {
|
||||
return all || hashes.contains(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specific hashes that we want to collect query plans on.
|
||||
*/
|
||||
public Set<String> getHashes() {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specific hashes that we want to collect query plans on.
|
||||
*/
|
||||
public void setHashes(Set<String> hashes) {
|
||||
this.hashes = hashes;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +1,66 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Request used to capture query plans.
|
||||
*/
|
||||
public class QueryPlanRequest {
|
||||
|
||||
private final List<MetaQueryPlan> plans = new ArrayList<>();
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private boolean store;
|
||||
|
||||
private long since;
|
||||
|
||||
private Set<Class<?>> includedBeanTypes;
|
||||
private int maxCount;
|
||||
|
||||
private Set<String> includedLabels;
|
||||
|
||||
public List<MetaQueryPlan> getPlans() {
|
||||
return plans;
|
||||
}
|
||||
private long maxTimeMillis;
|
||||
|
||||
/**
|
||||
* Return the connection to use to capture the query plans.
|
||||
*/
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection to use to capture the query plans.
|
||||
*/
|
||||
public void setConnection(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the captured query plan is stored.
|
||||
*/
|
||||
public boolean isStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to store the captured query plan.
|
||||
*/
|
||||
public void setStore(boolean store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the epoch time after which the query plan was capture (to be included).
|
||||
* Return the epoch time in millis for minimum bind capture time.
|
||||
* <p>
|
||||
* When set this ensures that the bind values used to get the query plan
|
||||
* have been around for a while (e.g. 5 mins) and so reasonably represent
|
||||
* bind values that match the slowest execution for this query plan.
|
||||
*/
|
||||
public long getSince() {
|
||||
return since;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the epoch time after which the query plan was captured.
|
||||
* <p>
|
||||
* This is used to only capture plans that have changed since a given time (like the time of last capture).
|
||||
* </p>
|
||||
* Set the epoch time (e.g. 5 mins ago) such that the query bind values
|
||||
* reasonably represent bind values that match the slowest execution for this query plan.
|
||||
*
|
||||
* @param since The time after which the query plan was captured to be included
|
||||
* @param since The minimum age of the bind values capture.
|
||||
*/
|
||||
public void setSince(long since) {
|
||||
this.since = since;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process consume the query plan.
|
||||
* Return the maximum number of plans to capture.
|
||||
*/
|
||||
public void process(MetaQueryPlan plan) {
|
||||
plans.add(plan);
|
||||
public int getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean type should be included in the query plan capture.
|
||||
* Set the maximum number of plans to capture.
|
||||
*/
|
||||
public boolean includeType(Class<?> beanType) {
|
||||
return includedBeanTypes == null || includedBeanTypes.isEmpty() || includedBeanTypes.contains(beanType);
|
||||
public void setMaxCount(int maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the label should be included in the query plan capture.
|
||||
* Return the maximum amount of time we want to use to capture plans.
|
||||
* <p>
|
||||
* Query plan collection will stop once this time is exceeded.
|
||||
*/
|
||||
public boolean includeLabel(String label) {
|
||||
return includedLabels == null || includedLabels.isEmpty() || includedLabels.contains(label);
|
||||
public long getMaxTimeMillis() {
|
||||
return maxTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time we want to use to capture plans.
|
||||
* <p>
|
||||
* Query plan collection will stop once this time is exceeded.
|
||||
*/
|
||||
public void setMaxTimeMillis(long maxTimeMillis) {
|
||||
this.maxTimeMillis = maxTimeMillis;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,9 @@ import java.util.Comparator;
|
||||
public interface ServerMetricsAsJson {
|
||||
|
||||
/**
|
||||
* Set to false to exclude profile location.
|
||||
* Set to false to exclude profile location and sql.
|
||||
*/
|
||||
ServerMetricsAsJson withLocation(boolean withLocation);
|
||||
|
||||
/**
|
||||
* Set to false to exclude SQL for query metrics.
|
||||
*/
|
||||
ServerMetricsAsJson withSql(boolean withSql);
|
||||
ServerMetricsAsJson withExtraAttributes(boolean withLocation);
|
||||
|
||||
/**
|
||||
* Set to false to exclude SQL hash.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.ebean.plugin;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
@@ -10,7 +12,7 @@ import java.util.List;
|
||||
/**
|
||||
* Extensions to Database API made available to plugins.
|
||||
*/
|
||||
public interface SpiServer extends EbeanServer {
|
||||
public interface SpiServer extends EbeanServer, BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the serverConfig.
|
||||
@@ -52,4 +54,19 @@ public interface SpiServer extends EbeanServer {
|
||||
*/
|
||||
DataSource getReadOnlyDataSource();
|
||||
|
||||
/**
|
||||
* Invoke lazy loading on this single bean (reference bean).
|
||||
*/
|
||||
void loadBeanRef(EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Invoke lazy loading on this single bean (L2 cache bean).
|
||||
*/
|
||||
void loadBeanL2(EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Invoke lazy loading on this single bean when no BeanLoader is set.
|
||||
* Typically due to serialisation or multiple stateless updates.
|
||||
*/
|
||||
void loadBean(EntityBeanIntercept ebi);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,13 @@ public interface JsonContext {
|
||||
*/
|
||||
String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string in pretty format.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJsonPretty(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.CountMetric;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
|
||||
/**
|
||||
* Extra metrics collected to measure internal behaviour.
|
||||
*/
|
||||
public class ExtraMetrics {
|
||||
|
||||
private final TimedMetric bindCapture;
|
||||
private final TimedMetric planCollect;
|
||||
private final CountMetric loadOneL2;
|
||||
private final CountMetric loadOneRef;
|
||||
private final CountMetric loadOneNoLoader;
|
||||
|
||||
/**
|
||||
* Create the extra metrics.
|
||||
*/
|
||||
public ExtraMetrics() {
|
||||
final MetricFactory factory = MetricFactory.get();
|
||||
this.bindCapture = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.bindcapture");
|
||||
this.planCollect = factory.createTimedMetric(MetricType.ORM, "ebean.queryplan.collect");
|
||||
this.loadOneL2 = factory.createCountMetric(MetricType.ORM, "loadone.l2");
|
||||
this.loadOneRef = factory.createCountMetric(MetricType.ORM, "loadone.ref");
|
||||
this.loadOneNoLoader = factory.createCountMetric(MetricType.ORM, "loadone.noloader");
|
||||
}
|
||||
|
||||
/**
|
||||
* Timed metric for bind capture used with query plan collection.
|
||||
*/
|
||||
public TimedMetric getBindCapture() {
|
||||
return bindCapture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timed metric for query plan collection.
|
||||
*/
|
||||
public TimedMetric getPlanCollect() {
|
||||
return planCollect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment counter for lazy loading one bean from L2 cache.
|
||||
* All good when lazy loading also hits L2 cache.
|
||||
*/
|
||||
public void incrementLoadOneL2() {
|
||||
loadOneL2.increment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment counter for lazy loading on reference bean.
|
||||
* We ought to be able to avoid this by changing to a tuned query.
|
||||
*/
|
||||
public void incrementLoadOneRef() {
|
||||
loadOneRef.increment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment counter for lazy loading one bean due to no loader.
|
||||
* Likely due to multiple stateless updates or serialisation.
|
||||
*/
|
||||
public void incrementLoadOneNoLoader() {
|
||||
loadOneNoLoader.increment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the metrics.
|
||||
*/
|
||||
public void visitMetrics(MetricVisitor visitor) {
|
||||
bindCapture.visit(visitor);
|
||||
planCollect.visit(visitor);
|
||||
loadOneL2.visit(visitor);
|
||||
loadOneRef.visit(visitor);
|
||||
loadOneNoLoader.visit(visitor);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.TxScope;
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ public class HelpScopeTrans {
|
||||
}
|
||||
|
||||
private static SpiEbeanServer server() {
|
||||
return (SpiEbeanServer) Ebean.getDefaultServer();
|
||||
return (SpiEbeanServer) DB.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebeaninternal.server.type.bindcapture.BindCapture;
|
||||
|
||||
class NoopQueryBindCapture implements SpiQueryBindCapture {
|
||||
|
||||
@Override
|
||||
public boolean collectFor(long timeMicros) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBind(BindCapture bindCapture, long timeMicros, long startNanos) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryPlanInit(long thresholdMicros) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class NoopQueryPlanManager implements QueryPlanManager {
|
||||
|
||||
@Override
|
||||
public SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan) {
|
||||
return SpiQueryBindCapture.NOOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> collect(QueryPlanRequest request) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manage query plan capture.
|
||||
*/
|
||||
public interface QueryPlanManager {
|
||||
|
||||
QueryPlanManager NOOP = new NoopQueryPlanManager();
|
||||
|
||||
/**
|
||||
* Create the bind capture for the given query plan.
|
||||
*/
|
||||
SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan);
|
||||
|
||||
/**
|
||||
* Collect the database query plans.
|
||||
*/
|
||||
List<MetaQueryPlan> collect(QueryPlanRequest request);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
|
||||
/**
|
||||
* Internal database query plan being capture.
|
||||
*/
|
||||
public interface SpiDbQueryPlan extends MetaQueryPlan {
|
||||
|
||||
/**
|
||||
* Extend with queryTimeMicros and captureCount.
|
||||
*/
|
||||
SpiDbQueryPlan with(long queryTimeMicros, long captureCount);
|
||||
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import io.ebean.TxScope;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
@@ -32,7 +31,7 @@ import java.util.function.Predicate;
|
||||
/**
|
||||
* Service Provider extension to EbeanServer.
|
||||
*/
|
||||
public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader, BeanCollectionLoader {
|
||||
public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the log manager.
|
||||
@@ -311,4 +310,9 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
* Execute the sql update regardless of transaction batch mode.
|
||||
*/
|
||||
int executeNow(SpiSqlUpdate sqlUpdate);
|
||||
|
||||
/**
|
||||
* Create a query bind capture for the given query plan.
|
||||
*/
|
||||
SpiQueryBindCapture createQueryBindCapture(SpiQueryPlan queryPlan);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebeaninternal.server.type.bindcapture.BindCapture;
|
||||
|
||||
/**
|
||||
* Capture query bind values and with those actual database query plans.
|
||||
*/
|
||||
public interface SpiQueryBindCapture {
|
||||
|
||||
/**
|
||||
* NOOP implementation.
|
||||
*/
|
||||
SpiQueryBindCapture NOOP = new NoopQueryBindCapture();
|
||||
|
||||
/**
|
||||
* Return true if the query just executed should be bind captured to collect
|
||||
* the query plan from (as the query time is large / interesting).
|
||||
*/
|
||||
boolean collectFor(long timeMicros);
|
||||
|
||||
/**
|
||||
* Set the captured bind values that we can use later to collect a query plan.
|
||||
*
|
||||
* @param bindCapture The bind values of the query
|
||||
* @param queryTimeMicros The query execution time
|
||||
* @param startNanos The nanos start of this bind capture
|
||||
*/
|
||||
void setBind(BindCapture bindCapture, long queryTimeMicros, long startNanos);
|
||||
|
||||
/**
|
||||
* Update the threshold micros triggering the bind capture.
|
||||
*/
|
||||
void queryPlanInit(long thresholdMicros);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
|
||||
/**
|
||||
* The internal ORM "query plan".
|
||||
*/
|
||||
public interface SpiQueryPlan {
|
||||
|
||||
/**
|
||||
* The related entity bean type
|
||||
*/
|
||||
Class<?> getBeanType();
|
||||
|
||||
/**
|
||||
* The plan name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The hash for the query plan.
|
||||
*/
|
||||
String getHash();
|
||||
|
||||
/**
|
||||
* The SQL for the query plan.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* The related profile location.
|
||||
*/
|
||||
ProfileLocation getProfileLocation();
|
||||
|
||||
/**
|
||||
* Initiate bind capture with the give threshold.
|
||||
*/
|
||||
void queryPlanInit(long thresholdMicros);
|
||||
|
||||
/**
|
||||
* Return as Database query plan.
|
||||
*
|
||||
* @param bind Description of the bind values used
|
||||
* @param planString The raw database query plan
|
||||
*/
|
||||
SpiDbQueryPlan createMeta(String bind, String planString);
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import io.ebean.TxScope;
|
||||
import io.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Service provider interface for the transaction manager.
|
||||
@@ -55,4 +57,9 @@ public interface SpiTransactionManager {
|
||||
*/
|
||||
void notifyOfQueryOnly(SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
* Return a connection used for query plan collection.
|
||||
*/
|
||||
Connection getQueryPlanConnection() throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.dbmigration;
|
||||
import io.ebean.config.DbMigrationConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.migration.ddl.DdlAutoCommit;
|
||||
import io.ebean.migration.ddl.DdlRunner;
|
||||
import io.ebean.migration.runner.ScriptTransform;
|
||||
import io.ebean.util.JdbcClose;
|
||||
@@ -47,6 +48,7 @@ public class DdlGenerator {
|
||||
private final boolean ddlAutoCommit;
|
||||
private final String dbSchema;
|
||||
private final ScriptTransform scriptTransform;
|
||||
private final String platformName;
|
||||
|
||||
private CurrentModel currentModel;
|
||||
private String dropAllContent;
|
||||
@@ -60,13 +62,15 @@ public class DdlGenerator {
|
||||
this.extraDdl = serverConfig.isDdlExtra();
|
||||
this.createOnly = serverConfig.isDdlCreateOnly();
|
||||
this.dbSchema = serverConfig.getDbSchema();
|
||||
final DatabasePlatform databasePlatform = server.getDatabasePlatform();
|
||||
this.platformName = databasePlatform.getPlatform().base().name();
|
||||
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
|
||||
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
|
||||
this.runDdl = false;
|
||||
this.ddlAutoCommit = false;
|
||||
} else {
|
||||
this.runDdl = serverConfig.isDdlRun();
|
||||
this.ddlAutoCommit = server.getDatabasePlatform().isDdlAutoCommit();
|
||||
this.ddlAutoCommit = databasePlatform.isDdlAutoCommit();
|
||||
}
|
||||
this.scriptTransform = createScriptTransform(serverConfig.getMigrationConfig());
|
||||
this.baseDir = initBaseDir();
|
||||
@@ -156,19 +160,19 @@ public class DdlGenerator {
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
public int runScript(Connection connection, boolean expectErrors, String content, String scriptName) {
|
||||
public void runScript(Connection connection, boolean expectErrors, String content, String scriptName) {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
DdlRunner runner = createDdlRunner(expectErrors, scriptName);
|
||||
try {
|
||||
if (expectErrors || ddlAutoCommit) {
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
int count = runner.runAll(scriptTransform.transform(content), connection);
|
||||
runner.runAll(scriptTransform.transform(content), connection);
|
||||
if (expectErrors || ddlAutoCommit) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
connection.commit();
|
||||
return count;
|
||||
runner.runNonTransactional(connection);
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PersistenceException("Failed to run script", e);
|
||||
@@ -177,6 +181,10 @@ public class DdlGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private DdlRunner createDdlRunner(boolean expectErrors, String scriptName) {
|
||||
return new DdlRunner(expectErrors, scriptName, platformName);
|
||||
}
|
||||
|
||||
protected void runDropSql(Connection connection) throws IOException {
|
||||
if (!createOnly) {
|
||||
if (extraDdl && jaxbPresent) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.dbmigration;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
@@ -90,6 +91,8 @@ public class DefaultDbMigration implements DbMigration {
|
||||
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
protected String migrationPath;
|
||||
|
||||
protected DatabasePlatform databasePlatform;
|
||||
|
||||
private boolean vanillaPlatform;
|
||||
@@ -137,13 +140,18 @@ public class DefaultDbMigration implements DbMigration {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
this.migrationPath = migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server to use to determine the current model.
|
||||
* Typically this is not called explicitly.
|
||||
*/
|
||||
@Override
|
||||
public void setServer(EbeanServer ebeanServer) {
|
||||
this.server = (SpiEbeanServer) ebeanServer;
|
||||
public void setServer(Database database) {
|
||||
this.server = (SpiEbeanServer) database;
|
||||
setServerConfig(server.getServerConfig());
|
||||
}
|
||||
|
||||
@@ -671,7 +679,7 @@ public class DefaultDbMigration implements DbMigration {
|
||||
*/
|
||||
private void setDefaults() {
|
||||
if (server == null) {
|
||||
setServer(Ebean.getDefaultServer());
|
||||
setServer(DB.getDefault());
|
||||
}
|
||||
if (vanillaPlatform || databasePlatform == null) {
|
||||
// not explicitly set so use the platform of the server
|
||||
@@ -684,6 +692,9 @@ public class DefaultDbMigration implements DbMigration {
|
||||
if (applyPrefix != null) {
|
||||
migrationConfig.setApplyPrefix(applyPrefix);
|
||||
}
|
||||
if (migrationPath != null) {
|
||||
migrationConfig.setMigrationPath(migrationPath);
|
||||
}
|
||||
if (header != null) {
|
||||
migrationConfig.setDdlHeader(header);
|
||||
}
|
||||
|
||||
+45
-38
@@ -112,8 +112,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
handleStrictError(tableName, columnName);
|
||||
}
|
||||
|
||||
before = getScriptsForPlatform(column.getBefore(), platformDdl.getPlatform().getName());
|
||||
after = getScriptsForPlatform(column.getAfter(), platformDdl.getPlatform().getName());
|
||||
before = getScriptsForPlatform(column.getBefore());
|
||||
after = getScriptsForPlatform(column.getAfter());
|
||||
this.withHistory = withHistory;
|
||||
}
|
||||
|
||||
@@ -136,9 +136,9 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
before = Collections.singletonList(platformDdl.getUpdateNullWithDefault());
|
||||
} else {
|
||||
before = getScriptsForPlatform(alter.getBefore(), platformDdl.getPlatform().getName());
|
||||
before = getScriptsForPlatform(alter.getBefore());
|
||||
}
|
||||
after = getScriptsForPlatform(alter.getAfter(), platformDdl.getPlatform().getName());
|
||||
after = getScriptsForPlatform(alter.getAfter());
|
||||
}
|
||||
|
||||
void writeBefore(DdlBuffer buffer) throws IOException {
|
||||
@@ -167,7 +167,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getScriptsForPlatform(List<DdlScript> scripts, String searchPlatform) {
|
||||
private List<String> getScriptsForPlatform(List<DdlScript> scripts) {
|
||||
String searchPlatform = platformDdl.getPlatform().getName();
|
||||
List<String> ret = Collections.emptyList();
|
||||
for (DdlScript script : scripts) {
|
||||
if (script.getPlatforms() == null || script.getPlatforms().isEmpty()) {
|
||||
@@ -358,7 +359,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
* For all other DB platforms these unique constraints are done inline as per normal.
|
||||
*/
|
||||
protected void writeUniqueOneToOneConstraints(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
String tableName = createTable.getName();
|
||||
for (Column col : externalUnique) {
|
||||
String uqName = col.getUniqueOneToOne();
|
||||
@@ -381,7 +381,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void writeSequence(DdlWrite writer, CreateTable createTable, String pk) throws IOException {
|
||||
|
||||
// explicit sequence use or platform decides
|
||||
String explicitSequenceName = createTable.getSequenceName();
|
||||
int initial = toInt(createTable.getSequenceInitial());
|
||||
@@ -400,13 +399,11 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void createWithHistory(DdlWrite writer, String name) throws IOException {
|
||||
|
||||
MTable table = writer.getTable(name);
|
||||
platformDdl.createWithHistory(writer, table);
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String references = column.getReferences();
|
||||
if (hasValue(references)) {
|
||||
@@ -417,13 +414,11 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
|
||||
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column));
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
}
|
||||
|
||||
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (ForeignKey key : createTable.getForeignKey()) {
|
||||
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
|
||||
write.apply().append(",").newLine().append(" ").append(fkConstraint);
|
||||
@@ -431,7 +426,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (Column column : createTable.getColumn()) {
|
||||
String references = column.getReferences();
|
||||
if (hasValue(references)) {
|
||||
@@ -443,7 +437,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void writeAddCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
|
||||
|
||||
for (ForeignKey key : createTable.getForeignKey()) {
|
||||
writeForeignKey(write, new WriteForeignKey(createTable.getName(), key));
|
||||
}
|
||||
@@ -454,12 +447,11 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException {
|
||||
|
||||
DdlBuffer fkeyBuffer = write.applyForeignKeys();
|
||||
String tableName = lowerTableName(request.table());
|
||||
if (request.indexName() != null) {
|
||||
// no matching unique constraint so add the index
|
||||
fkeyBuffer.appendStatement(platformDdl.createIndex(request.indexName(), tableName, request.cols()));
|
||||
fkeyBuffer.appendStatement(platformDdl.createIndex(new WriteCreateIndex(request.indexName(), tableName, request.cols(), false)));
|
||||
}
|
||||
|
||||
alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request);
|
||||
@@ -474,7 +466,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
protected void alterTableAddForeignKey(DdlOptions options, DdlBuffer buffer, WriteForeignKey request) throws IOException {
|
||||
|
||||
buffer.appendStatement(platformDdl.alterTableAddForeignKey(options, request));
|
||||
}
|
||||
|
||||
@@ -493,7 +484,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
* Add 'drop table' statement to the buffer.
|
||||
*/
|
||||
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
|
||||
|
||||
buffer.appendStatement(platformDdl.dropTable(tableName));
|
||||
}
|
||||
|
||||
@@ -501,26 +491,38 @@ public class BaseTableDdl implements TableDdl {
|
||||
* Add 'drop sequence' statement to the buffer.
|
||||
*/
|
||||
protected void dropSequence(DdlBuffer buffer, String sequenceName) throws IOException {
|
||||
|
||||
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
|
||||
}
|
||||
|
||||
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
|
||||
|
||||
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
|
||||
for (UniqueConstraint uniqueConstraint : createTable.getUniqueConstraint()) {
|
||||
if (inlineUniqueWhenNull) {
|
||||
String uqName = uniqueConstraint.getName();
|
||||
String[] columns = split(uniqueConstraint.getColumnNames());
|
||||
apply.append(",").newLine();
|
||||
apply.append(" constraint ").append(uqName).append(" unique");
|
||||
appendColumns(columns, apply);
|
||||
} else {
|
||||
externalCompoundUnique.add(uniqueConstraint);
|
||||
if (platformInclude(uniqueConstraint.getPlatforms())) {
|
||||
if (inlineUniqueWhenNull) {
|
||||
String uqName = uniqueConstraint.getName();
|
||||
apply.append(",").newLine();
|
||||
apply.append(" constraint ").append(uqName).append(" unique");
|
||||
appendColumns(split(uniqueConstraint.getColumnNames()), apply);
|
||||
} else {
|
||||
externalCompoundUnique.add(uniqueConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean platformInclude(String platforms) {
|
||||
if (platforms == null || platforms.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
String currentPlatform = platformDdl.getPlatform().getPlatform().name();
|
||||
for (String name : StringHelper.splitNames(platforms)) {
|
||||
if (currentPlatform.equalsIgnoreCase(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the unique constraints inline with the create table statement.
|
||||
*/
|
||||
@@ -607,26 +609,31 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
|
||||
writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns())));
|
||||
writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()));
|
||||
public void generate(DdlWrite writer, CreateIndex index) throws IOException {
|
||||
if (platformInclude(index.getPlatforms())) {
|
||||
writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
|
||||
writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
|
||||
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
|
||||
if (platformInclude(dropIndex.getPlatforms())) {
|
||||
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
|
||||
if (platformInclude(constraint.getPlatforms())) {
|
||||
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
|
||||
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
|
||||
|
||||
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
|
||||
writer.apply().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));
|
||||
} else {
|
||||
String[] cols = split(constraint.getColumnNames());
|
||||
String[] nullableColumns = split(constraint.getNullableColumns());
|
||||
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -56,12 +56,12 @@ public class ClickHouseDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName) {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createIndex(String indexName, String tableName, String[] columns) {
|
||||
public String createIndex(WriteCreateIndex create) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -13,25 +13,24 @@ public class HanaColumnStoreDdl extends AbstractHanaDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createIndex(String indexName, String tableName, String[] columns) {
|
||||
public String createIndex(WriteCreateIndex create) {
|
||||
final String[] columns = create.getColumns();
|
||||
if (columns == null || columns.length == 0) {
|
||||
return "-- cannot create index: no columns given";
|
||||
}
|
||||
|
||||
if (columns.length == 1) {
|
||||
return "-- explicit index \"" + indexName + "\" for single column \"" + columns[0] + "\" of table \"" + tableName
|
||||
return "-- explicit index \"" + create.getIndexName() + "\" for single column \"" + columns[0] + "\" of table \"" + create.getTableName()
|
||||
+ "\" is not necessary";
|
||||
}
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("create inverted hash index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
|
||||
buffer.append("create inverted hash index ").append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
|
||||
appendColumns(columns, buffer);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName) {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
DdlBuffer buffer = new BaseDdlBuffer(null);
|
||||
try {
|
||||
buffer.append("delimiter $$").newLine();
|
||||
|
||||
@@ -30,7 +30,7 @@ public class MySqlDdl extends PlatformDdl {
|
||||
* Return the drop index statement.
|
||||
*/
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName) {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return "drop index " + maxConstraintName(indexName) + " on " + tableName;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,9 @@ public class PlatformDdl {
|
||||
|
||||
protected String addForeignKeySkipCheck = "";
|
||||
|
||||
protected String uniqueIndex = "unique";
|
||||
protected String indexConcurrent = "";
|
||||
|
||||
/**
|
||||
* Set false for MsSqlServer to allow multiple nulls for OneToOne mapping.
|
||||
*/
|
||||
@@ -380,21 +383,34 @@ public class PlatformDdl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the drop index statement.
|
||||
* Return the drop index statement for known non concurrent index.
|
||||
*/
|
||||
public String dropIndex(String indexName, String tableName) {
|
||||
return dropIndexIfExists + maxConstraintName(indexName);
|
||||
return dropIndex(indexName, tableName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the create index statement.
|
||||
* Return the drop index statement.
|
||||
*/
|
||||
public String createIndex(String indexName, String tableName, String[] columns) {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return dropIndexIfExists + maxConstraintName(indexName);
|
||||
}
|
||||
|
||||
public String createIndex(WriteCreateIndex create) {
|
||||
if (create.useDefinition()) {
|
||||
return create.getDefinition();
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("create index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
|
||||
appendColumns(columns, buffer);
|
||||
|
||||
buffer.append("create ");
|
||||
if (create.isUnique()) {
|
||||
buffer.append(uniqueIndex).append(" ");
|
||||
}
|
||||
buffer.append("index ");
|
||||
if (create.isConcurrent()) {
|
||||
buffer.append(indexConcurrent);
|
||||
}
|
||||
buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
|
||||
appendColumns(create.getColumns(), buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public class PostgresDdl extends PlatformDdl {
|
||||
|
||||
private static final String dropIndexConcurrentlyIfExists = "drop index concurrently if exists ";
|
||||
|
||||
public PostgresDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new PostgresHistoryDdl();
|
||||
@@ -18,6 +20,7 @@ public class PostgresDdl extends PlatformDdl {
|
||||
this.alterTableIfExists = "if exists ";
|
||||
this.columnSetNull = "drop not null";
|
||||
this.addForeignKeySkipCheck = " not valid";
|
||||
this.indexConcurrent = "concurrently ";
|
||||
}
|
||||
|
||||
public String setLockTimeout(int lockTimeoutSeconds) {
|
||||
@@ -39,7 +42,6 @@ public class PostgresDdl extends PlatformDdl {
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn) {
|
||||
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "bigserial";
|
||||
}
|
||||
@@ -56,4 +58,9 @@ public class PostgresDdl extends PlatformDdl {
|
||||
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException {
|
||||
apply.append(" partition by range (").append(partitionColumn).append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return (concurrent ? dropIndexConcurrentlyIfExists : dropIndexIfExists) + maxConstraintName(indexName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,13 @@ public class SplitColumns {
|
||||
return columns.split(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* Split returning null when columns is null or empty.
|
||||
*/
|
||||
public static String[] splitWithNull(String columns) {
|
||||
if (columns == null || columns.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return columns.split(",");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dropIndex(String indexName, String tableName) {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('" + tableName + "','U') AND name = '"
|
||||
+ maxConstraintName(indexName) + "') drop index " + maxConstraintName(indexName) + " ON " + tableName;
|
||||
}
|
||||
@@ -105,9 +105,9 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
@Override
|
||||
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)).append(";\n");
|
||||
sb.append(dropIndex(uniqueConstraintName, tableName));
|
||||
sb.append(super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebeaninternal.dbmigration.migration.CreateIndex;
|
||||
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
|
||||
|
||||
class WriteCreateIndex {
|
||||
|
||||
private final String indexName;
|
||||
private final String tableName;
|
||||
private final String[] columns;
|
||||
private final boolean unique;
|
||||
private final boolean concurrent;
|
||||
private final String definition;
|
||||
|
||||
WriteCreateIndex(String indexName, String tableName, String[] columns, boolean unique) {
|
||||
this.indexName = indexName;
|
||||
this.tableName = tableName;
|
||||
this.columns = columns;
|
||||
this.unique = unique;
|
||||
this.concurrent = false;
|
||||
this.definition = null;
|
||||
}
|
||||
|
||||
public WriteCreateIndex(CreateIndex index) {
|
||||
this.indexName = index.getIndexName();
|
||||
this.tableName = index.getTableName();
|
||||
this.columns = split(index.getColumns());
|
||||
this.unique = Boolean.TRUE.equals(index.isUnique());
|
||||
this.concurrent = Boolean.TRUE.equals(index.isConcurrent());
|
||||
this.definition = index.getDefinition();
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public boolean isUnique() {
|
||||
return unique;
|
||||
}
|
||||
|
||||
public boolean isConcurrent() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
public String getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public boolean useDefinition() {
|
||||
return definition != null && !definition.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
@@ -41,6 +42,8 @@ public class AddUniqueConstraint {
|
||||
protected Boolean oneToOne;
|
||||
@XmlAttribute(name = "nullableColumns")
|
||||
protected String nullableColumns;
|
||||
@XmlAttribute(name = "platforms")
|
||||
protected String platforms;
|
||||
|
||||
/**
|
||||
* Gets the value of the constraintName property.
|
||||
@@ -142,4 +145,24 @@ public class AddUniqueConstraint {
|
||||
this.nullableColumns = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the platforms property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the platforms property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setPlatforms(String value) {
|
||||
this.platforms = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <attribute name="indexName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="columns" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="definition" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
@@ -35,6 +39,14 @@ public class CreateIndex {
|
||||
protected String tableName;
|
||||
@XmlAttribute(name = "columns", required = true)
|
||||
protected String columns;
|
||||
@XmlAttribute(name = "unique")
|
||||
protected Boolean unique;
|
||||
@XmlAttribute(name = "concurrent")
|
||||
protected Boolean concurrent;
|
||||
@XmlAttribute(name = "definition")
|
||||
protected String definition;
|
||||
@XmlAttribute(name = "platforms")
|
||||
protected String platforms;
|
||||
|
||||
/**
|
||||
* Gets the value of the indexName property.
|
||||
@@ -96,4 +108,84 @@ public class CreateIndex {
|
||||
this.columns = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the unique property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public Boolean isUnique() {
|
||||
return unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the unique property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public void setUnique(Boolean value) {
|
||||
this.unique = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the concurrent property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public Boolean isConcurrent() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the concurrent property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public void setConcurrent(Boolean value) {
|
||||
this.concurrent = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the definition property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the definition property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setDefinition(String value) {
|
||||
this.definition = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the platforms property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the platforms property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setPlatforms(String value) {
|
||||
this.platforms = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.List;
|
||||
* <attribute name="sequenceInitial" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="sequenceAllocate" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="pkName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="storageEngine" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
|
||||
@@ -18,6 +18,8 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="indexName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
@@ -32,6 +34,10 @@ public class DropIndex {
|
||||
protected String indexName;
|
||||
@XmlAttribute(name = "tableName", required = true)
|
||||
protected String tableName;
|
||||
@XmlAttribute(name = "concurrent")
|
||||
protected Boolean concurrent;
|
||||
@XmlAttribute(name = "platforms")
|
||||
protected String platforms;
|
||||
|
||||
/**
|
||||
* Gets the value of the indexName property.
|
||||
@@ -73,4 +79,44 @@ public class DropIndex {
|
||||
this.tableName = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the concurrent property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public Boolean isConcurrent() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the concurrent property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link Boolean }
|
||||
*/
|
||||
public void setConcurrent(Boolean value) {
|
||||
this.concurrent = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the platforms property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the platforms property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setPlatforms(String value) {
|
||||
this.platforms = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
@@ -38,6 +39,8 @@ public class UniqueConstraint {
|
||||
protected Boolean oneToOne;
|
||||
@XmlAttribute(name = "nullableColumns")
|
||||
protected String nullableColumns;
|
||||
@XmlAttribute(name = "platforms")
|
||||
protected String platforms;
|
||||
|
||||
/**
|
||||
* Gets the value of the name property.
|
||||
@@ -119,4 +122,24 @@ public class UniqueConstraint {
|
||||
this.nullableColumns = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the platforms property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the platforms property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setPlatforms(String value) {
|
||||
this.platforms = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.ebeaninternal.dbmigration.model;
|
||||
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import io.ebeaninternal.dbmigration.migration.ChangeSet;
|
||||
import io.ebeaninternal.dbmigration.model.build.ModelBuildBeanVisitor;
|
||||
import io.ebeaninternal.dbmigration.model.build.ModelBuildContext;
|
||||
@@ -24,9 +24,9 @@ public class CurrentModel {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
@@ -60,8 +60,8 @@ public class CurrentModel {
|
||||
|
||||
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
|
||||
this.server = server;
|
||||
this.databasePlatform = server.getDatabasePlatform();
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = maxLength(server, constraintNaming);
|
||||
this.platformTypes = platformTypes;
|
||||
this.jaxbPresent = server.getServerConfig().getClassLoadConfig().isJavaxJAXBPresent();
|
||||
}
|
||||
@@ -84,16 +84,6 @@ public class CurrentModel {
|
||||
return read().getPartitionedTables();
|
||||
}
|
||||
|
||||
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
|
||||
if (naming.getMaxLength() != null) {
|
||||
return naming.getMaxLength();
|
||||
}
|
||||
|
||||
int maxConstraintNameLength = server.getDatabasePlatform().getMaxConstraintNameLength();
|
||||
return new DefaultConstraintMaxLength(maxConstraintNameLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current model by reading all the bean descriptors and properties.
|
||||
*/
|
||||
@@ -101,7 +91,7 @@ public class CurrentModel {
|
||||
if (model == null) {
|
||||
model = new ModelContainer();
|
||||
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
|
||||
ModelBuildContext context = new ModelBuildContext(model, databasePlatform, constraintNaming, platformTypes);
|
||||
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
|
||||
VisitAllUsing visit = new VisitAllUsing(visitor, server);
|
||||
visit.visitAllBeans();
|
||||
|
||||
@@ -7,6 +7,9 @@ import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.splitWithNull;
|
||||
|
||||
/**
|
||||
* A unique constraint for multiple columns.
|
||||
* <p>
|
||||
@@ -28,12 +31,41 @@ public class MCompoundUniqueConstraint {
|
||||
*/
|
||||
private final String[] columns;
|
||||
|
||||
private final String platforms;
|
||||
|
||||
private String[] nullableColumns;
|
||||
|
||||
public MCompoundUniqueConstraint(String[] columns, Boolean oneToOne, String name) {
|
||||
/**
|
||||
* Create for OneToOne.
|
||||
*/
|
||||
public MCompoundUniqueConstraint(String[] columns, String name) {
|
||||
this.name = name;
|
||||
this.columns = columns;
|
||||
this.oneToOne = Boolean.TRUE.equals(oneToOne);
|
||||
this.oneToOne = true;
|
||||
this.platforms = null;
|
||||
}
|
||||
|
||||
public MCompoundUniqueConstraint(String[] columns, boolean oneToOne, String name, String platforms) {
|
||||
this.name = name;
|
||||
this.columns = columns;
|
||||
this.oneToOne = oneToOne;
|
||||
this.platforms = platforms;
|
||||
}
|
||||
|
||||
public MCompoundUniqueConstraint(AddUniqueConstraint change) {
|
||||
this.name = change.getConstraintName();
|
||||
this.columns = split(change.getColumnNames());
|
||||
this.oneToOne = change.isOneToOne();
|
||||
this.platforms = change.getPlatforms();
|
||||
this.nullableColumns = splitWithNull(change.getNullableColumns());
|
||||
}
|
||||
|
||||
public MCompoundUniqueConstraint(UniqueConstraint uq) {
|
||||
this.name = uq.getName();
|
||||
this.columns = split(uq.getColumnNames());
|
||||
this.oneToOne = uq.isOneToOne();
|
||||
this.platforms = uq.getPlatforms();
|
||||
this.nullableColumns = splitWithNull(uq.getNullableColumns());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +76,7 @@ public class MCompoundUniqueConstraint {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this unqiue constraint is specifically for OneToOne mapping.
|
||||
* Return true if this unique constraint is specifically for OneToOne mapping.
|
||||
*/
|
||||
public boolean isOneToOne() {
|
||||
return oneToOne;
|
||||
@@ -57,12 +89,17 @@ public class MCompoundUniqueConstraint {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
public UniqueConstraint getUniqueConstraint() {
|
||||
UniqueConstraint uq = new UniqueConstraint();
|
||||
uq.setName(getName());
|
||||
uq.setColumnNames(join(columns));
|
||||
uq.setNullableColumns(join(nullableColumns));
|
||||
uq.setOneToOne(isOneToOne());
|
||||
uq.setPlatforms(platforms);
|
||||
return uq;
|
||||
}
|
||||
|
||||
@@ -76,6 +113,7 @@ public class MCompoundUniqueConstraint {
|
||||
create.setColumnNames(join(columns));
|
||||
create.setNullableColumns(join(nullableColumns));
|
||||
create.setOneToOne(isOneToOne());
|
||||
create.setPlatforms(platforms);
|
||||
return create;
|
||||
}
|
||||
|
||||
@@ -83,12 +121,13 @@ public class MCompoundUniqueConstraint {
|
||||
* Create a AddUniqueConstraint migration with 'DROP CONSTRAINT' set for this index.
|
||||
*/
|
||||
public AddUniqueConstraint dropUniqueConstraint(String tableName) {
|
||||
AddUniqueConstraint dropUniqueConstraint = new AddUniqueConstraint();
|
||||
dropUniqueConstraint.setConstraintName(name);
|
||||
dropUniqueConstraint.setTableName(tableName);
|
||||
dropUniqueConstraint.setColumnNames(DdlHelp.DROP_CONSTRAINT);
|
||||
dropUniqueConstraint.setNullableColumns(join(nullableColumns));
|
||||
return dropUniqueConstraint;
|
||||
AddUniqueConstraint drop = new AddUniqueConstraint();
|
||||
drop.setConstraintName(name);
|
||||
drop.setTableName(tableName);
|
||||
drop.setColumnNames(DdlHelp.DROP_CONSTRAINT);
|
||||
drop.setNullableColumns(join(nullableColumns));
|
||||
drop.setPlatforms(platforms);
|
||||
return drop;
|
||||
}
|
||||
|
||||
public void setNullableColumns(String[] nullableColumns) {
|
||||
@@ -127,9 +166,10 @@ public class MCompoundUniqueConstraint {
|
||||
return false;
|
||||
}
|
||||
MCompoundUniqueConstraint other = (MCompoundUniqueConstraint) obj;
|
||||
return Arrays.equals(columns, other.columns)
|
||||
&& Arrays.equals(nullableColumns, other.nullableColumns)
|
||||
// not including platforms in equals check
|
||||
return oneToOne == other.oneToOne
|
||||
&& Objects.equals(name, other.name)
|
||||
&& oneToOne == other.oneToOne;
|
||||
&& Arrays.equals(columns, other.columns)
|
||||
&& Arrays.equals(nullableColumns, other.nullableColumns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.ebeaninternal.dbmigration.migration.DropIndex;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Index as part of the logical model.
|
||||
@@ -13,10 +14,12 @@ import java.util.List;
|
||||
public class MIndex {
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String indexName;
|
||||
|
||||
private String platforms;
|
||||
private List<String> columns = new ArrayList<>();
|
||||
private boolean unique;
|
||||
private boolean concurrent;
|
||||
private String definition;
|
||||
|
||||
/**
|
||||
* Create a single column non unique index.
|
||||
@@ -36,10 +39,27 @@ public class MIndex {
|
||||
Collections.addAll(this.columns, columnNames);
|
||||
}
|
||||
|
||||
public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique, boolean concurrent, String definition) {
|
||||
this(indexName, tableName, columnNames);
|
||||
this.platforms = platforms;
|
||||
this.unique = unique;
|
||||
this.concurrent = concurrent;
|
||||
this.definition = emptyToNull(definition);
|
||||
}
|
||||
|
||||
public MIndex(CreateIndex createIndex) {
|
||||
this.indexName = createIndex.getIndexName();
|
||||
this.tableName = createIndex.getTableName();
|
||||
this.columns = split(createIndex.getColumns());
|
||||
this.platforms = createIndex.getPlatforms();
|
||||
this.unique = Boolean.TRUE.equals(createIndex.isUnique());
|
||||
this.concurrent = Boolean.TRUE.equals(createIndex.isConcurrent());
|
||||
this.definition = emptyToNull(createIndex.getDefinition());
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
// currently indexName should be unique (not indexName + platforms)
|
||||
return indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,9 +91,24 @@ public class MIndex {
|
||||
create.setIndexName(indexName);
|
||||
create.setTableName(tableName);
|
||||
create.setColumns(join());
|
||||
create.setPlatforms(platforms);
|
||||
if (Boolean.TRUE.equals(unique)) {
|
||||
create.setUnique(Boolean.TRUE);
|
||||
}
|
||||
if (Boolean.TRUE.equals(concurrent)) {
|
||||
create.setConcurrent(Boolean.TRUE);
|
||||
}
|
||||
create.setDefinition(emptyToNull(definition));
|
||||
return create;
|
||||
}
|
||||
|
||||
private String emptyToNull(String val) {
|
||||
if (val == null || val.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DropIndex migration for this index.
|
||||
*/
|
||||
@@ -81,6 +116,10 @@ public class MIndex {
|
||||
DropIndex dropIndex = new DropIndex();
|
||||
dropIndex.setIndexName(indexName);
|
||||
dropIndex.setTableName(tableName);
|
||||
dropIndex.setPlatforms(platforms);
|
||||
if (Boolean.TRUE.equals(concurrent)) {
|
||||
dropIndex.setConcurrent(Boolean.TRUE);
|
||||
}
|
||||
return dropIndex;
|
||||
}
|
||||
|
||||
@@ -88,7 +127,6 @@ public class MIndex {
|
||||
* Compare with an index of the same name.
|
||||
*/
|
||||
public void compare(ModelDiff modelDiff, MIndex newIndex) {
|
||||
|
||||
if (changed(newIndex)) {
|
||||
// drop and recreate the index
|
||||
modelDiff.addDropIndex(dropIndex());
|
||||
@@ -103,6 +141,12 @@ public class MIndex {
|
||||
if (!tableName.equals(newIndex.getTableName())) {
|
||||
return true;
|
||||
}
|
||||
if (unique != newIndex.unique) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(definition, newIndex.definition)) {
|
||||
return true;
|
||||
}
|
||||
List<String> newColumns = newIndex.getColumns();
|
||||
if (columns.size() != newColumns.size()) {
|
||||
return true;
|
||||
@@ -117,6 +161,9 @@ public class MIndex {
|
||||
|
||||
|
||||
private List<String> split(String columns) {
|
||||
if (columns.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String[] cols = columns.split(",");
|
||||
List<String> colList = new ArrayList<>(cols.length);
|
||||
Collections.addAll(colList, cols);
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
|
||||
|
||||
/**
|
||||
* Holds the logical model for a given Table and everything associated to it.
|
||||
* <p>
|
||||
@@ -173,11 +175,8 @@ public class MTable {
|
||||
for (Column column : cols) {
|
||||
addColumn(column);
|
||||
}
|
||||
List<UniqueConstraint> uqConstraints = createTable.getUniqueConstraint();
|
||||
for (UniqueConstraint uq : uqConstraints) {
|
||||
MCompoundUniqueConstraint mUq = new MCompoundUniqueConstraint(SplitColumns.split(uq.getColumnNames()), uq.isOneToOne(), uq.getName());
|
||||
mUq.setNullableColumns(SplitColumns.split(uq.getNullableColumns()));
|
||||
uniqueConstraints.add(mUq);
|
||||
for (UniqueConstraint uq : createTable.getUniqueConstraint()) {
|
||||
uniqueConstraints.add(new MCompoundUniqueConstraint(uq));
|
||||
}
|
||||
|
||||
for (ForeignKey fk : createTable.getForeignKey()) {
|
||||
@@ -189,11 +188,10 @@ public class MTable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addForeignKey(String name, String refTableName, String indexName, String columnNames, String refColumnNames) {
|
||||
MCompoundForeignKey foreignKey = new MCompoundForeignKey(name, refTableName, indexName);
|
||||
String[] cols = SplitColumns.split(columnNames);
|
||||
String[] refCols = SplitColumns.split(refColumnNames);
|
||||
String[] cols = split(columnNames);
|
||||
String[] refCols = split(refColumnNames);
|
||||
for (int i = 0; i < cols.length && i < refCols.length; i++) {
|
||||
foreignKey.addColumnPair(cols[i], refCols[i]);
|
||||
}
|
||||
@@ -443,6 +441,10 @@ public class MTable {
|
||||
return partitionMeta;
|
||||
}
|
||||
|
||||
public String getPkName() {
|
||||
return pkName;
|
||||
}
|
||||
|
||||
public void setPkName(String pkName) {
|
||||
this.pkName = pkName;
|
||||
}
|
||||
@@ -593,19 +595,8 @@ public class MTable {
|
||||
/**
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
|
||||
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
|
||||
String[] cols = new String[columns.size()];
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
cols[i] = columns.get(i).getName();
|
||||
}
|
||||
addUniqueConstraint(cols, oneToOne, constraintName);
|
||||
public void addUniqueConstraint(MCompoundUniqueConstraint uniqueConstraint) {
|
||||
uniqueConstraints.add(uniqueConstraint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -761,10 +752,7 @@ public class MTable {
|
||||
List<String> nullableColumns = new ArrayList<>();
|
||||
for (String columnName : uniq.getColumns()) {
|
||||
MColumn col = getColumn(columnName);
|
||||
if (col == null) {
|
||||
throw new IllegalStateException("Column '" + columnName + "' not found in table " + getName());
|
||||
}
|
||||
if (!col.isNotnull()) {
|
||||
if (col != null && !col.isNotnull()) {
|
||||
nullableColumns.add(columnName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebeaninternal.dbmigration.model;
|
||||
|
||||
import io.ebean.migration.MigrationVersion;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns;
|
||||
import io.ebeaninternal.dbmigration.migration.AddColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.AddTableComment;
|
||||
@@ -21,6 +20,7 @@ import io.ebeaninternal.dbmigration.migration.Migration;
|
||||
import io.ebeaninternal.dbmigration.migration.Sql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -82,13 +82,6 @@ public class ModelContainer {
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map of all the non unique non fk indexes.
|
||||
*/
|
||||
public Map<String, MIndex> getIndexes() {
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table by name.
|
||||
*/
|
||||
@@ -97,10 +90,21 @@ public class ModelContainer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index by name.
|
||||
* Lookup the matching index during DIFF migration processing.
|
||||
*/
|
||||
public MIndex getIndex(String indexName) {
|
||||
return indexes.get(indexName);
|
||||
public MIndex getIndex(MIndex newIndex) {
|
||||
return indexes.get(newIndex.getKey());
|
||||
}
|
||||
|
||||
public Collection<MIndex> allIndexes() {
|
||||
return indexes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the index does not exist and should be dropped.
|
||||
*/
|
||||
public boolean dropIndex(MIndex existingIndex) {
|
||||
return !indexes.containsKey(existingIndex.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,10 +205,7 @@ public class ModelContainer {
|
||||
if (DdlHelp.isDropConstraint(change.getColumnNames())) {
|
||||
table.getUniqueConstraints().removeIf(constraint -> constraint.getName().equals(change.getConstraintName()));
|
||||
} else {
|
||||
MCompoundUniqueConstraint constraint = new MCompoundUniqueConstraint(
|
||||
SplitColumns.split(change.getColumnNames()), change.isOneToOne(), change.getConstraintName());
|
||||
constraint.setNullableColumns(SplitColumns.split(change.getNullableColumns()));
|
||||
table.getUniqueConstraints().add(constraint);
|
||||
table.getUniqueConstraints().add(new MCompoundUniqueConstraint(change));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,8 +217,7 @@ public class ModelContainer {
|
||||
if (DdlHelp.isDropForeignKey(change.getColumnNames())) {
|
||||
table.removeForeignKey(change.getName());
|
||||
} else {
|
||||
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(),
|
||||
change.getRefColumnNames());
|
||||
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(), change.getRefColumnNames());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,8 @@ public class ModelContainer {
|
||||
if (indexes.containsKey(indexName)) {
|
||||
throw new IllegalStateException("Index [" + indexName + "] already exists in model?");
|
||||
}
|
||||
indexes.put(createIndex.getIndexName(), new MIndex(createIndex));
|
||||
MIndex index = new MIndex(createIndex);
|
||||
indexes.put(index.getKey(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +322,7 @@ public class ModelContainer {
|
||||
if (reusedElementCollection != null) {
|
||||
final MIndex index = reusedElementCollection.setReusedElementCollection();
|
||||
if (index != null) {
|
||||
indexes.put(index.getIndexName(), index);
|
||||
indexes.put(index.getKey(), index);
|
||||
}
|
||||
} else {
|
||||
if (table.isPartitioned()) {
|
||||
@@ -332,17 +333,10 @@ public class ModelContainer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single column index.
|
||||
* Add an index.
|
||||
*/
|
||||
public void addIndex(String indexName, String tableName, String columnName) {
|
||||
indexes.put(indexName, new MIndex(indexName, tableName, columnName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a multi column index.
|
||||
*/
|
||||
public void addIndex(String indexName, String tableName, String[] columnNames) {
|
||||
indexes.put(indexName, new MIndex(indexName, tableName, columnNames));
|
||||
public void addIndex(MIndex index) {
|
||||
indexes.put(index.getKey(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,9 +140,8 @@ public class ModelDiff {
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, MIndex> newIndexes = newModel.getIndexes();
|
||||
for (MIndex newIndex : newIndexes.values()) {
|
||||
MIndex currentIndex = baseModel.getIndex(newIndex.getIndexName());
|
||||
for (MIndex newIndex : newModel.allIndexes()) {
|
||||
MIndex currentIndex = baseModel.getIndex(newIndex);
|
||||
if (currentIndex == null) {
|
||||
addCreateIndex(newIndex.createIndex());
|
||||
} else {
|
||||
@@ -151,8 +150,8 @@ public class ModelDiff {
|
||||
}
|
||||
|
||||
// search for indexes that are no longer used
|
||||
for (MIndex existingIndex : baseModel.getIndexes().values()) {
|
||||
if (!newIndexes.containsKey(existingIndex.getIndexName())) {
|
||||
for (MIndex existingIndex : baseModel.allIndexes()) {
|
||||
if (newModel.dropIndex(existingIndex)) {
|
||||
addDropIndex(existingIndex.dropIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
|
||||
import io.ebeaninternal.dbmigration.model.MIndex;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import io.ebeaninternal.dbmigration.model.ModelContainer;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -30,17 +33,30 @@ public class ModelBuildContext {
|
||||
|
||||
private final ModelContainer model;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
|
||||
public ModelBuildContext(ModelContainer model, DatabasePlatform databasePlatform, DbConstraintNaming naming, boolean platformTypes) {
|
||||
this.model = model;
|
||||
this.databasePlatform = databasePlatform;
|
||||
this.constraintNaming = naming;
|
||||
this.maxLength = maxLength;
|
||||
this.platformTypes = platformTypes;
|
||||
this.maxLength = maxLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the max length handling for constraint names.
|
||||
*/
|
||||
private DbConstraintNaming.MaxLength maxLength() {
|
||||
if (constraintNaming.getMaxLength() != null) {
|
||||
return constraintNaming.getMaxLength();
|
||||
}
|
||||
return new DefaultConstraintMaxLength(databasePlatform.getMaxConstraintNameLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,40 +71,51 @@ public class ModelBuildContext {
|
||||
return constraintNaming.normaliseTable(baseTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take into account max length and quoted identifiers in constraint and index names.
|
||||
*/
|
||||
private String name(String constraintName, int indexCount) {
|
||||
return databasePlatform.convertQuotedIdentifiers(maxLength(constraintName, indexCount));
|
||||
}
|
||||
|
||||
private String maxLength(String constraintName, int indexCount) {
|
||||
return maxLength.maxLength(constraintName, indexCount);
|
||||
}
|
||||
|
||||
public String primaryKeyName(String tableName) {
|
||||
return maxLength(constraintNaming.primaryKeyName(tableName), 0);
|
||||
return name(constraintNaming.primaryKeyName(tableName), 0);
|
||||
}
|
||||
|
||||
public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) {
|
||||
return maxLength(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
|
||||
return name(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount);
|
||||
}
|
||||
|
||||
public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) {
|
||||
return maxLength(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
|
||||
return name(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount);
|
||||
}
|
||||
|
||||
public String foreignKeyIndexName(String tableName, String column, int indexCount) {
|
||||
return maxLength(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
|
||||
return name(constraintNaming.foreignKeyIndexName(tableName, column), indexCount);
|
||||
}
|
||||
|
||||
public String indexName(String tableName, String column, int indexCount) {
|
||||
return maxLength(constraintNaming.indexName(tableName, column), indexCount);
|
||||
return name(constraintNaming.indexName(tableName, column), indexCount);
|
||||
}
|
||||
|
||||
public String indexName(String tableName, String[] columns, int indexCount) {
|
||||
return maxLength(constraintNaming.indexName(tableName, columns), indexCount);
|
||||
return name(constraintNaming.indexName(tableName, columns), indexCount);
|
||||
}
|
||||
|
||||
public String uniqueConstraintName(String tableName, String columnName, int indexCount) {
|
||||
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
|
||||
return name(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount);
|
||||
}
|
||||
|
||||
public String uniqueConstraintName(String tableName, String[] columnNames, int indexCount) {
|
||||
return maxLength(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
|
||||
return name(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount);
|
||||
}
|
||||
|
||||
public String checkConstraintName(String tableName, String columnName, int checkCount) {
|
||||
return maxLength(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
|
||||
return name(constraintNaming.checkConstraintName(tableName, columnName), checkCount);
|
||||
}
|
||||
|
||||
public MTable addTable(MTable table) {
|
||||
@@ -99,16 +126,8 @@ public class ModelBuildContext {
|
||||
model.addTableElementCollection(table);
|
||||
}
|
||||
|
||||
public void addIndex(String indexName, String tableName, String columnName) {
|
||||
model.addIndex(indexName, tableName, columnName);
|
||||
}
|
||||
|
||||
public void addIndex(String indexName, String tableName, String[] columnNames) {
|
||||
model.addIndex(indexName, tableName, columnNames);
|
||||
}
|
||||
|
||||
private String maxLength(String constraintName, int indexCount) {
|
||||
return maxLength.maxLength(constraintName, indexCount);
|
||||
public void addIndex(MIndex index) {
|
||||
model.addIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+72
-59
@@ -1,8 +1,11 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.IndexSet;
|
||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
|
||||
import io.ebeaninternal.dbmigration.model.MCompoundUniqueConstraint;
|
||||
import io.ebeaninternal.dbmigration.model.MIndex;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import io.ebeaninternal.dbmigration.model.visitor.BaseTablePropertyVisitor;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -20,6 +23,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
|
||||
@@ -42,7 +46,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
private int countUnique;
|
||||
private int countCheck;
|
||||
|
||||
|
||||
public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table, BeanDescriptor<?> beanDescriptor) {
|
||||
this.ctx = ctx;
|
||||
this.table = table;
|
||||
@@ -54,36 +57,60 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
* Add unique constraints defined via JPA UniqueConstraint annotations.
|
||||
*/
|
||||
private void addIndexes(IndexDefinition[] indexes) {
|
||||
|
||||
if (indexes != null) {
|
||||
for (IndexDefinition index : indexes) {
|
||||
String[] columns = index.getColumns();
|
||||
indexSet.add(columns);
|
||||
|
||||
if (index.isUnique()) {
|
||||
String uqName = index.getName();
|
||||
if (uqName == null || uqName.trim().isEmpty()) {
|
||||
uqName = determineUniqueConstraintName(columns);
|
||||
}
|
||||
table.addUniqueConstraint(columns, false, uqName);
|
||||
|
||||
if (index.isUniqueConstraint()) {
|
||||
table.addUniqueConstraint(createMUniqueConstraint(index, columns));
|
||||
} else {
|
||||
// 'just' an index (not a unique constraint)
|
||||
String idxName = index.getName();
|
||||
if (idxName == null || idxName.trim().isEmpty()) {
|
||||
idxName = determineIndexName(columns);
|
||||
}
|
||||
ctx.addIndex(idxName, table.getName(), columns);
|
||||
ctx.addIndex(createMIndex(indexName(index), table.getName(), index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MCompoundUniqueConstraint createMUniqueConstraint(IndexDefinition index, String[] columns) {
|
||||
return new MCompoundUniqueConstraint(columns, false, uniqueConstraintName(index), platforms(index.getPlatforms()));
|
||||
}
|
||||
|
||||
private String uniqueConstraintName(IndexDefinition index) {
|
||||
String uqName = index.getName();
|
||||
if (uqName == null || uqName.trim().isEmpty()) {
|
||||
return uniqueConstraintName(index.getColumns());
|
||||
}
|
||||
return uqName;
|
||||
}
|
||||
|
||||
private String indexName(IndexDefinition index) {
|
||||
String idxName = index.getName();
|
||||
if (idxName == null || idxName.trim().isEmpty()) {
|
||||
idxName = indexName(index.getColumns());
|
||||
}
|
||||
return idxName;
|
||||
}
|
||||
|
||||
private MIndex createMIndex(String indexName, String tableName, IndexDefinition index) {
|
||||
return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms()), index.isUnique(), index.isConcurrent(), index.getDefinition());
|
||||
}
|
||||
|
||||
private String platforms(Platform[] platforms) {
|
||||
if (platforms == null || platforms.length == 0) {
|
||||
return null;
|
||||
}
|
||||
StringJoiner joiner = new StringJoiner(",");
|
||||
for (Platform platform : platforms) {
|
||||
joiner.add(platform.name());
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
|
||||
// set the primary key name
|
||||
table.setPkName(determinePrimaryKeyName());
|
||||
table.setPkName(primaryKeyName());
|
||||
|
||||
// check if indexes on foreign keys should be suppressed
|
||||
for (MColumn column : table.allColumns()) {
|
||||
@@ -105,7 +132,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
}
|
||||
|
||||
addDraftTable();
|
||||
|
||||
table.updateCompoundIndices();
|
||||
}
|
||||
|
||||
@@ -136,7 +162,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
if (cols.size() == 2) {
|
||||
// always the second column that we put the unique constraint on
|
||||
MColumn col = new ArrayList<>(cols).get(1);
|
||||
col.setUnique(determineUniqueConstraintName(col.getName()));
|
||||
col.setUnique(uniqueConstraintName(col.getName()));
|
||||
}
|
||||
}
|
||||
} else if (p.isElementCollection()) {
|
||||
@@ -146,9 +172,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
|
||||
@Override
|
||||
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
|
||||
|
||||
if (p instanceof BeanPropertyAssocOne) {
|
||||
visitOneImported((BeanPropertyAssocOne)p);
|
||||
visitOneImported((BeanPropertyAssocOne<?>)p);
|
||||
} else {
|
||||
visitScalar(p);
|
||||
}
|
||||
@@ -174,8 +199,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
if (columns.length > 1) {
|
||||
// compound foreign key
|
||||
String refTable = p.getTargetDescriptor().getBaseTable();
|
||||
String fkName = determineForeignKeyConstraintName(p.getName());
|
||||
String fkIndex = determineForeignKeyIndexName(p.getName());
|
||||
String fkName = foreignKeyConstraintName(p.getName());
|
||||
String fkIndex = foreignKeyIndexName(p.getName());
|
||||
compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex);
|
||||
table.addForeignKey(compoundKey);
|
||||
}
|
||||
@@ -202,9 +227,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
refTable = p.getTargetDescriptor().getBaseTable();
|
||||
}
|
||||
col.setReferences(refTable + "." + refColumn);
|
||||
col.setForeignKeyName(determineForeignKeyConstraintName(col.getName()));
|
||||
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
|
||||
if (p.hasForeignKeyIndex()) {
|
||||
col.setForeignKeyIndex(determineForeignKeyIndexName(col.getName()));
|
||||
col.setForeignKeyIndex(foreignKeyIndexName(col.getName()));
|
||||
}
|
||||
PropertyForeignKey foreignKey = p.getForeignKey();
|
||||
if (foreignKey != null) {
|
||||
@@ -222,13 +247,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
// for MsSqlServer we need different DDL to handle NULL values on this constraint
|
||||
if (modelColumns.size() == 1) {
|
||||
MColumn col = modelColumns.get(0);
|
||||
col.setUniqueOneToOne(determineUniqueConstraintName(col.getName()));
|
||||
indexSetAdd(col.getName());
|
||||
col.setUniqueOneToOne(uniqueConstraintName(col.getName()));
|
||||
|
||||
} else {
|
||||
String uqName = determineUniqueConstraintName(p.getName());
|
||||
table.addUniqueConstraint(modelColumns, true, uqName);
|
||||
indexSetAdd(modelColumns);
|
||||
String[] cols = indexSetAdd(toColumnNames(modelColumns));
|
||||
String uqName = uniqueConstraintName(p.getName());
|
||||
table.addUniqueConstraint(new MCompoundUniqueConstraint(cols, uqName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +284,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
if (foreignKey == null || !foreignKey.isNoConstraint()) {
|
||||
TableJoinColumn[] columns = primaryKeyJoin.columns();
|
||||
col.setReferences(primaryKeyJoin.getTable() + "." + columns[0].getForeignDbColumn());
|
||||
col.setForeignKeyName(determineForeignKeyConstraintName(col.getName()));
|
||||
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
|
||||
if (foreignKey != null) {
|
||||
col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate());
|
||||
}
|
||||
@@ -275,7 +300,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
col.setDbMigrationInfos(p.getDbMigrationInfos());
|
||||
|
||||
if (p.isUnique() && !p.isId()) {
|
||||
col.setUnique(determineUniqueConstraintName(col.getName()));
|
||||
col.setUnique(uniqueConstraintName(col.getName()));
|
||||
indexSetAdd(col.getName());
|
||||
}
|
||||
Set<String> checkConstraintValues = p.getDbCheckConstraintValues();
|
||||
@@ -285,7 +310,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
inheritInfo.appendCheckConstraintValues(p.getName(), checkConstraintValues);
|
||||
}
|
||||
col.setCheckConstraint(buildCheckConstraint(p.getDbColumn(), checkConstraintValues));
|
||||
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
|
||||
col.setCheckConstraintName(checkConstraintName(col.getName()));
|
||||
}
|
||||
|
||||
lastColumn = col;
|
||||
@@ -313,85 +338,73 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
indexSet.add(column);
|
||||
}
|
||||
|
||||
private void indexSetAdd(List<MColumn> modelColumns) {
|
||||
private String[] indexSetAdd(String[] cols) {
|
||||
indexSet.add(cols);
|
||||
return cols;
|
||||
}
|
||||
|
||||
private String[] toColumnNames(List<MColumn> modelColumns) {
|
||||
String[] cols = new String[modelColumns.size()];
|
||||
for (int i = 0; i < modelColumns.size(); i++) {
|
||||
cols[i] = modelColumns.get(i).getName();
|
||||
}
|
||||
indexSet.add(cols);
|
||||
return cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary key constraint name.
|
||||
*/
|
||||
protected String determinePrimaryKeyName() {
|
||||
|
||||
protected String primaryKeyName() {
|
||||
return ctx.primaryKeyName(table.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint name given a single column foreign key.
|
||||
*/
|
||||
protected String determineForeignKeyConstraintName(String columnName) {
|
||||
|
||||
protected String foreignKeyConstraintName(String columnName) {
|
||||
return ctx.foreignKeyConstraintName(table.getName(), columnName, ++countForeignKey);
|
||||
}
|
||||
|
||||
protected String determineForeignKeyIndexName(String column) {
|
||||
|
||||
protected String foreignKeyIndexName(String column) {
|
||||
String[] cols = {column};
|
||||
return determineForeignKeyIndexName(cols);
|
||||
return foreignKeyIndexName(cols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint name given a single column foreign key.
|
||||
*/
|
||||
protected String determineForeignKeyIndexName(String[] columns) {
|
||||
|
||||
protected String foreignKeyIndexName(String[] columns) {
|
||||
return ctx.foreignKeyIndexName(table.getName(), columns, ++countIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name given a single column foreign key.
|
||||
*/
|
||||
protected String determineIndexName(String column) {
|
||||
|
||||
return ctx.indexName(table.getName(), column, ++countIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name given multiple columns.
|
||||
*/
|
||||
protected String determineIndexName(String[] columns) {
|
||||
|
||||
protected String indexName(String[] columns) {
|
||||
return ctx.indexName(table.getName(), columns, ++countIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
protected String determineUniqueConstraintName(String columnName) {
|
||||
|
||||
protected String uniqueConstraintName(String columnName) {
|
||||
return ctx.uniqueConstraintName(table.getName(), columnName, ++countUnique);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
protected String determineUniqueConstraintName(String[] columnNames) {
|
||||
|
||||
protected String uniqueConstraintName(String[] columnNames) {
|
||||
return ctx.uniqueConstraintName(table.getName(), columnNames, ++countUnique);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the constraint name.
|
||||
*/
|
||||
protected String determineCheckConstraintName(String columnName) {
|
||||
|
||||
protected String checkConstraintName(String columnName) {
|
||||
return ctx.checkConstraintName(table.getName(), columnName, ++countCheck);
|
||||
}
|
||||
|
||||
|
||||
private boolean hasValue(String val) {
|
||||
return val != null && !val.isEmpty();
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ public class BaseQueryTuner {
|
||||
SpiQuery.Type type = query.getType();
|
||||
switch (type) {
|
||||
case COUNT:
|
||||
case ATTRIBUTE:
|
||||
case ID_LIST:
|
||||
case UPDATE:
|
||||
case DELETE:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.avaje.classpath.scanner.ClassPathScannerFactory;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.avaje.classpath.scanner.ClassPathScannerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -22,9 +22,11 @@ class DScriptRunner implements ScriptRunner {
|
||||
private static final String NEWLINE = "\n";
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
private final String platformName;
|
||||
|
||||
DScriptRunner(SpiEbeanServer server) {
|
||||
this.server = server;
|
||||
this.platformName = this.server.getDatabasePlatform().getPlatform().base().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +58,7 @@ class DScriptRunner implements ScriptRunner {
|
||||
}
|
||||
|
||||
String content = content(resource);
|
||||
runScript(content, scriptName, placeholderMap);
|
||||
runScript(content, scriptName, placeholderMap, false);
|
||||
}
|
||||
|
||||
private String content(URL resource) {
|
||||
@@ -72,21 +74,25 @@ class DScriptRunner implements ScriptRunner {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runScript(String name, String content, boolean useAutoCommit) {
|
||||
runScript(content, name, null, useAutoCommit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the DDL statements in the script.
|
||||
*/
|
||||
private void runScript(String content, String scriptName, Map<String, String> placeholderMap) {
|
||||
|
||||
private void runScript(String content, String scriptName, Map<String, String> placeholderMap, boolean useAutoCommit) {
|
||||
try {
|
||||
if (placeholderMap != null) {
|
||||
content = ScriptTransform.build(null, placeholderMap).transform(content);
|
||||
}
|
||||
|
||||
try (Connection connection = obtainConnection()) {
|
||||
DdlRunner runner = new DdlRunner(false, scriptName);
|
||||
DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName);
|
||||
runner.runAll(content, connection);
|
||||
connection.commit();
|
||||
runner.runNonTransactional(connection);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ModuleInfoLoader;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.ServerConfigProvider;
|
||||
import io.ebean.config.TenantMode;
|
||||
@@ -85,11 +86,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
public SpiEbeanServer createServer(ServerConfig serverConfig) {
|
||||
|
||||
synchronized (this) {
|
||||
if (serverConfig.isDefaultServer()) {
|
||||
for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
|
||||
configProvider.apply(serverConfig);
|
||||
}
|
||||
}
|
||||
applyConfigServices(serverConfig);
|
||||
|
||||
setNamingConvention(serverConfig);
|
||||
BootupClasses bootupClasses = getBootupClasses(serverConfig);
|
||||
@@ -120,7 +117,6 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
// executor and l2 caching service setup early (used during server construction)
|
||||
SpiBackgroundExecutor executor = createBackgroundExecutor(serverConfig);
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(online, clusterManager, executor, serverConfig, bootupClasses);
|
||||
|
||||
DefaultServer server = new DefaultServer(c, c.cacheManager());
|
||||
@@ -128,24 +124,45 @@ public class DefaultContainer implements SpiContainer {
|
||||
// generate and run DDL if required
|
||||
// if there are any other tasks requiring action in their plugins, do them as well
|
||||
if (!DbOffline.isGenerateMigration()) {
|
||||
server.executePlugins(online);
|
||||
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
// register the server once it has been created
|
||||
clusterManager.registerServer(server);
|
||||
}
|
||||
}
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
startServer(online, server);
|
||||
}
|
||||
DbOffline.reset();
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyConfigServices(ServerConfig config) {
|
||||
if (config.isDefaultServer()) {
|
||||
for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
|
||||
configProvider.apply(config);
|
||||
}
|
||||
if (config.isAutoLoadModuleInfo()) {
|
||||
// auto register entity classes (default db)
|
||||
for (ModuleInfoLoader loader : ServiceLoader.load(ModuleInfoLoader.class)) {
|
||||
config.addAll(loader.entityClasses());
|
||||
}
|
||||
}
|
||||
} else if (config.isAutoLoadModuleInfo()) {
|
||||
// auto register entity classes (other named db)
|
||||
for (ModuleInfoLoader loader : ServiceLoader.load(ModuleInfoLoader.class)) {
|
||||
config.addAll(loader.entityClassesFor(config.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startServer(boolean online, DefaultServer server) {
|
||||
server.executePlugins(online);
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
clusterManager.registerServer(server);
|
||||
}
|
||||
}
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entities, scalarTypes, Listeners etc combining the class registered
|
||||
* ones with the already created instances.
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import io.ebean.meta.MetricData;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.ServerMetrics;
|
||||
import io.ebean.meta.ServerMetricsAsJson;
|
||||
@@ -27,8 +28,13 @@ public class DefaultMetaInfoManager implements MetaInfoManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request) {
|
||||
return server.collectQueryPlans(request);
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
|
||||
return server.queryPlanInit(initRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
|
||||
return server.queryPlanCollectNow(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,6 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.bean.PersistenceContext.WithOption;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
@@ -56,6 +55,7 @@ import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.Plugin;
|
||||
@@ -63,9 +63,10 @@ import io.ebean.plugin.Property;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebean.util.JdbcClose;
|
||||
import io.ebeaninternal.api.ExtraMetrics;
|
||||
import io.ebeaninternal.api.LoadBeanRequest;
|
||||
import io.ebeaninternal.api.LoadManyRequest;
|
||||
import io.ebeaninternal.api.QueryPlanManager;
|
||||
import io.ebeaninternal.api.ScopedTransaction;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiDtoQuery;
|
||||
@@ -74,6 +75,8 @@ import io.ebeaninternal.api.SpiJsonContext;
|
||||
import io.ebeaninternal.api.SpiLogManager;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuery.Type;
|
||||
import io.ebeaninternal.api.SpiQueryBindCapture;
|
||||
import io.ebeaninternal.api.SpiQueryPlan;
|
||||
import io.ebeaninternal.api.SpiSqlQuery;
|
||||
import io.ebeaninternal.api.SpiSqlUpdate;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
@@ -138,7 +141,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -162,6 +164,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final QueryPlanManager queryPlanManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
/**
|
||||
@@ -233,9 +239,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
*/
|
||||
private final int lazyLoadBatchSize;
|
||||
|
||||
/**
|
||||
* The query batch size
|
||||
*/
|
||||
private final int queryBatchSize;
|
||||
|
||||
private final boolean updateAllPropertiesInBatch;
|
||||
@@ -248,15 +251,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
* Create the DefaultServer.
|
||||
*/
|
||||
public DefaultServer(InternalConfiguration config, ServerCacheManager cache) {
|
||||
|
||||
this.logManager = config.getLogManager();
|
||||
this.dtoBeanManager = config.getDtoBeanManager();
|
||||
this.serverConfig = config.getServerConfig();
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
this.serverCacheManager = cache;
|
||||
this.databasePlatform = config.getDatabasePlatform();
|
||||
this.backgroundExecutor = config.getBackgroundExecutor();
|
||||
|
||||
this.extraMetrics = config.getExtraMetrics();
|
||||
this.serverName = serverConfig.getName();
|
||||
this.lazyLoadBatchSize = serverConfig.getLazyLoadBatchSize();
|
||||
this.queryBatchSize = serverConfig.getQueryBatchSize();
|
||||
@@ -267,22 +268,17 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
this.currentTenantProvider = serverConfig.getCurrentTenantProvider();
|
||||
this.slowQueryMicros = config.getSlowQueryMicros();
|
||||
this.slowQueryListener = config.getSlowQueryListener();
|
||||
|
||||
this.beanDescriptorManager = config.getBeanDescriptorManager();
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
|
||||
this.updateAllPropertiesInBatch = serverConfig.isUpdateAllPropertiesInBatch();
|
||||
this.callStackFactory = initCallStackFactory(serverConfig);
|
||||
|
||||
this.persister = config.createPersister(this);
|
||||
this.queryEngine = config.createOrmQueryEngine();
|
||||
this.relationalQueryEngine = config.createRelationalQueryEngine();
|
||||
this.dtoQueryEngine = config.createDtoQueryEngine();
|
||||
|
||||
this.autoTuneService = config.createAutoTuneService(this);
|
||||
this.readAuditPrepare = config.getReadAuditPrepare();
|
||||
this.readAuditLogger = config.getReadAuditLogger();
|
||||
|
||||
this.beanLoader = new DefaultBeanLoader(this);
|
||||
this.jsonContext = config.createJsonContext(this);
|
||||
this.dataTimeZone = config.getDataTimeZone();
|
||||
@@ -291,13 +287,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this);
|
||||
this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor());
|
||||
this.documentStore = docStoreComponents.documentStore();
|
||||
|
||||
this.queryPlanManager = config.initQueryPlanManager(transactionManager);
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
this.serverPlugins = config.getPlugins();
|
||||
this.ddlGenerator = new DdlGenerator(this, serverConfig);
|
||||
this.scriptRunner = new DScriptRunner(this);
|
||||
|
||||
configureServerPlugins();
|
||||
|
||||
// Register with the JVM Shutdown hook
|
||||
ShutdownManager.registerEbeanServer(this);
|
||||
}
|
||||
@@ -584,6 +580,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
beanLoader.loadBean(ebi);
|
||||
extraMetrics.incrementLoadOneNoLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBeanRef(EntityBeanIntercept ebi) {
|
||||
beanLoader.loadBean(ebi);
|
||||
extraMetrics.incrementLoadOneRef();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBeanL2(EntityBeanIntercept ebi) {
|
||||
beanLoader.loadBean(ebi);
|
||||
extraMetrics.incrementLoadOneL2();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2385,7 +2394,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a set of properties if saving the bean will violate the unique constraints (defined by given properties).
|
||||
*/
|
||||
@@ -2430,21 +2438,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
relationalQueryEngine.visitMetrics(visitor);
|
||||
persister.visitMetrics(visitor);
|
||||
}
|
||||
extraMetrics.visitMetrics(visitor);
|
||||
visitor.visitEnd();
|
||||
}
|
||||
|
||||
public List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getDataSource().getConnection();
|
||||
request.setConnection(connection);
|
||||
beanDescriptorManager.collectQueryPlans(request);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@Override
|
||||
public SpiQueryBindCapture createQueryBindCapture(SpiQueryPlan plan) {
|
||||
return queryPlanManager.createBindCapture(plan);
|
||||
}
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
return request.getPlans();
|
||||
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
|
||||
return beanDescriptorManager.queryPlanInit(initRequest);
|
||||
}
|
||||
|
||||
List<MetaQueryPlan> queryPlanCollectNow(QueryPlanRequest request) {
|
||||
return queryPlanManager.collect(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,9 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
private Appendable writer;
|
||||
|
||||
/**
|
||||
* By default include SQL for the initial collection only.
|
||||
* By default include sql and location attributes for the initial collection only.
|
||||
*/
|
||||
private int includeSqlMode = 1;
|
||||
|
||||
/**
|
||||
* By default include with the initial SQL collection only.
|
||||
*/
|
||||
private int includeLocation = 1;
|
||||
private int includeExtraAttributes = 1;
|
||||
|
||||
private boolean withHeader = true;
|
||||
private boolean withHash = true;
|
||||
@@ -50,14 +45,8 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withLocation(boolean withLocation) {
|
||||
this.includeLocation = withLocation ? 2 : 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerMetricsAsJson withSql(boolean withSql) {
|
||||
this.includeSqlMode = withSql ? 2 : 0;
|
||||
public ServerMetricsAsJson withExtraAttributes(boolean extraAttributes) {
|
||||
this.includeExtraAttributes = extraAttributes ? 2 : 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -96,7 +85,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
try {
|
||||
start();
|
||||
for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
|
||||
log(metric);
|
||||
logTimed(metric);
|
||||
}
|
||||
|
||||
List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
|
||||
@@ -118,7 +107,6 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
logQuery(metric);
|
||||
}
|
||||
}
|
||||
|
||||
end();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error writing metrics as JSON", e);
|
||||
@@ -183,23 +171,12 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
objStart();
|
||||
key("name");
|
||||
val(metric.getName());
|
||||
key("type");
|
||||
val(metric.getMetricType().name());
|
||||
}
|
||||
|
||||
private void metricEnd() throws IOException {
|
||||
objEnd();
|
||||
}
|
||||
|
||||
private void log(MetaTimedMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
appendCounters(metric);
|
||||
if (includeLocation != 0) {
|
||||
appendLocation(metric.getLocation());
|
||||
}
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private void logCount(MetaCountMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
key("count");
|
||||
@@ -207,42 +184,40 @@ class DumpMetricsJson implements ServerMetricsAsJson {
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private void logQuery(MetaQueryMetric metric) throws IOException {
|
||||
private void logTimed(MetaTimedMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
appendCounters(metric);
|
||||
if (withHash) {
|
||||
key("hash");
|
||||
val(metric.getHash());
|
||||
appendTiming(metric);
|
||||
if (isIncludeDetail(metric)) {
|
||||
appendExtra("loc", metric.getLocation());
|
||||
}
|
||||
appendLocationAndSql(metric);
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private void appendLocationAndSql(MetaQueryMetric metric) throws IOException {
|
||||
if (includeLocation == 2) {
|
||||
appendLocation(metric.getLocation());
|
||||
private void logQuery(MetaQueryMetric metric) throws IOException {
|
||||
metricStart(metric);
|
||||
appendTiming(metric);
|
||||
if (withHash) {
|
||||
appendExtra("hash", metric.getHash());
|
||||
}
|
||||
if (isIncludeSql(metric)) {
|
||||
if (includeLocation == 1) {
|
||||
appendLocation(metric.getLocation());
|
||||
}
|
||||
key("sql");
|
||||
val(metric.getSql());
|
||||
if (isIncludeDetail(metric)) {
|
||||
appendExtra("loc", metric.getLocation());
|
||||
appendExtra("sql", metric.getSql());
|
||||
}
|
||||
metricEnd();
|
||||
}
|
||||
|
||||
private boolean isIncludeDetail(MetaTimedMetric metric) {
|
||||
return includeExtraAttributes == 2 || includeExtraAttributes == 1 && metric.initialCollection();
|
||||
}
|
||||
|
||||
private void appendExtra(String key, String val) throws IOException {
|
||||
if (val != null) {
|
||||
key(key);
|
||||
val(val);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isIncludeSql(MetaQueryMetric metric) {
|
||||
return includeSqlMode == 2 || includeSqlMode == 1 && metric.initialCollection();
|
||||
}
|
||||
|
||||
private void appendLocation(String location) throws IOException {
|
||||
if (location != null) {
|
||||
key("loc");
|
||||
val(location);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendCounters(MetaTimedMetric timedMetric) throws IOException {
|
||||
private void appendTiming(MetaTimedMetric timedMetric) throws IOException {
|
||||
key("count");
|
||||
val(timedMetric.getCount());
|
||||
key("total");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.avaje.classpath.scanner.Resource;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebeaninternal.server.dto.DtoNamedQueries;
|
||||
import io.ebeaninternal.xmlmapping.XmlMappingReader;
|
||||
import io.ebeaninternal.xmlmapping.model.XmDto;
|
||||
import io.ebeaninternal.xmlmapping.model.XmEbean;
|
||||
import io.ebeaninternal.xmlmapping.model.XmRawSql;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.avaje.classpath.scanner.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebeaninternal.api.ExtraMetrics;
|
||||
import io.ebeaninternal.api.QueryPlanManager;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiJsonContext;
|
||||
@@ -64,9 +66,15 @@ import io.ebeaninternal.server.persist.DefaultPersister;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.persist.platform.PostgresMultiValueBind;
|
||||
import io.ebeaninternal.server.query.CQueryEngine;
|
||||
import io.ebeaninternal.server.query.CQueryPlanManager;
|
||||
import io.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import io.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import io.ebeaninternal.server.query.DtoQueryEngine;
|
||||
import io.ebeaninternal.server.query.QueryPlanLogger;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerExplain;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerOracle;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerPostgres;
|
||||
import io.ebeaninternal.server.query.QueryPlanLoggerSqlServer;
|
||||
import io.ebeaninternal.server.readaudit.DefaultReadAuditLogger;
|
||||
import io.ebeaninternal.server.readaudit.DefaultReadAuditPrepare;
|
||||
import io.ebeaninternal.server.text.json.DJsonContext;
|
||||
@@ -164,8 +172,10 @@ public class InternalConfiguration {
|
||||
|
||||
private final SpiLogManager logManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics = new ExtraMetrics();
|
||||
|
||||
InternalConfiguration(boolean online, ClusterManager clusterManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses) {
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses) {
|
||||
|
||||
this.online = online;
|
||||
this.serverConfig = serverConfig;
|
||||
@@ -242,6 +252,10 @@ public class InternalConfiguration {
|
||||
return clockService;
|
||||
}
|
||||
|
||||
public ExtraMetrics getExtraMetrics() {
|
||||
return extraMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a SpiServerPlugin and if so 'collect' it to give the complete list
|
||||
* later on the DefaultServer for late call to configure().
|
||||
@@ -433,8 +447,8 @@ public class InternalConfiguration {
|
||||
|
||||
TransactionManagerOptions options =
|
||||
new TransactionManagerOptions(notifyL2CacheInForeground, serverConfig, scopeManager, clusterManager, backgroundExecutor,
|
||||
indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager,
|
||||
tableModState, cacheNotify, clockService);
|
||||
indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager,
|
||||
tableModState, cacheNotify, clockService);
|
||||
|
||||
if (serverConfig.isExplicitTransactionBeginMode()) {
|
||||
return new ExplicitTransactionManager(options);
|
||||
@@ -527,7 +541,7 @@ public class InternalConfiguration {
|
||||
}
|
||||
|
||||
private boolean isMySql(Platform platform) {
|
||||
return platform.base() == Platform.MYSQL;
|
||||
return platform.base() == Platform.MYSQL;
|
||||
}
|
||||
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
@@ -636,4 +650,28 @@ public class InternalConfiguration {
|
||||
|
||||
return new DefaultServerCacheManager(builder);
|
||||
}
|
||||
|
||||
public QueryPlanManager initQueryPlanManager(TransactionManager transactionManager) {
|
||||
if (!serverConfig.isCollectQueryPlans()) {
|
||||
return QueryPlanManager.NOOP;
|
||||
}
|
||||
long threshold = serverConfig.getCollectQueryPlanThresholdMicros();
|
||||
return new CQueryPlanManager(transactionManager, threshold, queryPlanLogger(databasePlatform.getPlatform()), extraMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger to log query plans for the given platform.
|
||||
*/
|
||||
QueryPlanLogger queryPlanLogger(Platform platform) {
|
||||
switch (platform.base()) {
|
||||
case POSTGRES:
|
||||
return new QueryPlanLoggerPostgres();
|
||||
case SQLSERVER:
|
||||
return new QueryPlanLoggerSqlServer();
|
||||
case ORACLE:
|
||||
return new QueryPlanLoggerOracle();
|
||||
default:
|
||||
return new QueryPlanLoggerExplain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PersistDeferredRelationship {
|
||||
public void execute(SpiTransaction transaction) {
|
||||
|
||||
String sql = beanDescriptor.getUpdateImportedIdSql(importedId);
|
||||
SqlUpdate sqlUpdate = ebeanServer.createSqlUpdate(sql);
|
||||
SqlUpdate sqlUpdate = ebeanServer.sqlUpdate(sql);
|
||||
|
||||
// bind the set clause for the importedId
|
||||
int pos = importedId.bind(1, sqlUpdate, assocBean);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.core.bootup;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassPathScanner;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebeaninternal.server.core.ClassPathScanners;
|
||||
import org.avaje.classpath.scanner.ClassPathScanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core.bootup;
|
||||
|
||||
import io.avaje.classpath.scanner.ClassFilter;
|
||||
import io.ebean.annotation.DocStore;
|
||||
import io.ebean.config.IdGenerator;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
@@ -18,7 +19,6 @@ import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import org.avaje.classpath.scanner.ClassFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -129,7 +129,7 @@ public class BootupClasses implements ClassFilter {
|
||||
|
||||
/**
|
||||
* Adds the list <code>toAdd</code> to <code>instances</code> and removes any pending
|
||||
* candiate, to prevent duplicate instantiiation.
|
||||
* candidate, to prevent duplicate instantiation.
|
||||
*/
|
||||
private <T> void add(List<T> toAdd, List<T> instances, List<Class<? extends T>> candidates) {
|
||||
if (toAdd != null) {
|
||||
@@ -433,9 +433,7 @@ public class BootupClasses implements ClassFilter {
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
// single instances
|
||||
// TODO: What should happen, if there is already an other
|
||||
// changeLogListener assigned? (Last wins? / Exception?)
|
||||
// single instances, last assigned wins
|
||||
if (ChangeLogListener.class.isAssignableFrom(cls)) {
|
||||
changeLogListenerClass = (Class<? extends ChangeLogListener>) cls;
|
||||
interesting = true;
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.bean.SingleBeanLoader;
|
||||
import io.ebean.cache.QueryCacheEntry;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.ServerConfig;
|
||||
@@ -27,8 +28,9 @@ import io.ebean.event.changelog.ChangeType;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.plugin.BeanDocType;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
@@ -482,7 +484,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
this.dbComment = deploy.getDbComment();
|
||||
this.partitionMeta = deploy.getPartitionMeta();
|
||||
this.storageEngine = deploy.getStorageEngine();
|
||||
this.autoTunable = EntityType.ORM == entityType && (beanFinder == null);
|
||||
this.autoTunable = beanFinder == null && (entityType == EntityType.ORM || entityType == EntityType.VIEW);
|
||||
|
||||
// helper object used to derive lists of properties
|
||||
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
|
||||
@@ -1682,10 +1684,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return new DeployUpdateParser(this).parse(ormUpdateStatement);
|
||||
}
|
||||
|
||||
void collectQueryPlans(QueryPlanRequest request) {
|
||||
void queryPlanInit(QueryPlanInit request, List<MetaQueryPlan> list) {
|
||||
for (CQueryPlan queryPlan : queryPlanCache.values()) {
|
||||
if (request.includeLabel(queryPlan.getLabel())) {
|
||||
queryPlan.collectQueryPlan(request);
|
||||
if (request.includeHash(queryPlan.getHash())) {
|
||||
queryPlan.queryPlanInit(request.getThresholdMicros());
|
||||
list.add(queryPlan.createMeta(null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1714,19 +1717,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
/**
|
||||
* Trim query plans not used since the passed in epoch time.
|
||||
*/
|
||||
List<CQueryPlan> trimQueryPlans(long unusedSince) {
|
||||
|
||||
List<CQueryPlan> list = new ArrayList<>();
|
||||
|
||||
void trimQueryPlans(long unusedSince) {
|
||||
Iterator<CQueryPlan> it = queryPlanCache.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CQueryPlan queryPlan = it.next();
|
||||
if (queryPlan.getLastQueryTime() < unusedSince) {
|
||||
it.remove();
|
||||
list.add(queryPlan);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2043,7 +2041,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
if (disableLazyLoad) {
|
||||
ebi.setDisableLazyLoad(true);
|
||||
} else {
|
||||
ebi.setBeanLoader(ebeanServer);
|
||||
ebi.setBeanLoader(refBeanLoader());
|
||||
}
|
||||
ebi.setReference(idPropertyIndex);
|
||||
if (Boolean.TRUE == readOnly) {
|
||||
@@ -2061,6 +2059,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
}
|
||||
|
||||
SingleBeanLoader refBeanLoader() {
|
||||
return new SingleBeanLoader.Ref(ebeanServer);
|
||||
}
|
||||
|
||||
SingleBeanLoader l2BeanLoader() {
|
||||
return new SingleBeanLoader.L2(ebeanServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a non read only reference bean without checking cacheSharableBeans.
|
||||
*/
|
||||
@@ -2075,7 +2081,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
EntityBean eb = createEntityBean();
|
||||
id = convertSetId(id, eb);
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
ebi.setBeanLoader(ebeanServer);
|
||||
ebi.setBeanLoader(refBeanLoader());
|
||||
ebi.setReference(idPropertyIndex);
|
||||
if (pc != null) {
|
||||
contextPut(pc, id, eb);
|
||||
|
||||
@@ -690,7 +690,7 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
// Not using loadContext here so no batch lazy loading for these beans
|
||||
ebi.setBeanLoader(desc.getEbeanServer());
|
||||
ebi.setBeanLoader(desc.l2BeanLoader());
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.api.ConcurrencyMode;
|
||||
@@ -55,7 +56,6 @@ import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import io.ebeaninternal.server.properties.BeanPropertyAccess;
|
||||
import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
|
||||
import io.ebeaninternal.server.query.CQueryPlan;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeInteger;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
@@ -244,17 +244,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Run periodic trim of query plans.
|
||||
*/
|
||||
public void scheduleBackgroundTrim() {
|
||||
backgroundExecutor.executePeriodically(this::trimQueryPlans, 30L, TimeUnit.SECONDS);
|
||||
backgroundExecutor.executePeriodically(this::trimQueryPlans, 60L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void trimQueryPlans() {
|
||||
long lastUsed = System.currentTimeMillis() - (queryPlanTTLSeconds * 1000L);
|
||||
for (BeanDescriptor<?> descriptor : immutableDescriptorList) {
|
||||
if (!descriptor.isEmbedded()) {
|
||||
List<CQueryPlan> trimmedPlans = descriptor.trimQueryPlans(lastUsed);
|
||||
if (!trimmedPlans.isEmpty()) {
|
||||
logger.trace("trimmed {} query plans for type:{}", trimmedPlans.size(), descriptor.getName());
|
||||
}
|
||||
descriptor.trimQueryPlans(lastUsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -954,6 +951,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
if (matchSet.size() == 1) {
|
||||
// all right with the world
|
||||
prop.clearTableJoin();
|
||||
return true;
|
||||
}
|
||||
if (matchSet.size() == 2) {
|
||||
@@ -1696,12 +1694,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
}
|
||||
|
||||
public void collectQueryPlans(QueryPlanRequest request) {
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit request) {
|
||||
List<MetaQueryPlan> list = new ArrayList<>();
|
||||
for (BeanDescriptor<?> desc : immutableDescriptorList) {
|
||||
if (request.includeType(desc.getBeanType())) {
|
||||
desc.collectQueryPlans(request);
|
||||
}
|
||||
desc.queryPlanInit(request, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1713,7 +1711,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
@Override
|
||||
public int compare(BeanDescriptor<?> o1, BeanDescriptor<?> o2) {
|
||||
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
/**
|
||||
* Holds multiple column unique constraints defined for an entity.
|
||||
*/
|
||||
public class IndexDefinition {
|
||||
|
||||
private final String[] columns;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Platform[] platforms;
|
||||
private final boolean unique;
|
||||
private final boolean concurrent;
|
||||
private final String definition;
|
||||
|
||||
public IndexDefinition(String[] columns, String name, boolean unique) {
|
||||
/**
|
||||
* Create from Index annotation.
|
||||
*/
|
||||
public IndexDefinition(String[] columns, String name, boolean unique, Platform[] platforms, boolean concurrent, String definition) {
|
||||
this.columns = columns;
|
||||
this.unique = unique;
|
||||
this.name = name;
|
||||
this.platforms = platforms;
|
||||
this.concurrent = concurrent;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,6 +33,29 @@ public class IndexDefinition {
|
||||
this.columns = columns;
|
||||
this.unique = true;
|
||||
this.name = null;
|
||||
this.platforms = null;
|
||||
this.concurrent = false;
|
||||
this.definition = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this can be used as a unique constraint.
|
||||
*/
|
||||
public boolean isUniqueConstraint() {
|
||||
return unique && !concurrent && noDefinition() && noColumnFormulas();
|
||||
}
|
||||
|
||||
private boolean noDefinition() {
|
||||
return definition == null || definition.isEmpty();
|
||||
}
|
||||
|
||||
private boolean noColumnFormulas() {
|
||||
for (String column : columns) {
|
||||
if (column.contains("(")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,4 +79,24 @@ public class IndexDefinition {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platforms this index applies to.
|
||||
*/
|
||||
public Platform[] getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this index has the concurrent flag.
|
||||
*/
|
||||
public boolean isConcurrent() {
|
||||
return concurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw definition of the index if supplied.
|
||||
*/
|
||||
public String getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ public class IntersectionTable {
|
||||
* Return a SqlUpdate for inserting into the intersection table.
|
||||
*/
|
||||
public SqlUpdate insert(EbeanServer server, boolean draft) {
|
||||
return server.createSqlUpdate(draft ? draftInsertSql : insertSql);
|
||||
return server.sqlUpdate(draft ? draftInsertSql : insertSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a SqlUpdate for deleting from the intersection table.
|
||||
*/
|
||||
public SqlUpdate delete(EbeanServer server, boolean draft) {
|
||||
return server.createSqlUpdate(draft ? draftDeleteSql : deleteSql);
|
||||
return server.sqlUpdate(draft ? draftDeleteSql : deleteSql);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public class TableJoinColumn {
|
||||
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
|
||||
this.localSqlFormula = InternString.intern(deploy.getLocalSqlFormula());
|
||||
this.foreignSqlFormula = InternString.intern(deploy.getForeignSqlFormula());
|
||||
|
||||
this.insertable = deploy.isInsertable();
|
||||
this.updateable = deploy.isUpdateable();
|
||||
this.queryHash = hash();
|
||||
|
||||
@@ -269,5 +269,12 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
public <A> BeanDescriptor<A> getElementDescriptor() {
|
||||
return (BeanDescriptor<A>)elementDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the table join due to an implied mappedBy.
|
||||
*/
|
||||
public void clearTableJoin() {
|
||||
tableJoin.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import io.ebeaninternal.server.deploy.BeanTable;
|
||||
import io.ebeaninternal.server.deploy.InheritInfo;
|
||||
import io.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
@@ -74,31 +75,33 @@ public class DeployTableJoin {
|
||||
* The order is generally true for OneToMany and false for ManyToOne relationships.
|
||||
* </p>
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
public void addJoinColumn(DeployUtil deploy, boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
if (!"".equals(jc.table())) {
|
||||
setTable(jc.table());
|
||||
setTable(deploy.convertQuotes(jc.table()));
|
||||
}
|
||||
if (!"".equals(jc.name()) || !"".equals(jc.referencedColumnName())) {
|
||||
// only add the join column details when name or referencedColumnName is specified
|
||||
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
|
||||
String ref = deploy.convertQuotes(jc.referencedColumnName());
|
||||
String nam = deploy.convertQuotes(jc.name());
|
||||
addJoinColumn(new DeployTableJoinColumn(order, ref, nam, jc.insertable(), jc.updatable(), beanTable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn array.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
public void addJoinColumn(DeployUtil util, boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
for (JoinColumn aJcArray : jcArray) {
|
||||
addJoinColumn(order, aJcArray, beanTable);
|
||||
addJoinColumn(util, order, aJcArray, beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn set.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, Set<JoinColumn> joinColumns, BeanTable beanTable) {
|
||||
public void addJoinColumn(DeployUtil util, boolean order, Set<JoinColumn> joinColumns, BeanTable beanTable) {
|
||||
for (JoinColumn joinColumn : joinColumns) {
|
||||
addJoinColumn(order, joinColumn, beanTable);
|
||||
addJoinColumn(util, order, joinColumn, beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,4 +178,16 @@ public class DeployTableJoin {
|
||||
columns.get(0).setLocalDbColumn(dbColumn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the join columns due to an implied mappedBy.
|
||||
* <p>
|
||||
* Effectively prior to clear this was considered a unidirectional OneToMany and the
|
||||
* foreign key was defined by naming convention. Clearing this means that it uses the
|
||||
* foreign key as defined by the implied mappedBy property (the only ManyToOne that
|
||||
* maps back to the parent (that holds the OneToMany).
|
||||
*/
|
||||
public void clear() {
|
||||
columns.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,14 @@ public class DeployTableJoinColumn {
|
||||
this.updateable = updateable;
|
||||
}
|
||||
|
||||
public DeployTableJoinColumn(boolean order, String ref, String name, boolean insertable, boolean updateable, BeanTable beanTable) {
|
||||
this(ref, name, insertable, updateable);
|
||||
setReferencedColumn(beanTable);
|
||||
if (!order) {
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
void setLocalSqlFormula(String localSqlFormula) {
|
||||
if (localSqlFormula != null) {
|
||||
this.localSqlFormula = localSqlFormula;
|
||||
@@ -80,15 +88,6 @@ public class DeployTableJoinColumn {
|
||||
return foreignSqlFormula;
|
||||
}
|
||||
|
||||
|
||||
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
|
||||
setReferencedColumn(beanTable);
|
||||
if (!order) {
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private void setReferencedColumn(BeanTable beanTable) {
|
||||
if (localDbColumn == null) {
|
||||
BeanProperty idProperty = beanTable.getIdProperty();
|
||||
|
||||
@@ -140,7 +140,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
Set<JoinColumn> joinColumns = getAll(prop, JoinColumn.class);
|
||||
if (joinColumns != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, joinColumns, beanTable);
|
||||
prop.getTableJoin().addJoinColumn(util, true, joinColumns, beanTable);
|
||||
}
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
@@ -210,7 +210,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
BeanTable localTable = factory.getBeanTable(descriptor.getBeanType());
|
||||
if (collectionTable != null) {
|
||||
prop.getTableJoin().addJoinColumn(true, collectionTable.joinColumns(), localTable);
|
||||
prop.getTableJoin().addJoinColumn(util, true, collectionTable.joinColumns(), localTable);
|
||||
}
|
||||
if (!prop.getTableJoin().hasJoinColumns()) {
|
||||
BeanProperty localId = localTable.getIdProperty();
|
||||
@@ -326,11 +326,11 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
intJoin.setTable(intTableName);
|
||||
|
||||
// add the source to intersection join columns
|
||||
intJoin.addJoinColumn(true, joinTable.joinColumns(), prop.getBeanTable());
|
||||
intJoin.addJoinColumn(util, true, joinTable.joinColumns(), prop.getBeanTable());
|
||||
|
||||
// set the intersection to dest table join columns
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
destJoin.addJoinColumn(false, joinTable.inverseJoinColumns(), prop.getBeanTable());
|
||||
destJoin.addJoinColumn(util, false, joinTable.inverseJoinColumns(), prop.getBeanTable());
|
||||
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
if (beanTable == null) {
|
||||
throw new IllegalStateException("Looks like a missing @ManyToOne or @OneToOne on property " + prop.getFullBeanName() + " - no related 'BeanTable'");
|
||||
}
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
prop.getTableJoin().addJoinColumn(util, false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,8 @@ public class AnnotationClass extends AnnotationParser {
|
||||
}
|
||||
|
||||
for (Index index : findAnnotationsRecursive(cls, Index.class)) {
|
||||
descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(), index.unique()));
|
||||
descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(),
|
||||
index.unique(), index.platforms(), index.concurrent(), index.definition()));
|
||||
}
|
||||
|
||||
UniqueConstraint uc = findAnnotationRecursive(cls, UniqueConstraint.class);
|
||||
|
||||
@@ -221,6 +221,38 @@ public class AnnotationFields extends AnnotationParser {
|
||||
util.setLobType(prop);
|
||||
}
|
||||
|
||||
Length length = get(prop, Length.class);
|
||||
if (length != null) {
|
||||
prop.setDbLength(length.value());
|
||||
}
|
||||
|
||||
io.ebean.annotation.NotNull nonNull = get(prop, io.ebean.annotation.NotNull.class);
|
||||
if (nonNull != null) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
if (!prop.isLob()) {
|
||||
// take the max size of all @Size annotations
|
||||
int maxSize = -1;
|
||||
for (Size size : getAll(prop, Size.class)) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
if (maxSize != -1) {
|
||||
prop.setDbLength(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get(prop, TenantId.class) != null) {
|
||||
prop.setTenantId();
|
||||
}
|
||||
@@ -283,11 +315,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
Aggregation aggregation = get(prop, Aggregation.class);
|
||||
if (aggregation != null) {
|
||||
prop.setAggregation(aggregation.value());
|
||||
}
|
||||
Sum sum = get(prop, Sum.class);
|
||||
if (sum != null) {
|
||||
prop.setAggregation("sum(" + prop.getName() + ")");
|
||||
prop.setAggregation(aggregation.value().replace("$1", prop.getName()));
|
||||
}
|
||||
|
||||
Version version = get(prop, Version.class);
|
||||
@@ -322,41 +350,8 @@ public class AnnotationFields extends AnnotationParser {
|
||||
prop.setExcludedFromHistory();
|
||||
}
|
||||
|
||||
Length length = get(prop, Length.class);
|
||||
if (length != null) {
|
||||
prop.setDbLength(length.value());
|
||||
}
|
||||
|
||||
io.ebean.annotation.NotNull nonNull = get(prop, io.ebean.annotation.NotNull.class);
|
||||
if (nonNull != null) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
readDbMigration(prop);
|
||||
|
||||
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
if (!prop.isLob()) {
|
||||
// take the max size of all @Size annotations
|
||||
int maxSize = -1;
|
||||
for (Size size : getAll(prop, Size.class)) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
if (maxSize != -1) {
|
||||
prop.setDbLength(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Want to process last so we can use with @Formula
|
||||
Transient t = get(prop, Transient.class);
|
||||
if (t != null) {
|
||||
@@ -421,7 +416,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
if (columnNames.length == 1 && hasRelationshipItem(prop)) {
|
||||
throw new RuntimeException("Can't use Index on foreign key relationships.");
|
||||
}
|
||||
descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique()));
|
||||
descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique(), index.platforms(), index.concurrent(), index.definition()));
|
||||
}
|
||||
|
||||
private void readJsonAnnotations(DeployBeanProperty prop) {
|
||||
|
||||
@@ -128,7 +128,7 @@ public class DeployInherit {
|
||||
if (dv != null) {
|
||||
info.setDiscriminatorValue(dv.value());
|
||||
} else {
|
||||
info.setDiscriminatorValue(cls.getSimpleName());
|
||||
info.setDiscriminatorDefaultValue(cls);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
|
||||
@@ -178,6 +178,16 @@ public class DeployInheritInfo {
|
||||
return discriminatorStringValue;
|
||||
}
|
||||
|
||||
public void setDiscriminatorDefaultValue(Class<?> cls) {
|
||||
if (columnType == Types.INTEGER) {
|
||||
discriminatorStringValue = "0";
|
||||
discriminatorObjectValue = 0;
|
||||
} else {
|
||||
discriminatorStringValue = cls.getSimpleName();
|
||||
discriminatorObjectValue = discriminatorStringValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the discriminator value for this node.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.annotation.DbArray;
|
||||
import io.ebean.annotation.DbMap;
|
||||
import io.ebean.annotation.DbJson;
|
||||
import io.ebean.annotation.DbJsonB;
|
||||
import io.ebean.annotation.DbJsonType;
|
||||
import io.ebean.annotation.DbMap;
|
||||
import io.ebean.config.EncryptDeploy;
|
||||
import io.ebean.config.EncryptDeployManager;
|
||||
import io.ebean.config.EncryptKeyManager;
|
||||
@@ -191,7 +191,7 @@ public class DeployUtil {
|
||||
void setDbArray(DeployBeanProperty prop, DbArray dbArray) {
|
||||
|
||||
Class<?> type = prop.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, dbArray, prop.getGenericType());
|
||||
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, dbArray, prop.getGenericType(), prop.isNullable());
|
||||
if (scalarType == null) {
|
||||
throw new RuntimeException("No ScalarType for @DbArray type for [" + prop.getFullBeanName() + "]");
|
||||
}
|
||||
@@ -291,4 +291,11 @@ public class DeployUtil {
|
||||
boolean isUseJavaxValidationNotNull() {
|
||||
return useJavaxValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert quoted identifiers if necessary (including all quoted).
|
||||
*/
|
||||
public String convertQuotes(String name) {
|
||||
return dbPlatform.convertQuotedIdentifiers(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,20 @@ public class Str {
|
||||
public static String add(String s0, String s1, String... args) {
|
||||
|
||||
// determine a decent buffer size
|
||||
int len = 16 + s0.length() + s1.length();
|
||||
int len = 16 + s0.length();
|
||||
if (s1 != null) {
|
||||
len += s1.length();
|
||||
}
|
||||
for (String arg1 : args) {
|
||||
len += (arg1 == null) ? 0 : arg1.length();
|
||||
}
|
||||
|
||||
// append all the strings into the buffer
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
sb.append(s0).append(s1);
|
||||
sb.append(s0);
|
||||
if (s1 != null) {
|
||||
sb.append(s1);
|
||||
}
|
||||
for (String arg : args) {
|
||||
if (arg != null) {
|
||||
sb.append(arg);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user