mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
67
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a1704e6a9 | ||
|
|
854c208f92 | ||
|
|
e6f604764c | ||
|
|
9b501b3dc8 | ||
|
|
c2fb23a25c | ||
|
|
1ad7ace9bd | ||
|
|
6a3a7eafea | ||
|
|
896aed0b38 | ||
|
|
f7359aacd7 | ||
|
|
d77fb9265b | ||
|
|
db27844eca | ||
|
|
61be1683b2 | ||
|
|
27a1f35356 | ||
|
|
f0c0b7ebcc | ||
|
|
f4c646cdc1 | ||
|
|
48abc73e50 | ||
|
|
91a327a5e7 | ||
|
|
a861e8bdcc | ||
|
|
7692d9782a | ||
|
|
524e3e31f0 | ||
|
|
d69d96a400 | ||
|
|
0ce39c73f1 | ||
|
|
82d6294dcb | ||
|
|
ba01103f48 | ||
|
|
3e14ec6a5a | ||
|
|
b9d5d35850 | ||
|
|
04adc35ccd | ||
|
|
bfc2b57df5 | ||
|
|
a5880fca97 | ||
|
|
8685f2056a | ||
|
|
2ac19bea1a | ||
|
|
9410f82f5a | ||
|
|
21382a52ed | ||
|
|
f871259f20 | ||
|
|
eb765056fd | ||
|
|
ddf3c753d6 | ||
|
|
4767aff046 | ||
|
|
75846edd97 | ||
|
|
f7c6745de1 | ||
|
|
f080f16e63 | ||
|
|
9135f87253 | ||
|
|
90ccf2d8b4 | ||
|
|
11409f8c09 | ||
|
|
fb472a0304 | ||
|
|
04c9007d22 | ||
|
|
8f75a04ad0 | ||
|
|
2236e4bfd7 | ||
|
|
6d1c3738de | ||
|
|
20160144f5 | ||
|
|
891166507d | ||
|
|
bce97b1063 | ||
|
|
c5b960c588 | ||
|
|
009b400ed3 | ||
|
|
b6ee6ade8c | ||
|
|
0891c067d5 | ||
|
|
7b3b32f0ff | ||
|
|
3878b02cff | ||
|
|
92995b807e | ||
|
|
907d36123d | ||
|
|
2db95f909d | ||
|
|
5213e8b653 | ||
|
|
2314fd267f | ||
|
|
b24f093bbb | ||
|
|
444c868124 | ||
|
|
81b16b8f73 | ||
|
|
e0d322d80a | ||
|
|
1dd0f3cbf8 |
+2
-3
@@ -1,15 +1,14 @@
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
sudo: required
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk11
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
addons:
|
||||
postgresql: "9.6"
|
||||
postgresql: 10
|
||||
# apt:
|
||||
# packages:
|
||||
# - mysql-server-5.7
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.1.13</version>
|
||||
<version>12.2.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -18,12 +18,11 @@
|
||||
<properties>
|
||||
<jackson-core.version>2.10.0</jackson-core.version>
|
||||
<jackson-databind.version>2.10.0</jackson-databind.version>
|
||||
<snakeyaml.version>1.21</snakeyaml.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-12.1.13</tag>
|
||||
<tag>ebean-12.2.2</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -62,13 +61,10 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Exclude snakeyaml if you desire - it is not strictly required.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>config</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -76,22 +72,22 @@
|
||||
to assist with IDE auto-completion with Ebean API
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jsr305</artifactId>
|
||||
<version>1.1</version>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-jsr305</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<version>2.2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.4</version>
|
||||
<version>6.11</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -181,7 +177,7 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.2.2</version>
|
||||
<version>42.2.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -204,7 +200,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean.test</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<version>3.1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -220,7 +216,7 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.197</version>
|
||||
<version>1.4.199</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -296,7 +292,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.1.12</version>
|
||||
<version>12.2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -68,7 +68,7 @@ public interface ExpressionList<T> {
|
||||
* optional asc and desc keywords representing ascending and descending order
|
||||
* respectively.
|
||||
*/
|
||||
Query<T> order(String orderByClause);
|
||||
ExpressionList<T> order(String orderByClause);
|
||||
|
||||
/**
|
||||
* Return the OrderBy so that you can append an ascending or descending
|
||||
@@ -506,7 +506,7 @@ public interface ExpressionList<T> {
|
||||
* @param expressions Filter expressions with and, or and ? or ?1 type bind parameters
|
||||
* @param params Bind parameters used in the expressions
|
||||
*/
|
||||
Query<T> filterMany(String manyProperty, String expressions, Object... params);
|
||||
ExpressionList<T> filterMany(String manyProperty, String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
@@ -557,14 +557,14 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* @see Query#setFirstRow(int)
|
||||
*/
|
||||
Query<T> setFirstRow(int firstRow);
|
||||
ExpressionList<T> setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of rows to fetch.
|
||||
*
|
||||
* @see Query#setMaxRows(int)
|
||||
*/
|
||||
Query<T> setMaxRows(int maxRows);
|
||||
ExpressionList<T> setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the name of the property which values become the key of a map.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.config.properties.PropertiesLoader;
|
||||
import io.avaje.config.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -11,8 +11,6 @@ import java.util.Properties;
|
||||
*/
|
||||
class PrimaryServer {
|
||||
|
||||
private static Properties globalProperties;
|
||||
|
||||
private static String defaultServerName;
|
||||
|
||||
private static boolean skip;
|
||||
@@ -43,14 +41,10 @@ class PrimaryServer {
|
||||
* Return the default configuration Properties.
|
||||
*/
|
||||
static synchronized Properties getProperties() {
|
||||
if (globalProperties == null) {
|
||||
globalProperties = PropertiesLoader.load();
|
||||
}
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = determineDefaultServerName();
|
||||
}
|
||||
return globalProperties;
|
||||
|
||||
return Config.asProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,15 +56,9 @@ class PrimaryServer {
|
||||
defaultServerName = System.getProperty("db", defaultServerName);
|
||||
defaultServerName = System.getProperty("ebean_db", defaultServerName);
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = System.getProperty("datasource.default");
|
||||
defaultServerName = Config.get("datasource.default", null);
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = System.getProperty("ebean.default.datasource");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
}
|
||||
}
|
||||
defaultServerName = Config.get("ebean.default.datasource", null);
|
||||
}
|
||||
}
|
||||
if (defaultServerName == null) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.sql.SQLException;
|
||||
* <pre>{@code
|
||||
*
|
||||
* //
|
||||
* // A mapper from ResultSet into our CustomerDto bean
|
||||
* // Map from ResultSet to CustomerDto bean
|
||||
* //
|
||||
* class CustomerMapper implements RowMapper<CustomerDto> {
|
||||
*
|
||||
@@ -42,7 +42,8 @@ import java.sql.SQLException;
|
||||
*
|
||||
* CustomerDto rob = DB.sqlQuery(sql)
|
||||
* .setParameter(1, "Rob")
|
||||
* .findOne(CUSTOMER_MAPPER);
|
||||
* .mapTo(CUSTOMER_MAPPER)
|
||||
* .findOne();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -75,17 +75,15 @@ public interface SqlQuery extends Serializable {
|
||||
SqlRow findOne();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single result using the mapper.
|
||||
*
|
||||
* @param mapper Used to map each ResultSet row into the result object.
|
||||
* Deprecated migrate to use {@link #mapTo(RowMapper)}
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T findOne(RowMapper<T> mapper);
|
||||
|
||||
/**
|
||||
* Execute the query returning a list using the mapper.
|
||||
*
|
||||
* @param mapper Used to map each ResultSet row into the result object.
|
||||
* Deprecated migrate to use {@link #mapTo(RowMapper)}
|
||||
*/
|
||||
@Deprecated
|
||||
<T> List<T> findList(RowMapper<T> mapper);
|
||||
|
||||
/**
|
||||
@@ -125,64 +123,47 @@ public interface SqlQuery extends Serializable {
|
||||
Optional<SqlRow> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single scalar attribute.
|
||||
* <pre>@{code
|
||||
* Deprecated - migrate to <code>.mapToScalar(attributeType).findOne()</code>.
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
|
||||
*
|
||||
* BigDecimal maxPrice = DB.sqlQuery(sql)
|
||||
* .setParameter(42)
|
||||
* .findSingleAttribute(BigDecimal.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
|
||||
* </p>
|
||||
*
|
||||
* @param attributeType The type of the returned value
|
||||
* .mapToScalar(BigDecimal.class)
|
||||
* .findOne();
|
||||
* }
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T findSingleAttribute(Class<T> attributeType);
|
||||
|
||||
/**
|
||||
* Execute the query returning a single BigDecimal value.
|
||||
* <p>
|
||||
* This is an alias for <code>findSingleAttribute(BigDecimal.class)</code>
|
||||
* </p>
|
||||
* Deprecated - migrate to <code>.mapToScalar(BigDecimal.class).findOne()</code>.
|
||||
* <pre>{@code
|
||||
*
|
||||
* .mapToScalar(BigDecimal.class)
|
||||
* .findOne();
|
||||
* }
|
||||
*/
|
||||
@Deprecated
|
||||
BigDecimal findSingleDecimal();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single Long value.
|
||||
* <p>
|
||||
* This is an alias for <code>findSingleAttribute(Long.class)</code>
|
||||
* </p>
|
||||
* Deprecated - migrate to <code>.mapToScalar(Long.class).findOne()</code>.
|
||||
* <pre>{@code
|
||||
*
|
||||
* .mapToScalar(Long.class)
|
||||
* .findOne();
|
||||
* }
|
||||
*/
|
||||
@Deprecated
|
||||
Long findSingleLong();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list of scalar attribute values.
|
||||
*
|
||||
* Deprecated - migrate to <code>.mapToScalar(Long.class).findList()</code>.
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql =
|
||||
* " select (unit_price * order_qty) " +
|
||||
* " from o_order_detail " +
|
||||
* " where unit_price > ? " +
|
||||
* " order by (unit_price * order_qty) desc";
|
||||
*
|
||||
* List<BigDecimal> lineAmounts =
|
||||
* DB.sqlQuery(sql)
|
||||
* .setParameter(42)
|
||||
* .findSingleAttributeList(BigDecimal.class);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
|
||||
*
|
||||
* @param attributeType The type of the returned value
|
||||
* .mapToScalar(Long.class)
|
||||
* .findList();
|
||||
* }
|
||||
*/
|
||||
@Deprecated
|
||||
<T> List<T> findSingleAttributeList(Class<T> attributeType);
|
||||
|
||||
/**
|
||||
@@ -293,4 +274,59 @@ public interface SqlQuery extends Serializable {
|
||||
*/
|
||||
SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
|
||||
|
||||
/**
|
||||
* The query result maps to a single scalar value like Long, BigDecimal,
|
||||
* String, UUID, OffsetDateTime etc.
|
||||
* <p>
|
||||
* Any scalar type Ebean is aware of can be used including java time
|
||||
* types like Instant, LocalDate, OffsetDateTime, UUID, Inet, Cdir etc.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = " select min(updtime) from o_order_detail " +
|
||||
* " where unit_price > ? and updtime is not null ";
|
||||
*
|
||||
* OffsetDateTime minCreated = DB.sqlQuery(sql)
|
||||
* .setParameter(42)
|
||||
* .mapToScalar(OffsetDateTime.class)
|
||||
* .findOne();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param attributeType The type the result is returned as
|
||||
* @return The query to execute via findOne() findList() etc
|
||||
*/
|
||||
<T> TypeQuery<T> mapToScalar(Class<T> attributeType);
|
||||
|
||||
/**
|
||||
* Use a RowMapper to map the result to beans.
|
||||
*
|
||||
* @param mapper Maps rows to beans
|
||||
* @param <T> The type of beans mapped to
|
||||
* @return The query to execute by findOne() findList() etc
|
||||
*/
|
||||
<T> TypeQuery<T> mapTo(RowMapper<T> mapper);
|
||||
|
||||
/**
|
||||
* Query mapping to single scalar values.
|
||||
*
|
||||
* @param <T> The type of the scalar values
|
||||
*/
|
||||
interface TypeQuery<T> {
|
||||
|
||||
/**
|
||||
* Return the single value.
|
||||
*/
|
||||
T findOne();
|
||||
|
||||
/**
|
||||
* Return the single value that is optional.
|
||||
*/
|
||||
Optional<T> findOneOrEmpty();
|
||||
|
||||
/**
|
||||
* Return the list of values.
|
||||
*/
|
||||
List<T> findList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* <h3>getGeneratedKeys</h3>
|
||||
* <p>
|
||||
* Often with large batch inserts we want to turn off getGeneratedKeys. We do
|
||||
* this via {@link #setBatchGetGeneratedKeys(boolean)}.
|
||||
* this via {@link #setGetGeneratedKeys(boolean)}.
|
||||
* Also note that some JDBC drivers do not support getGeneratedKeys in JDBC batch mode.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
@@ -342,7 +342,7 @@ public interface Transaction extends AutoCloseable {
|
||||
* </p>
|
||||
* <p>
|
||||
* We use {@link #flush()} to explicitly flush the batch and we can use
|
||||
* {@link #setBatchFlushOnQuery(boolean)} and {@link #setBatchFlushOnMixed(boolean)}
|
||||
* {@link #setFlushOnQuery(boolean)} and {@link #setFlushOnMixed(boolean)}
|
||||
* to control the automatic flushing behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -432,7 +432,15 @@ public interface Transaction extends AutoCloseable {
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
void setGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* Deprecated renamed to setGetGeneratedKeys().
|
||||
*/
|
||||
@Deprecated
|
||||
default void setBatchGetGeneratedKeys(boolean getGeneratedKeys) {
|
||||
setGetGeneratedKeys(getGeneratedKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
|
||||
@@ -449,7 +457,15 @@ public interface Transaction extends AutoCloseable {
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnMixed(boolean batchFlushOnMixed);
|
||||
void setFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
/**
|
||||
* Deprecated renamed to setFlushOnMixed().
|
||||
*/
|
||||
@Deprecated
|
||||
default void setBatchFlushOnMixed(boolean batchFlushOnMixed) {
|
||||
setFlushOnMixed(batchFlushOnMixed);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default executing a query will automatically flush any batched
|
||||
@@ -459,7 +475,15 @@ public interface Transaction extends AutoCloseable {
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnQuery(boolean batchFlushOnQuery);
|
||||
void setFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
/**
|
||||
* Deprecated renamed to setFlushOnQuery().
|
||||
*/
|
||||
@Deprecated
|
||||
default void setBatchFlushOnQuery(boolean batchFlushOnQuery) {
|
||||
setFlushOnQuery(batchFlushOnQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the batch (of persisted beans or executed UpdateSql etc)
|
||||
@@ -468,7 +492,15 @@ public interface Transaction extends AutoCloseable {
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
boolean isBatchFlushOnQuery();
|
||||
boolean isFlushOnQuery();
|
||||
|
||||
/**
|
||||
* Deprecated renamed to isFlushOnQuery().
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean isBatchFlushOnQuery() {
|
||||
return isFlushOnQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* The batch will be flushing automatically but you can use this to explicitly
|
||||
|
||||
@@ -36,7 +36,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
private volatile transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
|
||||
@@ -222,8 +222,8 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* Return true if this class is part of entity inheritance.
|
||||
*/
|
||||
protected boolean hasInheritance(Class<?> supCls) {
|
||||
return AnnotationUtil.findAnnotationRecursive(supCls, Inheritance.class) != null
|
||||
|| AnnotationUtil.findAnnotation(supCls, DiscriminatorValue.class) != null;
|
||||
return AnnotationUtil.typeHas(supCls, Inheritance.class)
|
||||
|| AnnotationUtil.has(supCls, DiscriminatorValue.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,16 +255,12 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* Gets the table name from annotation.
|
||||
*/
|
||||
protected TableName getTableNameFromAnnotation(Class<?> beanClass) {
|
||||
|
||||
final Table t = AnnotationUtil.findAnnotationRecursive(beanClass, Table.class);
|
||||
|
||||
// Take the annotation if defined
|
||||
if (t != null && !isEmpty(t.name())) {
|
||||
final Table table = AnnotationUtil.typeGet(beanClass, Table.class);
|
||||
if (table != null && !isEmpty(table.name())) {
|
||||
// Note: empty catalog and schema are converted to null
|
||||
// Only need to convert quoted identifiers from annotations
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
|
||||
return new TableName(quoteIdentifiers(table.catalog()), quoteIdentifiers(table.schema()), quoteIdentifiers(table.name()));
|
||||
}
|
||||
|
||||
// No annotation
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.avaje.config.Config;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
@@ -13,7 +14,6 @@ import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.properties.PropertiesLoader;
|
||||
import io.ebean.datasource.DataSourceConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
@@ -139,7 +139,7 @@ public class ServerConfig {
|
||||
* 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;
|
||||
private boolean loadModuleInfo = true;
|
||||
|
||||
/**
|
||||
* List of interesting classes such as entities, embedded, ScalarTypes,
|
||||
@@ -2746,7 +2746,7 @@ public class ServerConfig {
|
||||
* Load settings from ebean.properties.
|
||||
*/
|
||||
public void loadFromProperties() {
|
||||
this.properties = PropertiesLoader.load();
|
||||
this.properties = Config.asProperties();
|
||||
configureFromProperties();
|
||||
}
|
||||
|
||||
@@ -2755,7 +2755,7 @@ public class ServerConfig {
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
// keep the properties used for configuration so that these are available for plugins
|
||||
this.properties = PropertiesLoader.eval(properties);
|
||||
this.properties = Config.asConfiguration().eval(properties);
|
||||
configureFromProperties();
|
||||
}
|
||||
|
||||
@@ -3298,6 +3298,17 @@ public class ServerConfig {
|
||||
return loadModuleInfo && classes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set false to turn off automatic registration of entity beans.
|
||||
* <p>
|
||||
* When using query beans that also generates a module info class that
|
||||
* can register the entity bean classes (to avoid classpath scanning).
|
||||
* This is on by default and setting this to false turns it off.
|
||||
*/
|
||||
public void setLoadModuleInfo(boolean loadModuleInfo) {
|
||||
this.loadModuleInfo = loadModuleInfo;
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
|
||||
@@ -146,7 +146,7 @@ public class DatabasePlatform {
|
||||
|
||||
protected String truncateTable = "truncate table %s";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
protected String columnAliasPrefix;
|
||||
|
||||
/**
|
||||
* Use a BackTick ` at the beginning and end of table or column names that you
|
||||
@@ -278,7 +278,7 @@ public class DatabasePlatform {
|
||||
* Return true if this matches the given platform.
|
||||
*/
|
||||
public boolean isPlatform(Platform platform) {
|
||||
return this.platform == platform;
|
||||
return this.platform.base() == platform;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,7 +116,7 @@ public class DbPlatformTypeMapping {
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
put(DbType.CHAR, new DbPlatformType("char", 1));
|
||||
|
||||
@@ -35,6 +35,11 @@ public enum IdType {
|
||||
* Used when the key is a compound key or lookup table code.
|
||||
* </p>
|
||||
*/
|
||||
EXTERNAL
|
||||
EXTERNAL,
|
||||
|
||||
/**
|
||||
* Auto mapping to platform preferred identity strategy.
|
||||
*/
|
||||
AUTO
|
||||
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ public class LimitOffsetSqlLimiter implements SqlLimiter {
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, false);
|
||||
return new SqlLimitResponse(sql);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package io.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Adds the ROW_NUMBER() OVER function to a query.
|
||||
*/
|
||||
public class RowNumberSqlLimiter implements SqlLimiter {
|
||||
|
||||
/**
|
||||
* ROW_NUMBER() OVER (ORDER BY
|
||||
*/
|
||||
private static final String ROW_NUMBER_OVER = "row_number() over (order by ";
|
||||
|
||||
/**
|
||||
* ) as rn,
|
||||
*/
|
||||
private static final String ROW_NUMBER_AS = ") as rn, ";
|
||||
|
||||
private final String rowNumberWindowAlias;
|
||||
|
||||
/**
|
||||
* Specify the name of the rowNumberWindowAlias.
|
||||
*/
|
||||
public RowNumberSqlLimiter(String rowNumberWindowAlias) {
|
||||
this.rowNumberWindowAlias = rowNumberWindowAlias;
|
||||
}
|
||||
|
||||
public RowNumberSqlLimiter() {
|
||||
this("as limitresult");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow += firstRow;
|
||||
}
|
||||
|
||||
sb.append("select * from ( ");
|
||||
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
|
||||
sb.append(ROW_NUMBER_OVER);
|
||||
sb.append(request.getDbOrderBy());
|
||||
sb.append(ROW_NUMBER_AS);
|
||||
|
||||
sb.append(dbSql);
|
||||
|
||||
sb.append(" ) ");
|
||||
sb.append(rowNumberWindowAlias);
|
||||
sb.append(" where ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(" rn > ").append(firstRow);
|
||||
if (lastRow > 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
}
|
||||
if (lastRow > 0) {
|
||||
sb.append(" rn <= ").append(lastRow);
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, true);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package io.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Add ROWNUM column etc around SQL query to limit results.
|
||||
*/
|
||||
public class RownumSqlLimiter implements SqlLimiter {
|
||||
|
||||
private final String rnum;
|
||||
|
||||
private final boolean useFirstRowsHint;
|
||||
|
||||
/**
|
||||
* Create with default inner rownum column alias and used FIRST_ROWS hint.
|
||||
*/
|
||||
public RownumSqlLimiter() {
|
||||
this("rn_", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the inner rownum column alias and whether to include the FIRST_ROWS
|
||||
* hint.
|
||||
*/
|
||||
public RownumSqlLimiter(String rnum, boolean useFirstRowsHint) {
|
||||
this.rnum = rnum;
|
||||
this.useFirstRowsHint = useFirstRowsHint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
// select *
|
||||
// from ( select /*+ FIRST_ROWS(n) */ ROWNUM rnum, a.*
|
||||
// from ( your_query_goes_here,
|
||||
// with order by ) a
|
||||
// where ROWNUM <=
|
||||
// :MAX_ROW_TO_FETCH )
|
||||
// where rnum >= :MIN_ROW_TO_FETCH;
|
||||
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow += firstRow;
|
||||
}
|
||||
|
||||
sb.append("select * from ( ");
|
||||
|
||||
sb.append("select ");
|
||||
if (useFirstRowsHint && request.getMaxRows() > 0) {
|
||||
sb.append("/*+ FIRST_ROWS(").append(request.getMaxRows()).append(") */ ");
|
||||
}
|
||||
|
||||
sb.append("rownum ").append(rnum).append(", a.* ");
|
||||
sb.append(" from (");
|
||||
|
||||
sb.append(" select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append(dbSql);
|
||||
|
||||
sb.append(NEW_LINE).append(" ) a ");
|
||||
if (lastRow > 0) {
|
||||
sb.append(" where rownum <= ").append(lastRow);
|
||||
}
|
||||
sb.append(" ) ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(" where ");
|
||||
sb.append(rnum).append(" > ").append(firstRow);
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,14 +7,11 @@ public class SqlLimitResponse {
|
||||
|
||||
final String sql;
|
||||
|
||||
final boolean includesRowNumberColumn;
|
||||
|
||||
/**
|
||||
* Create the response.
|
||||
*/
|
||||
public SqlLimitResponse(String sql, boolean includesRowNumberColumn) {
|
||||
public SqlLimitResponse(String sql) {
|
||||
this.sql = sql;
|
||||
this.includesRowNumberColumn = includesRowNumberColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,11 +21,4 @@ public class SqlLimitResponse {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a ROW_NUMBER column is used in the query.
|
||||
*/
|
||||
public boolean isIncludesRowNumberColumn() {
|
||||
return includesRowNumberColumn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,8 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
//this.dbEncrypt =
|
||||
//this.historySupport =
|
||||
//this.exceptionTranslator =
|
||||
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
@@ -34,7 +32,7 @@ public class ClickHousePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("UInt16", false));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("UInt32", false));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16,4));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16, 3));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("Float64", false));
|
||||
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false));
|
||||
|
||||
@@ -42,8 +42,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3));
|
||||
persistBatchOnCascade = PersistBatch.NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,6 @@ public class Db2SqlLimiter implements SqlLimiter {
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
return new SqlLimitResponse(sql, false);
|
||||
return new SqlLimitResponse(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.inlineSqlUpdateLimit = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("50200","HYT00")
|
||||
|
||||
@@ -17,7 +17,6 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
this.sqlLimiter = new HanaSqlLimiter();
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.columnAliasPrefix = null;
|
||||
this.historySupport = new HanaHistorySupport();
|
||||
this.basicSqlLimiter = new HanaBasicSqlLimiter();
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ public class HanaSqlLimiter implements SqlLimiter {
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, false);
|
||||
return new SqlLimitResponse(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.inlineSqlUpdateLimit = true;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
this.columnAliasPrefix = null;
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -23,7 +23,6 @@ public class NuoDbPlatform extends DatabasePlatform {
|
||||
this.idInExpandedForm = true;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.columnAliasPrefix = null;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.historySupport = new NuoDbHistorySupport();
|
||||
//this.dbEncrypt = ...
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.ebean.config.dbplatform.oracle;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
/**
|
||||
* Oracle 11 platform using rownum sql limiting.
|
||||
*/
|
||||
public class Oracle11Platform extends OraclePlatform {
|
||||
|
||||
public Oracle11Platform() {
|
||||
super();
|
||||
this.platform = Platform.ORACLE11;
|
||||
this.columnAliasPrefix = "c";
|
||||
this.sqlLimiter = new OracleRownumSqlLimiter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.ebean.config.dbplatform.oracle;
|
||||
|
||||
import io.ebean.config.dbplatform.SqlLimitRequest;
|
||||
import io.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import io.ebean.config.dbplatform.SqlLimiter;
|
||||
|
||||
/**
|
||||
* Use ANSI offset rows syntax.
|
||||
*/
|
||||
class OracleAnsiSqlRowsLimiter implements SqlLimiter {
|
||||
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
String dbSql = request.getDbSql();
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
int firstRow = request.getFirstRow();
|
||||
int maxRows = request.getMaxRows();
|
||||
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append(dbSql);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" offset ").append(firstRow).append(" rows");
|
||||
}
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
return new SqlLimitResponse(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.config.dbplatform.RownumSqlLimiter;
|
||||
import io.ebean.config.dbplatform.SqlErrorCodes;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -27,7 +26,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.sqlLimiter = new OracleAnsiSqlRowsLimiter();
|
||||
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
@@ -63,8 +62,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("number", 19, 4));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("number", 5));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 38));
|
||||
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 16, 3));
|
||||
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255));
|
||||
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob"));
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.ebean.config.dbplatform.oracle;
|
||||
|
||||
import io.ebean.config.dbplatform.SqlLimitRequest;
|
||||
import io.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import io.ebean.config.dbplatform.SqlLimiter;
|
||||
|
||||
/**
|
||||
* Add ROWNUM column etc around SQL query to limit results.
|
||||
*/
|
||||
class OracleRownumSqlLimiter implements SqlLimiter {
|
||||
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
// select *
|
||||
// from ( select /*+ FIRST_ROWS(n) */ a.*, ROWNUM rnum
|
||||
// from ( your_query_goes_here,
|
||||
// with order by ) a
|
||||
// where ROWNUM <=
|
||||
// :MAX_ROW_TO_FETCH )
|
||||
// where rnum >= :MIN_ROW_TO_FETCH;
|
||||
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
int firstRow = request.getFirstRow();
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow += firstRow;
|
||||
}
|
||||
|
||||
sb.append("select * from (select ");
|
||||
if (request.getMaxRows() > 0) {
|
||||
sb.append("/*+ FIRST_ROWS(").append(request.getMaxRows()).append(") */ ");
|
||||
}
|
||||
|
||||
sb.append("a.*, rownum rn_ from (select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append(dbSql).append(") a ");
|
||||
if (lastRow > 0) {
|
||||
sb.append(" where rownum <= ").append(lastRow);
|
||||
}
|
||||
sb.append(") ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(" where rn_ > ").append(firstRow);
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
return new SqlLimitResponse(sql);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package io.ebean.config.dbplatform.postgres;
|
||||
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
|
||||
/**
|
||||
* Postgres v8.3 specific platform.
|
||||
* <p>
|
||||
* No support for getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
public class Postgres8Platform extends PostgresPlatform {
|
||||
|
||||
public Postgres8Platform() {
|
||||
super();
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.columnAliasPrefix = "as c";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.ebean.config.dbplatform.postgres;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
/**
|
||||
* Postgres9 platform - uses serial type for identity columns.
|
||||
*/
|
||||
public class Postgres9Platform extends PostgresPlatform {
|
||||
|
||||
public Postgres9Platform() {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES9;
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,9 @@ import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Postgres v9 specific platform.
|
||||
* Postgres 10+ platform.
|
||||
* <p>
|
||||
* Uses serial types and getGeneratedKeys.
|
||||
* </p>
|
||||
* Defaults to use "generated by default as identity".
|
||||
*/
|
||||
public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
@@ -35,7 +34,6 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
this.nativeUuidType = true;
|
||||
this.columnAliasPrefix = null;
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
@@ -72,7 +70,6 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz"));
|
||||
|
||||
dbTypeMap.put(DbType.BINARY, dbBytea);
|
||||
|
||||
@@ -35,8 +35,7 @@ public class SqlAnywhereLimiter implements SqlLimiter {
|
||||
sb.append(dbSql);
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, false);
|
||||
return new SqlLimitResponse(sql);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,8 +32,7 @@ public class SqlAnywherePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 16, 3));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("binary(4500)"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("long varchar"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("long binary"));
|
||||
|
||||
@@ -12,7 +12,6 @@ public class SqlServer17Platform extends SqlServerBasePlatform {
|
||||
public SqlServer17Platform() {
|
||||
super();
|
||||
this.platform = Platform.SQLSERVER17;
|
||||
this.columnAliasPrefix = null;
|
||||
this.nativeUuidType = true;
|
||||
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("uniqueidentifier", false));
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package io.ebean.config.dbplatform.sqlserver;
|
||||
|
||||
/**
|
||||
* SQL Server platform using the older ROW_NUMBER() mechanism.
|
||||
*/
|
||||
public class SqlServer2005Platform extends SqlServer16Platform {
|
||||
|
||||
public SqlServer2005Platform() {
|
||||
this.sqlLimiter = new SqlServer2005SqlLimiter();
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package io.ebean.config.dbplatform.sqlserver;
|
||||
|
||||
import io.ebean.config.dbplatform.SqlLimitRequest;
|
||||
import io.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import io.ebean.config.dbplatform.SqlLimiter;
|
||||
|
||||
/**
|
||||
* Use top and row_number() function to limit sql results.
|
||||
*/
|
||||
public class SqlServer2005SqlLimiter implements SqlLimiter {
|
||||
|
||||
final String rowNumberWindowAlias;
|
||||
|
||||
/**
|
||||
* Specify the name of the rowNumberWindowAlias.
|
||||
*/
|
||||
public SqlServer2005SqlLimiter(String rowNumberWindowAlias) {
|
||||
this.rowNumberWindowAlias = rowNumberWindowAlias;
|
||||
}
|
||||
|
||||
public SqlServer2005SqlLimiter() {
|
||||
this("as limitresult");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(500);
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow += firstRow;
|
||||
}
|
||||
|
||||
if (firstRow < 1) {
|
||||
// just use top n
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append("top ").append(lastRow).append(" ");
|
||||
sb.append(request.getDbSql());
|
||||
return new SqlLimitResponse(sb.toString(), false);
|
||||
}
|
||||
|
||||
/*
|
||||
* SELECT * FROM (SELECT TOP 20 ROW_NUMBER() OVER (ORDER BY ...) AS rn, ...)
|
||||
* AS limitresult WHERE rn >= 11 AND rn <= 20
|
||||
*/
|
||||
|
||||
sb.append("select * ").append(NEW_LINE).append("from ( ");
|
||||
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append("top ").append(lastRow);
|
||||
sb.append(" row_number() over (order by ");
|
||||
sb.append(request.getDbOrderBy());
|
||||
sb.append(") as rn, ");
|
||||
sb.append(request.getDbSql());
|
||||
|
||||
sb.append(NEW_LINE).append(") ");
|
||||
sb.append(rowNumberWindowAlias);
|
||||
sb.append(" where ");
|
||||
sb.append(" rn > ").append(firstRow);
|
||||
if (lastRow > 0) {
|
||||
sb.append(" and ");
|
||||
sb.append(" rn <= ").append(lastRow);
|
||||
}
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
return new SqlLimitResponse(sql, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,9 +62,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 16, 3));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("date"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("time"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2"));
|
||||
|
||||
@@ -29,7 +29,7 @@ public class SqlServerSqlLimiter implements SqlLimiter {
|
||||
}
|
||||
sb.append("top ").append(maxRows).append(" ");
|
||||
sb.append(dbSql);
|
||||
return new SqlLimitResponse(sb.toString(), false);
|
||||
return new SqlLimitResponse(sb.toString());
|
||||
}
|
||||
|
||||
sb.append("select ");
|
||||
@@ -43,8 +43,7 @@ public class SqlServerSqlLimiter implements SqlLimiter {
|
||||
if (maxRows > 0) {
|
||||
sb.append(" fetch next ").append(maxRows).append(" rows only");
|
||||
}
|
||||
String sql = sb.toString();
|
||||
return new SqlLimitResponse(sql, false);
|
||||
return new SqlLimitResponse(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
package io.ebean.config.properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manages the underlying map of properties we are gathering.
|
||||
*/
|
||||
class LoadContext {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LoadContext.class);
|
||||
|
||||
/**
|
||||
* Map we are loading the properties into.
|
||||
*/
|
||||
private final Map<String, String> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Names of resources/files that were loaded.
|
||||
*/
|
||||
private final Set<String> loadedResources = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* Return the input stream (maybe null) for the given source.
|
||||
*/
|
||||
InputStream resource(String resourcePath, Loader.Source source) {
|
||||
|
||||
InputStream is = null;
|
||||
if (source == Loader.Source.RESOURCE) {
|
||||
is = resourceStream(resourcePath);
|
||||
if (is != null) {
|
||||
loadedResources.add(resourcePath);
|
||||
}
|
||||
} else {
|
||||
File file = new File(resourcePath);
|
||||
if (file.exists()) {
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
loadedResources.add("file:" + resourcePath);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
private InputStream resourceStream(String resourcePath) {
|
||||
InputStream is = getClass().getResourceAsStream("/" + resourcePath);
|
||||
if (is == null) {
|
||||
// search the module path for top level resource
|
||||
is = ClassLoader.getSystemResourceAsStream(resourcePath);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property entry.
|
||||
*/
|
||||
void put(String key, String val) {
|
||||
if (val != null) {
|
||||
val = val.trim();
|
||||
}
|
||||
map.put(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate all the expressions and return as a Properties object.
|
||||
*/
|
||||
Properties eval() {
|
||||
|
||||
log.info("loaded properties from {}", loadedResources);
|
||||
|
||||
Properties properties = new Properties();
|
||||
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = PropertyEval.eval(entry.getValue());
|
||||
properties.setProperty(key, value);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the special properties that can point to an external properties source.
|
||||
*/
|
||||
String indirectLocation() {
|
||||
String indirectLocation = map.get("load.properties");
|
||||
if (indirectLocation == null) {
|
||||
indirectLocation = map.get("load.properties.override");
|
||||
}
|
||||
return indirectLocation;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package io.ebean.config.properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Loads the configuration from known/expected locations.
|
||||
* <p>
|
||||
* Defines the loading order of resources and files.
|
||||
* </p>
|
||||
*/
|
||||
class Loader {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Loader.class);
|
||||
|
||||
enum Source {
|
||||
RESOURCE,
|
||||
FILE
|
||||
}
|
||||
|
||||
private final LoadContext loadContext = new LoadContext();
|
||||
|
||||
private YamlLoader yamlLoader;
|
||||
|
||||
Loader() {
|
||||
String skipYaml = System.getProperty("ebeanSkipYaml");
|
||||
if (!"true".equals(skipYaml)) {
|
||||
try {
|
||||
Class<?> exists = Class.forName("org.yaml.snakeyaml.Yaml");
|
||||
if (exists != null) {
|
||||
yamlLoader = new YamlLoader(loadContext);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configuration with the expected ordering.
|
||||
*/
|
||||
void load() {
|
||||
|
||||
loadMain(Source.RESOURCE);
|
||||
// external file configuration overrides the resources configuration
|
||||
loadMain(Source.FILE);
|
||||
|
||||
loadViaSystemProperty();
|
||||
loadViaIndirection();
|
||||
|
||||
// test configuration (if found) overrides main configuration
|
||||
// we should only find these resources when running tests
|
||||
loadTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load test configuration.
|
||||
*/
|
||||
private void loadTest() {
|
||||
loadProperties("application-test.properties", Source.RESOURCE);
|
||||
loadYaml("application-test.yaml", Source.RESOURCE);
|
||||
loadYaml("application-test.yml", Source.RESOURCE);
|
||||
loadProperties("test-ebean.properties", Source.RESOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration defined by a <em>load.properties</em> entry in properties file.
|
||||
*/
|
||||
private void loadViaIndirection() {
|
||||
|
||||
String location = loadContext.indirectLocation();
|
||||
if (location != null) {
|
||||
location = PropertyEval.eval(location);
|
||||
loadWithExtensionCheck(location);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the main configuration for the given source.
|
||||
*/
|
||||
private void loadMain(Source source) {
|
||||
loadYaml("application.yaml", source);
|
||||
loadYaml("application.yml", source);
|
||||
loadProperties("application.properties", source);
|
||||
loadProperties("ebean.properties", source);
|
||||
}
|
||||
|
||||
private void loadViaSystemProperty() {
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName != null) {
|
||||
loadWithExtensionCheck(fileName);
|
||||
}
|
||||
} else {
|
||||
loadWithExtensionCheck(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
void loadWithExtensionCheck(String fileName) {
|
||||
if (fileName.endsWith("yaml") || fileName.endsWith("yml")) {
|
||||
loadYaml(fileName, Source.FILE);
|
||||
} else if (fileName.endsWith("properties")) {
|
||||
loadProperties(fileName, Source.FILE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expecting only yml or properties file but got [" + fileName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate all the configuration entries and return as properties.
|
||||
*/
|
||||
Properties eval() {
|
||||
return loadContext.eval();
|
||||
}
|
||||
|
||||
void loadYaml(String resourcePath, Source source) {
|
||||
if (yamlLoader != null) {
|
||||
try {
|
||||
try (InputStream is = resource(resourcePath, source)) {
|
||||
yamlLoader.load(is);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to read yml from:" + resourcePath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadProperties(String resourcePath, Source source) {
|
||||
try {
|
||||
try (InputStream is = resource(resourcePath, source)) {
|
||||
if (is != null) {
|
||||
loadProperties(is);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to read properties from:" + resourcePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream resource(String resourcePath, Source source) {
|
||||
return loadContext.resource(resourcePath, source);
|
||||
}
|
||||
|
||||
private void loadProperties(InputStream is) {
|
||||
|
||||
if (is != null) {
|
||||
try {
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
put(properties);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to load properties?", e);
|
||||
} finally {
|
||||
close(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void put(Properties properties) {
|
||||
Enumeration<?> enumeration = properties.propertyNames();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
String key = (String) enumeration.nextElement();
|
||||
String property = properties.getProperty(key);
|
||||
loadContext.put(key, property);
|
||||
}
|
||||
}
|
||||
|
||||
private void close(InputStream is) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
log.warn("Error closing input stream for properties", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package io.ebean.config.properties;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Loads and evaluates properties and yml configuration.
|
||||
*/
|
||||
public class PropertiesLoader {
|
||||
|
||||
private static Properties properties;
|
||||
|
||||
/**
|
||||
* Provides properties by reading known locations.
|
||||
* <p>
|
||||
* <h3>Main configuration</h3>
|
||||
* <p>
|
||||
* <p>Firstly loads from main resources</p>
|
||||
* <pre>
|
||||
* - application.properties
|
||||
* - application.yaml
|
||||
* - ebean.properties
|
||||
* </pre>
|
||||
* <p>
|
||||
* <p>Then loads from local files</p>
|
||||
* <pre>
|
||||
* - application.properties
|
||||
* - application.yaml
|
||||
* - ebean.properties
|
||||
* </pre>
|
||||
* <p>
|
||||
* <p>Then loads from environment variable <em>EBEAN_PROPS_FILE</em></p>
|
||||
* <p>Then loads from system property <em>ebean.props.file</em></p>
|
||||
* <p>Then loads from <em>load.properties</em></p>
|
||||
* <p>
|
||||
* <h3>Test configuration</h3>
|
||||
* <p>
|
||||
* Once the main configuration is read it will try to read common test configuration.
|
||||
* This will only be successful if the test resources are available (i.e. running tests).
|
||||
* </p>
|
||||
* <p>Loads from test resources</p>
|
||||
* <pre>
|
||||
* - application-test.properties
|
||||
* - application-test.yaml
|
||||
* - test-ebean.properties
|
||||
* </pre>
|
||||
*/
|
||||
public static synchronized Properties load() {
|
||||
|
||||
if (properties == null) {
|
||||
Loader loader = new Loader();
|
||||
loader.load();
|
||||
properties = loader.eval();
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the properties with 'eval' run on all the values.
|
||||
* This resolves expressions like ${HOME} etc.
|
||||
*/
|
||||
public static Properties eval(Properties properties) {
|
||||
Properties evalCopy = new Properties();
|
||||
|
||||
Enumeration<?> names = properties.propertyNames();
|
||||
while (names.hasMoreElements()) {
|
||||
String name = (String)names.nextElement();
|
||||
String value = PropertyEval.eval(properties.getProperty(name));
|
||||
evalCopy.setProperty(name, value);
|
||||
}
|
||||
return evalCopy;
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
package io.ebean.config.properties;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* Helper used to evaluate expressions such as ${CATALINA_HOME}.
|
||||
* <p>
|
||||
* The expressions can contain environment variables, system properties or JNDI
|
||||
* properties. JNDI expressions take the form ${jndi:propertyName} where you
|
||||
* substitute propertyName with the name of the jndi property you wish to
|
||||
* evaluate.
|
||||
* </p>
|
||||
*/
|
||||
final class PropertyEval {
|
||||
|
||||
/**
|
||||
* Prefix for looking up JNDI Environment variable.
|
||||
*/
|
||||
private static final String JAVA_COMP_ENV = "java:comp/env/";
|
||||
|
||||
/**
|
||||
* Used to detect the start of an expression.
|
||||
*/
|
||||
private static final String START = "${";
|
||||
|
||||
/**
|
||||
* Used to detect the end of an expression.
|
||||
*/
|
||||
private static final String END = "}";
|
||||
|
||||
/**
|
||||
* Specify the PropertyHolder.
|
||||
*/
|
||||
private PropertyEval() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value evaluating and replacing any expressions such as
|
||||
* ${CATALINA_HOME}.
|
||||
*/
|
||||
static String eval(String val) {
|
||||
if (val == null) {
|
||||
return null;
|
||||
}
|
||||
int sp = val.indexOf(START);
|
||||
if (sp > -1) {
|
||||
int ep = val.indexOf(END, sp + 1);
|
||||
if (ep > -1) {
|
||||
return eval(val, sp, ep);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the expression using JNDI, Environment variables, System Properties
|
||||
* or existing an property in SystemProperties itself.
|
||||
*/
|
||||
private static String evaluateExpression(String exp) {
|
||||
|
||||
if (exp.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (isJndiExpression(exp)) {
|
||||
// JNDI property lookup...
|
||||
String val = getJndiProperty(exp);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
String val = System.getProperty(exp);
|
||||
if (val == null) {
|
||||
val = System.getenv(exp);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
private static String eval(String val, int sp, int ep) {
|
||||
|
||||
return new EvalBuffer(val, sp, ep).process();
|
||||
}
|
||||
|
||||
|
||||
private static boolean isJndiExpression(String exp) {
|
||||
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if JNDI is not setup or if the property is not found.
|
||||
*
|
||||
* @param key the key of the JNDI Environment property including a JNDI: prefix.
|
||||
*/
|
||||
private static String getJndiProperty(String key) {
|
||||
|
||||
try {
|
||||
// remove the JNDI: prefix
|
||||
key = key.substring(5);
|
||||
return (String) getJndiObject(key);
|
||||
} catch (NamingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to getProperty but throws NamingException if JNDI is not setup or
|
||||
* if the property is not found.
|
||||
*/
|
||||
private static Object getJndiObject(String key) throws NamingException {
|
||||
|
||||
InitialContext ctx = new InitialContext();
|
||||
return ctx.lookup(JAVA_COMP_ENV + key);
|
||||
}
|
||||
|
||||
|
||||
private static class EvalBuffer {
|
||||
|
||||
private final StringBuilder buf = new StringBuilder();
|
||||
private final String original;
|
||||
private int position;
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
private String expression;
|
||||
private String defaultValue;
|
||||
|
||||
EvalBuffer(String val, int start, int ep) {
|
||||
this.original = val;
|
||||
this.start = start;
|
||||
this.end = ep;
|
||||
this.position = 0;
|
||||
moveToStart();
|
||||
}
|
||||
|
||||
void moveToStart() {
|
||||
if (start > position) {
|
||||
buf.append(original.substring(position, start));
|
||||
position = start;
|
||||
}
|
||||
}
|
||||
|
||||
void parseForDefault() {
|
||||
int colonPos = original.lastIndexOf(':', end);
|
||||
if (colonPos > start) {
|
||||
expression = original.substring(start + START.length(), colonPos);
|
||||
defaultValue = original.substring(colonPos + 1, end);
|
||||
} else {
|
||||
expression = original.substring(start + START.length(), end);
|
||||
}
|
||||
}
|
||||
|
||||
void evaluate() {
|
||||
String eval = evaluateExpression(expression);
|
||||
if (eval != null) {
|
||||
buf.append(eval);
|
||||
} else {
|
||||
if (defaultValue != null) {
|
||||
buf.append(defaultValue);
|
||||
} else {
|
||||
buf.append(START).append(expression).append(END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String end() {
|
||||
if (end < original.length() - 1) {
|
||||
buf.append(original.substring(end + 1));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
boolean next() {
|
||||
if (end < original.length()) {
|
||||
int startPos = original.indexOf(START, end + 1);
|
||||
if (startPos > -1) {
|
||||
int endPos = original.indexOf(END, startPos + 1);
|
||||
if (endPos > -1) {
|
||||
if (startPos > end + 1) {
|
||||
buf.append(original.substring(end + 1, startPos));
|
||||
}
|
||||
this.start = startPos;
|
||||
this.end = endPos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void evalNext() {
|
||||
parseForDefault();
|
||||
evaluate();
|
||||
}
|
||||
|
||||
String process() {
|
||||
evalNext();
|
||||
while (next()) {
|
||||
evalNext();
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package io.ebean.config.properties;
|
||||
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Loads configuration from Yml into the load context.
|
||||
* <p>
|
||||
* Note that this ignores 'lists' so just reads 'maps' and scalar values.
|
||||
* </p>
|
||||
*/
|
||||
class YamlLoader {
|
||||
|
||||
private final Yaml yaml = new Yaml();
|
||||
|
||||
private final LoadContext loadContext;
|
||||
|
||||
YamlLoader(LoadContext loadContext) {
|
||||
this.loadContext = loadContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void load(InputStream is) {
|
||||
if (is != null) {
|
||||
for (Object map : yaml.loadAll(is)) {
|
||||
loadMap((Map<String, Object>)map, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void loadMap(Map<String, Object> map, String path) {
|
||||
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (path != null) {
|
||||
key = path + "." + key;
|
||||
}
|
||||
Object val = entry.getValue();
|
||||
if (val instanceof Map) {
|
||||
loadMap((Map<String, Object>) val, key);
|
||||
} else {
|
||||
addScalar(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addScalar(String key, Object val) {
|
||||
if (val instanceof String) {
|
||||
loadContext.put(key, (String) val);
|
||||
} else if (val instanceof Number || val instanceof Boolean) {
|
||||
loadContext.put(key, val.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,11 +5,6 @@ package io.ebean.meta;
|
||||
*/
|
||||
public interface MetaMetric {
|
||||
|
||||
/**
|
||||
* Return the metric type.
|
||||
*/
|
||||
MetricType getMetricType();
|
||||
|
||||
/**
|
||||
* Return the metric name.
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,6 @@ package io.ebean.meta;
|
||||
public class MetricData {
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private String hash;
|
||||
private String loc;
|
||||
private String sql;
|
||||
@@ -16,9 +15,8 @@ public class MetricData {
|
||||
private Long max;
|
||||
private Long total;
|
||||
|
||||
public MetricData(String name, String type) {
|
||||
public MetricData(String name) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public MetricData() {
|
||||
@@ -32,14 +30,6 @@ public class MetricData {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.ebean.meta;
|
||||
|
||||
/**
|
||||
* The type of Metric.
|
||||
*/
|
||||
public enum MetricType {
|
||||
|
||||
/**
|
||||
* Transactions.
|
||||
*/
|
||||
TXN,
|
||||
|
||||
/**
|
||||
* ORM Insert Update or Delete.
|
||||
*/
|
||||
IUD,
|
||||
|
||||
/**
|
||||
* ORM queries.
|
||||
*/
|
||||
ORM,
|
||||
|
||||
/**
|
||||
* DTO queries.
|
||||
*/
|
||||
DTO,
|
||||
|
||||
/**
|
||||
* SQL queries with a label will have metrics collected.
|
||||
* <p>
|
||||
* SqlQuery and SqlUpdate without a label have no metrics collected.
|
||||
*/
|
||||
SQL,
|
||||
|
||||
/**
|
||||
* L2 cache metrics.
|
||||
*/
|
||||
L2
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebean.metric;
|
||||
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.meta.MetricType;
|
||||
|
||||
/**
|
||||
* Factory to create timed metric counters.
|
||||
@@ -18,21 +17,21 @@ public interface MetricFactory {
|
||||
/**
|
||||
* Create a timed metric group.
|
||||
*/
|
||||
TimedMetricMap createTimedMetricMap(MetricType metricType, String name);
|
||||
TimedMetricMap createTimedMetricMap(String name);
|
||||
|
||||
/**
|
||||
* Create a Timed metric.
|
||||
*/
|
||||
TimedMetric createTimedMetric(MetricType metricType, String name);
|
||||
TimedMetric createTimedMetric(String name);
|
||||
|
||||
/**
|
||||
* Create a counter metric.
|
||||
*/
|
||||
CountMetric createCountMetric(MetricType metricType, String name);
|
||||
CountMetric createCountMetric(String name);
|
||||
|
||||
/**
|
||||
* Create a Timed metric.
|
||||
*/
|
||||
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql);
|
||||
QueryPlanMetric createQueryPlanMetric(Class<?> type, String label, ProfileLocation profileLocation, String sql);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,12 +8,11 @@ import io.ebean.event.BeanPersistListener;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Information and methods on BeanDescriptors made available to plugins.
|
||||
*/
|
||||
@@ -156,11 +155,6 @@ public interface BeanType<T> {
|
||||
*/
|
||||
IdType getIdType();
|
||||
|
||||
/**
|
||||
* Return the sequence name associated to this entity bean type (if there is one).
|
||||
*/
|
||||
String getSequenceName();
|
||||
|
||||
/**
|
||||
* Return true if this bean type has doc store backing.
|
||||
*/
|
||||
|
||||
@@ -171,7 +171,7 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
|
||||
logger.info("Creating transaction, batchSize[" + persistBatchSize + "]");
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(persistBatchSize);
|
||||
transaction.setBatchGetGeneratedKeys(false);
|
||||
transaction.setGetGeneratedKeys(false);
|
||||
|
||||
} else {
|
||||
// explicitly turn off JDBC batching in case
|
||||
|
||||
@@ -1,304 +1,98 @@
|
||||
package io.ebean.util;
|
||||
|
||||
import io.ebean.annotation.Formula;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.Where;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Annotation utility methods to find annotations recursively - taken from the spring framework.
|
||||
* Annotation utility methods to find annotations.
|
||||
*/
|
||||
public class AnnotationUtil {
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Annotation} is defined in the core JDK {@code java.lang.annotation} package.
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
|
||||
return annotation.annotationType().getName().startsWith("java.lang.annotation");
|
||||
public static boolean notJavaLang(Annotation annotation) {
|
||||
return !annotation.annotationType().getName().startsWith("java.lang.annotation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the supplied {@link AnnotatedElement}.
|
||||
* <p>
|
||||
* Meta-annotations will be searched if the annotation is not <em>directly present</em> on the supplied element.
|
||||
* <p>
|
||||
* <strong>Warning</strong>: this method operates generically on annotated elements. In other words, this method
|
||||
* does not execute specialized search algorithms for classes or methods. It only traverses through Annotations!
|
||||
* It also does not filter out platform dependent annotations!
|
||||
* Simple get on field or method with no meta-annotations or platform filtering.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// check if directly present, if not, start search for meta-annotations.
|
||||
Annotation[] anns = annotatedElement.getAnnotations();
|
||||
if (anns.length == 0) {
|
||||
return null; // no annotations present, so searching for meta annotations not required
|
||||
}
|
||||
|
||||
// As we need the anns array anyway, we iterate over this instead
|
||||
// of using annotatedElement.getAnnotation(...) which is synchronized internally
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
}
|
||||
}
|
||||
|
||||
return findAnnotation(anns, annotationType, new HashSet<>());
|
||||
|
||||
public static <A extends Annotation> A get(AnnotatedElement element, Class<A> annotation) {
|
||||
return element.getAnnotation(annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the supplied class.
|
||||
* <p>Meta-annotations will be searched if the annotation is not directly present on
|
||||
* the supplied element.
|
||||
* <p><strong>Note</strong>: this method searches for annotations at class & superClass(es)!
|
||||
* Simple has with no meta-annotations or platform filtering.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <A extends Annotation> A findAnnotationRecursive(Class<?> clazz, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
public static <A extends Annotation> boolean has(AnnotatedElement element, Class<A> annotation) {
|
||||
return get(element, annotation) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* On class get the annotation - includes inheritance.
|
||||
*/
|
||||
public static <A extends Annotation> A typeGet(Class<?> clazz, Class<A> annotationType) {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
// check if directly present, if not, start search for meta-annotations.
|
||||
Annotation[] anns = clazz.getAnnotations();
|
||||
if (anns.length != 0) {
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
}
|
||||
}
|
||||
|
||||
A ann = findAnnotation(anns, annotationType, new HashSet<>());
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
final A val = clazz.getAnnotation(annotationType);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
// no meta-annotation present at this class - traverse to superclass
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first annotation of a type for this platform. (if annotation is platform specific, otherwise first
|
||||
* found annotation is returned)
|
||||
* On class get all the annotations - includes inheritance.
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Platform platform) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
public static <A extends Annotation> Set<A> typeGetAll(Class<?> clazz, Class<A> annotationType) {
|
||||
Set<A> result = new LinkedHashSet<>();
|
||||
typeGetAllCollect(clazz, annotationType, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> void typeGetAllCollect(Class<?> clazz, Class<A> annotationType, Set<A> result) {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
final A val = clazz.getAnnotation(annotationType);
|
||||
if (val != null) {
|
||||
result.add(val);
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
Set<A> anns = findAnnotations(annotatedElement, annotationType);
|
||||
return getPlatformMatchingAnnotation(anns, platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all annotations recusively for a class and its superclasses or interfaces.
|
||||
* On class simple check for annotation - includes inheritance.
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findAnnotationsRecursive(Class<?> clazz, Class<A> annotationType) {
|
||||
Objects.requireNonNull(annotationType);
|
||||
Set<A> ret = new LinkedHashSet<>();
|
||||
public static <A extends Annotation> boolean typeHas(Class<?> clazz, Class<A> annotation) {
|
||||
return typeGet(clazz, annotation) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the annotations for the filter searching meta-annotations.
|
||||
*/
|
||||
public static Set<Annotation> metaFindAllFor(AnnotatedElement element, Set<Class<?>> filter) {
|
||||
Set<Annotation> visited = new HashSet<>();
|
||||
Set<Class<?>> visitedInterfaces = new HashSet<>();
|
||||
while (clazz != null && !clazz.getName().startsWith("java.lang.")) {
|
||||
findMetaAnnotationsRecursive(clazz, annotationType, ret, visited, visitedInterfaces);
|
||||
clazz = clazz.getSuperclass();
|
||||
Set<Annotation> result = new LinkedHashSet<>();
|
||||
for (Annotation ann : element.getAnnotations()) {
|
||||
metaAdd(ann, filter, visited, result);
|
||||
}
|
||||
return ret;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the interfaces for annotations.
|
||||
*/
|
||||
private static <A extends Annotation> void findMetaAnnotationsRecursive(Class<?> clazz,
|
||||
Class<A> annotationType, Set<A> ret,
|
||||
Set<Annotation> visited, Set<Class<?>> visitedInterfaces) {
|
||||
findMetaAnnotations(clazz, annotationType, ret, visited);
|
||||
for (Class<?> iface : clazz.getInterfaces()) {
|
||||
if (!iface.getName().startsWith("java.lang.") && visitedInterfaces.add(iface)) {
|
||||
findMetaAnnotationsRecursive(iface, annotationType, ret, visited, visitedInterfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> A findAnnotation(Annotation[] anns, Class<A> annotationType, Set<Annotation> visited) {
|
||||
|
||||
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
Annotation[] metaAnns = ann.annotationType().getAnnotations();
|
||||
for (Annotation metaAnn : metaAnns) {
|
||||
if (metaAnn.annotationType() == annotationType) {
|
||||
return (A) metaAnn;
|
||||
}
|
||||
}
|
||||
if (metaAnns.length > 0) {
|
||||
A annotation = findAnnotation(metaAnns, annotationType, visited);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all {@link Annotation}s of {@code annotationType} on the supplied {@link AnnotatedElement}.
|
||||
* <p>
|
||||
* Meta-annotations will be searched if the annotation is not <em>directly present</em> on the supplied element.
|
||||
* <p>
|
||||
* <strong>Warning</strong>: this method operates generically on annotated elements. In other words, this method
|
||||
* does not execute specialized search algorithms for classes or methods. It only traverses through Annotations!
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findAnnotations(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
Set<A> ret = new LinkedHashSet<>();
|
||||
findMetaAnnotations(annotatedElement, annotationType, ret, new HashSet<>());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> void findMetaAnnotations(AnnotatedElement annotatedElement, Class<A> annotationType, Set<A> ret, Set<Annotation> visited) {
|
||||
|
||||
Annotation[] anns = annotatedElement.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
ret.add((A) ann);
|
||||
} else {
|
||||
Method repeatableValueMethod = getRepeatableValueMethod(ann, annotationType);
|
||||
if (repeatableValueMethod != null) {
|
||||
try {
|
||||
A[] repeatedAnns = (A[]) repeatableValueMethod.invoke(ann);
|
||||
for (Annotation repeatedAnn : repeatedAnns) {
|
||||
ret.add((A) repeatedAnn);
|
||||
findMetaAnnotations(repeatedAnn.annotationType(), annotationType, ret, visited);
|
||||
}
|
||||
} catch (Exception e) { // catch all exceptions (thrown by invoke)
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
findMetaAnnotations(ann.annotationType(), annotationType, ret, visited);
|
||||
}
|
||||
private static void metaAdd(Annotation ann, Set<Class<?>> filter, Set<Annotation> visited, Set<Annotation> result) {
|
||||
if (notJavaLang(ann) && visited.add(ann)) {
|
||||
if (filter.contains(ann.annotationType())) {
|
||||
result.add(ann);
|
||||
} else {
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
metaAdd(metaAnn, filter, visited, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// caches for getRepeatableValueMethod
|
||||
private static Method getNullMethod() {
|
||||
try {
|
||||
return AnnotationUtil.class.getDeclaredMethod("getNullMethod");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Annotation, Method> valueMethods = new ConcurrentHashMap<>();
|
||||
// only a non-null-marker the valueMethods - Cache
|
||||
private static final Method nullMethod = getNullMethod();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the <code>value()</code> method for a possible containerAnnotation.
|
||||
* Method is retuned only, if its signature is <code>array of containingType</code>.
|
||||
*/
|
||||
private static <A extends Annotation> Method getRepeatableValueMethod(
|
||||
Annotation containerAnnotation, Class<A> containingType) {
|
||||
|
||||
Method method = valueMethods.get(containerAnnotation);
|
||||
if (method == null) {
|
||||
try {
|
||||
method = containerAnnotation.annotationType().getMethod("value");
|
||||
} catch (NoSuchMethodException e) {
|
||||
method = nullMethod;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Method prev = valueMethods.putIfAbsent(containerAnnotation, method);
|
||||
method = prev == null ? method : prev;
|
||||
}
|
||||
if (method != nullMethod) {
|
||||
Class<?> retType = method.getReturnType();
|
||||
if (retType.isArray() && retType.getComponentType() == containingType) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a suitable annotation from <code>Set<T> anns</code> for this platform.
|
||||
* To distinguish between platforms, annotation type <code>T</code> must define
|
||||
* a method withthis signature:
|
||||
* <p>
|
||||
* <code>Class<? extends DatabasePlatform>[] platforms() default {};</code>
|
||||
* </p>
|
||||
* The finding rules are:
|
||||
* <ol>
|
||||
* <li>Check if T has method "platforms" if not, return <code>ann[0]</code></code>
|
||||
* <li>find the annotation that is defined for <code>databasePlatform</code></li>
|
||||
* <li>otherwise return the annotation for default platform (platforms = {})</li>
|
||||
* <li>return null
|
||||
* </ol>
|
||||
* (This mechanism is currently used by {@link Where} and {@link Formula})
|
||||
*/
|
||||
public static <T extends Annotation> T getPlatformMatchingAnnotation(Set<T> anns, Platform matchPlatform) {
|
||||
if (anns.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Method getPlatformsMethod = null;
|
||||
T fallback = null;
|
||||
for (T ann : anns) {
|
||||
try {
|
||||
if (getPlatformsMethod == null) {
|
||||
getPlatformsMethod = ann.getClass().getMethod("platforms");
|
||||
}
|
||||
if (!Platform[].class.isAssignableFrom(getPlatformsMethod.getReturnType())) {
|
||||
return ann;
|
||||
}
|
||||
Platform[] platforms = (Platform[]) getPlatformsMethod.invoke(ann);
|
||||
if (platforms.length == 0) {
|
||||
fallback = ann;
|
||||
} else {
|
||||
for (Platform platform : platforms) {
|
||||
if (matchPlatform == platform) {
|
||||
return ann;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
return ann; // not platform specific - return first one
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.CountMetric;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
@@ -22,11 +21,11 @@ public class ExtraMetrics {
|
||||
*/
|
||||
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");
|
||||
this.bindCapture = factory.createTimedMetric("ebean.queryplan.bindcapture");
|
||||
this.planCollect = factory.createTimedMetric("ebean.queryplan.collect");
|
||||
this.loadOneL2 = factory.createCountMetric("loadone.l2");
|
||||
this.loadOneRef = factory.createCountMetric("loadone.ref");
|
||||
this.loadOneNoLoader = factory.createCountMetric("loadone.noloader");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
public class PlatformMatch {
|
||||
|
||||
/**
|
||||
* Return true if the script platforms is a match/supported for the given platform.
|
||||
*
|
||||
* @param platform The database platform we are generating/running DDL for
|
||||
* @param platforms The platforms (comma delimited) this script should run for
|
||||
*/
|
||||
public static boolean matchPlatform(Platform platform, String platforms) {
|
||||
if (platforms == null || platforms.trim().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// match on base platform name and platform name
|
||||
for (String name : StringHelper.splitNames(platforms)) {
|
||||
if (name.equalsIgnoreCase(platform.base().name()) || name.equalsIgnoreCase(platform.name())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -71,13 +71,13 @@ public class ScopeTrans {
|
||||
restoreBatchOnCascade = transaction.isBatchOnCascade();
|
||||
restoreBatchSize = transaction.getBatchSize();
|
||||
restoreBatchGeneratedKeys = transaction.getBatchGetGeneratedKeys();
|
||||
restoreBatchFlushOnQuery = transaction.isBatchFlushOnQuery();
|
||||
restoreBatchFlushOnQuery = transaction.isFlushOnQuery();
|
||||
}
|
||||
if (txScope.isBatchSet()) {
|
||||
transaction.setBatchMode(txScope.isBatchMode());
|
||||
}
|
||||
if (!txScope.isFlushOnQuery()) {
|
||||
transaction.setBatchFlushOnQuery(false);
|
||||
transaction.setFlushOnQuery(false);
|
||||
}
|
||||
if (txScope.isBatchOnCascadeSet()) {
|
||||
transaction.setBatchOnCascade(txScope.isBatchOnCascade());
|
||||
@@ -86,7 +86,7 @@ public class ScopeTrans {
|
||||
transaction.setBatchSize(txScope.getBatchSize());
|
||||
}
|
||||
if (txScope.isSkipGeneratedKeys()) {
|
||||
transaction.setBatchGetGeneratedKeys(false);
|
||||
transaction.setGetGeneratedKeys(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ public class ScopeTrans {
|
||||
transaction.commit();
|
||||
} else {
|
||||
nestedCommit = true;
|
||||
transaction.setBatchFlushOnQuery(restoreBatchFlushOnQuery);
|
||||
transaction.setFlushOnQuery(restoreBatchFlushOnQuery);
|
||||
if (restoreBatch != null) {
|
||||
transaction.setBatchMode(restoreBatch);
|
||||
}
|
||||
@@ -147,7 +147,7 @@ public class ScopeTrans {
|
||||
transaction.setBatchSize(restoreBatchSize);
|
||||
}
|
||||
if (restoreBatchGeneratedKeys != null) {
|
||||
transaction.setBatchGetGeneratedKeys(restoreBatchGeneratedKeys);
|
||||
transaction.setGetGeneratedKeys(restoreBatchGeneratedKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,11 @@ public interface SpiExpressionList<T> extends ExpressionList<T>, SpiExpression {
|
||||
* Write the top level where expressions taking into account possible extra idEquals expression.
|
||||
*/
|
||||
void writeDocQuery(DocQueryContext context, SpiExpression idEquals) throws IOException;
|
||||
|
||||
/**
|
||||
* Apply firstRow maxRows limits on the filterMany query.
|
||||
*/
|
||||
default void applyRowLimits(SpiQuery<?> query) {
|
||||
// do nothing by default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,8 +269,8 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) {
|
||||
transaction.setBatchGetGeneratedKeys(getGeneratedKeys);
|
||||
public void setGetGeneratedKeys(boolean getGeneratedKeys) {
|
||||
transaction.setGetGeneratedKeys(getGeneratedKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,18 +279,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBatchFlushOnMixed(boolean batchFlushOnMixed) {
|
||||
transaction.setBatchFlushOnMixed(batchFlushOnMixed);
|
||||
public void setFlushOnMixed(boolean batchFlushOnMixed) {
|
||||
transaction.setFlushOnMixed(batchFlushOnMixed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBatchFlushOnQuery(boolean batchFlushOnQuery) {
|
||||
transaction.setBatchFlushOnQuery(batchFlushOnQuery);
|
||||
public void setFlushOnQuery(boolean batchFlushOnQuery) {
|
||||
transaction.setFlushOnQuery(batchFlushOnQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBatchFlushOnQuery() {
|
||||
return transaction.isBatchFlushOnQuery();
|
||||
public boolean isFlushOnQuery() {
|
||||
return transaction.isFlushOnQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.ebeaninternal.dbmigration;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
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;
|
||||
@@ -48,6 +48,7 @@ public class DdlGenerator {
|
||||
private final boolean ddlAutoCommit;
|
||||
private final String dbSchema;
|
||||
private final ScriptTransform scriptTransform;
|
||||
private final Platform platform;
|
||||
private final String platformName;
|
||||
|
||||
private CurrentModel currentModel;
|
||||
@@ -63,7 +64,8 @@ public class DdlGenerator {
|
||||
this.createOnly = serverConfig.isDdlCreateOnly();
|
||||
this.dbSchema = serverConfig.getDbSchema();
|
||||
final DatabasePlatform databasePlatform = server.getDatabasePlatform();
|
||||
this.platformName = databasePlatform.getPlatform().base().name();
|
||||
this.platform = databasePlatform.getPlatform();
|
||||
this.platformName = platform.base().name();
|
||||
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
|
||||
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
|
||||
this.runDdl = false;
|
||||
@@ -188,7 +190,7 @@ public class DdlGenerator {
|
||||
protected void runDropSql(Connection connection) throws IOException {
|
||||
if (!createOnly) {
|
||||
if (extraDdl && jaxbPresent) {
|
||||
String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName(), true);
|
||||
String extraApply = ExtraDdlXmlReader.buildExtra(platform, true);
|
||||
if (extraApply != null) {
|
||||
runScript(connection, false, extraApply, "extra-ddl");
|
||||
}
|
||||
@@ -209,13 +211,13 @@ public class DdlGenerator {
|
||||
|
||||
if (extraDdl && jaxbPresent) {
|
||||
if (currentModel().isTablePartitioning()) {
|
||||
String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(server.getDatabasePlatform().getName());
|
||||
String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(platform);
|
||||
if (extraPartitioning != null && !extraPartitioning.isEmpty()) {
|
||||
runScript(connection, false, extraPartitioning, "builtin-partitioning-ddl");
|
||||
}
|
||||
}
|
||||
|
||||
String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName(), false);
|
||||
String extraApply = ExtraDdlXmlReader.buildExtra(platform, false);
|
||||
if (extraApply != null) {
|
||||
runScript(connection, false, extraApply, "extra-ddl");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
|
||||
import io.ebean.config.dbplatform.mysql.MySql55Platform;
|
||||
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
|
||||
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
|
||||
import io.ebean.config.dbplatform.oracle.Oracle11Platform;
|
||||
import io.ebean.config.dbplatform.oracle.OraclePlatform;
|
||||
import io.ebean.config.dbplatform.postgres.Postgres9Platform;
|
||||
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
|
||||
import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
|
||||
import io.ebean.config.dbplatform.sqlite.SQLitePlatform;
|
||||
@@ -49,6 +51,8 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
|
||||
/**
|
||||
* Generates DB Migration xml and sql scripts.
|
||||
* <p>
|
||||
@@ -406,7 +410,7 @@ public class DefaultDbMigration implements DbMigration {
|
||||
if (extraDdl != null) {
|
||||
List<DdlScript> ddlScript = extraDdl.getDdlScript();
|
||||
for (DdlScript script : ddlScript) {
|
||||
if (!script.isDrop() && ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
|
||||
if (!script.isDrop() && matchPlatform(dbPlatform.getPlatform(), script.getPlatforms())) {
|
||||
writeExtraDdl(migrationDir, script);
|
||||
}
|
||||
}
|
||||
@@ -812,6 +816,8 @@ public class DefaultDbMigration implements DbMigration {
|
||||
return new H2Platform();
|
||||
case HSQLDB:
|
||||
return new HsqldbPlatform();
|
||||
case POSTGRES9:
|
||||
return new Postgres9Platform();
|
||||
case POSTGRES:
|
||||
return new PostgresPlatform();
|
||||
case MYSQL55:
|
||||
@@ -820,6 +826,8 @@ public class DefaultDbMigration implements DbMigration {
|
||||
return new MySqlPlatform();
|
||||
case ORACLE:
|
||||
return new OraclePlatform();
|
||||
case ORACLE11:
|
||||
return new Oracle11Platform();
|
||||
case SQLANYWHERE:
|
||||
return new SqlAnywherePlatform();
|
||||
case SQLSERVER16:
|
||||
|
||||
+3
-3
@@ -44,8 +44,8 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
String columnName = alter.getColumnName();
|
||||
String currentType = alter.getCurrentType();
|
||||
String type = alter.getType() != null ? alter.getType() : currentType;
|
||||
type = convert(type, false);
|
||||
currentType = convert(currentType, false);
|
||||
type = convert(type);
|
||||
currentType = convert(currentType);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
String defaultValue = DdlHelp.isDropDefault(alter.getDefaultValue()) ? "null"
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
|
||||
protected String convertArrayType(String logicalArrayType) {
|
||||
Matcher matcher = ARRAY_PATTERN.matcher(logicalArrayType);
|
||||
if (matcher.matches()) {
|
||||
return convert(matcher.group(1), false) + " array" + (matcher.group(2) == null ? "" : matcher.group(2));
|
||||
return convert(matcher.group(1)) + " array" + (matcher.group(2) == null ? "" : matcher.group(2));
|
||||
} else {
|
||||
return fallbackArrayType;
|
||||
}
|
||||
|
||||
+31
-45
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.ServerConfig;
|
||||
@@ -28,6 +29,8 @@ import io.ebeaninternal.dbmigration.migration.DropTable;
|
||||
import io.ebeaninternal.dbmigration.migration.ForeignKey;
|
||||
import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import io.ebeaninternal.dbmigration.model.MTableIdentity;
|
||||
import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
@@ -37,6 +40,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
|
||||
|
||||
/**
|
||||
@@ -168,18 +172,14 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
private List<String> getScriptsForPlatform(List<DdlScript> scripts) {
|
||||
String searchPlatform = platformDdl.getPlatform().getName();
|
||||
List<String> ret = Collections.emptyList();
|
||||
Platform searchPlatform = platformDdl.getPlatform().getPlatform();
|
||||
for (DdlScript script : scripts) {
|
||||
if (script.getPlatforms() == null || script.getPlatforms().isEmpty()) {
|
||||
ret = script.getDdl();
|
||||
} else for (String platform : StringHelper.splitNames(script.getPlatforms())) {
|
||||
if (platform.equals(searchPlatform)) {
|
||||
return script.getDdl();
|
||||
}
|
||||
if (matchPlatform(searchPlatform, script.getPlatforms())) {
|
||||
// just returns the first match (rather than appends them)
|
||||
return script.getDdl();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,21 +248,22 @@ public class BaseTableDdl implements TableDdl {
|
||||
List<Column> columns = createTable.getColumn();
|
||||
List<Column> pk = determinePrimaryKeyColumns(columns);
|
||||
|
||||
boolean singleColumnPrimaryKey = (pk.size() == 1);
|
||||
boolean useIdentity = false;
|
||||
boolean useSequence = false;
|
||||
|
||||
if (singleColumnPrimaryKey) {
|
||||
IdType useDbIdentityType = platformDdl.useIdentityType(createTable.getIdentityType());
|
||||
useIdentity = (IdType.IDENTITY == useDbIdentityType);
|
||||
useSequence = (IdType.SEQUENCE == useDbIdentityType);
|
||||
DdlIdentity identity = DdlIdentity.NONE;
|
||||
if ((pk.size() == 1)) {
|
||||
final IdentityMode identityMode = MTableIdentity.fromCreateTable(createTable);
|
||||
IdType idType = platformDdl.useIdentityType(identityMode.getIdType());
|
||||
String sequenceName = identityMode.getSequenceName();
|
||||
if (IdType.SEQUENCE == idType && (sequenceName == null || sequenceName.isEmpty())) {
|
||||
sequenceName = sequenceName(createTable, pk);
|
||||
}
|
||||
identity = new DdlIdentity(idType, identityMode, sequenceName);
|
||||
}
|
||||
|
||||
String partitionMode = createTable.getPartitionMode();
|
||||
|
||||
DdlBuffer apply = writer.apply();
|
||||
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(tableName).append(" (");
|
||||
writeTableColumns(apply, columns, useIdentity);
|
||||
writeTableColumns(apply, columns, identity);
|
||||
writeUniqueConstraints(apply, createTable);
|
||||
writeCompoundUniqueConstraints(apply, createTable);
|
||||
if (!pk.isEmpty()) {
|
||||
@@ -297,9 +298,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
// we drop the related sequence (if sequences are used)
|
||||
dropTable(writer.dropAll(), tableName);
|
||||
|
||||
if (useSequence) {
|
||||
String pkCol = pk.get(0).getName();
|
||||
writeSequence(writer, createTable, pkCol);
|
||||
if (identity.useSequence()) {
|
||||
writeSequence(writer, identity);
|
||||
}
|
||||
|
||||
// add blank line for a bit of whitespace between tables
|
||||
@@ -311,6 +311,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
private String sequenceName(CreateTable createTable, List<Column> pk) {
|
||||
return namingConvention.getSequenceName(createTable.getName(), pk.get(0).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add table and column comments (separate from the create table statement).
|
||||
*/
|
||||
@@ -350,8 +354,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTableColumns(DdlBuffer apply, List<Column> columns, boolean useIdentity) throws IOException {
|
||||
platformDdl.writeTableColumns(apply, columns, useIdentity);
|
||||
private void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) throws IOException {
|
||||
platformDdl.writeTableColumns(apply, columns, identity);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,18 +384,9 @@ 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());
|
||||
int allocate = toInt(createTable.getSequenceAllocate());
|
||||
|
||||
String seqName = explicitSequenceName;
|
||||
if (seqName == null) {
|
||||
seqName = namingConvention.getSequenceName(createTable.getName(), pk);
|
||||
}
|
||||
|
||||
String createSeq = platformDdl.createSequence(seqName, initial, allocate);
|
||||
protected void writeSequence(DdlWrite writer, DdlIdentity identity) throws IOException {
|
||||
String seqName = identity.getSequenceName();
|
||||
String createSeq = platformDdl.createSequence(seqName, identity);
|
||||
if (hasValue(createSeq)) {
|
||||
writer.apply().append(createSeq).newLine();
|
||||
writer.dropAll().appendStatement(platformDdl.dropSequence(seqName));
|
||||
@@ -511,16 +506,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
|
||||
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;
|
||||
return matchPlatform(platformDdl.getPlatform().getPlatform(), platforms);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +25,7 @@ public class CockroachDdl extends PlatformDdl {
|
||||
* Map bigint, integer and smallint all into serial.
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn) {
|
||||
|
||||
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "serial";
|
||||
}
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
*/
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type) throws IOException {
|
||||
|
||||
String platformType = platformDdl.convert(type, false);
|
||||
String platformType = platformDdl.convert(type);
|
||||
buffer.append(" ");
|
||||
buffer.append(platformDdl.lowerColumnName(columnName), 29);
|
||||
buffer.append(platformType);
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.annotation.IdentityGenerated;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
|
||||
public class DdlIdentity {
|
||||
|
||||
public static final DdlIdentity NONE = new DdlIdentity();
|
||||
|
||||
private final IdType idType;
|
||||
private final IdentityMode identityMode;
|
||||
private final String sequenceName;
|
||||
|
||||
public DdlIdentity(IdType idType, IdentityMode identityMode, String sequenceName) {
|
||||
this.idType = idType;
|
||||
this.identityMode = identityMode;
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
private DdlIdentity() {
|
||||
this.idType = null;
|
||||
this.identityMode = null;
|
||||
this.sequenceName = null;
|
||||
}
|
||||
|
||||
public boolean useSequence() {
|
||||
return idType == IdType.SEQUENCE;
|
||||
}
|
||||
|
||||
public boolean useIdentity() {
|
||||
return idType == IdType.IDENTITY;
|
||||
}
|
||||
|
||||
public String getSequenceName() {
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
private String generatedBy() {
|
||||
return isAlways() ? "always" : "by default";
|
||||
}
|
||||
|
||||
private boolean isAlways() {
|
||||
return IdentityGenerated.ALWAYS == identityMode.getGenerated();
|
||||
}
|
||||
|
||||
public String optionGenerated() {
|
||||
return " generated " + generatedBy() +" as identity";
|
||||
}
|
||||
|
||||
public String identityOptions(String startWith, String incrementBy, String cache) {
|
||||
return options(true, startWith, incrementBy, cache);
|
||||
}
|
||||
|
||||
public String sequenceOptions(String startWith, String incrementBy, String cache) {
|
||||
return options(false, startWith, incrementBy, cache);
|
||||
}
|
||||
|
||||
private String options(boolean brackets, String startWith, String incrementBy, String cache) {
|
||||
if (!identityMode.hasOptions()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(40);
|
||||
if (brackets) {
|
||||
sb.append(" (");
|
||||
} else {
|
||||
sb.append(" ");
|
||||
}
|
||||
optionFor(sb, startWith, identityMode.getStart());
|
||||
optionFor(sb, incrementBy, identityMode.getIncrement());
|
||||
optionFor(sb, cache, identityMode.getCache());
|
||||
if (brackets) {
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void optionFor(StringBuilder sb, String prefix, int val) {
|
||||
if (val > 0 && prefix != null) {
|
||||
if (sb.length() > 2) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(prefix).append(" ").append(val);
|
||||
}
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return identityMode.getStart();
|
||||
}
|
||||
|
||||
public int getIncrement() {
|
||||
return identityMode.getIncrement();
|
||||
}
|
||||
|
||||
public int getCache() {
|
||||
return identityMode.getCache();
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,14 @@ public class H2Ddl extends PlatformDdl {
|
||||
this.historyDdl = new H2HistoryDdl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify and return the column definition for autoincrement or identity definition.
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
|
||||
return asIdentityStandardOptions(columnDefn, identity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertArrayType(String logicalArrayType) {
|
||||
return "array";
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue,
|
||||
boolean isNotNull, String generated) throws IOException {
|
||||
|
||||
String platformType = platformDdl.convert(type, false);
|
||||
String platformType = platformDdl.convert(type);
|
||||
buffer.append(" ").append(platformDdl.lowerColumnName(columnName));
|
||||
buffer.append(" ").append(platformType);
|
||||
if (defaultValue != null) {
|
||||
|
||||
@@ -107,7 +107,7 @@ public class MySqlDdl extends PlatformDdl {
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type, false);
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
|
||||
@@ -115,8 +115,8 @@ public class MySqlDdl extends PlatformDdl {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, Column column, boolean useIdentity) throws IOException {
|
||||
super.writeColumnDefinition(buffer, column, useIdentity);
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) throws IOException {
|
||||
super.writeColumnDefinition(buffer, column, identity);
|
||||
String comment = column.getComment();
|
||||
if (!StringHelper.isNull(comment)) {
|
||||
// in mysql 5.5 column comment save in information_schema.COLUMNS.COLUMN_COMMENT(VARCHAR 1024)
|
||||
|
||||
@@ -19,7 +19,7 @@ public class Oracle10Ddl extends PlatformDdl {
|
||||
this.columnSetNotnull = "not null";
|
||||
this.columnSetNull = "null";
|
||||
this.columnSetDefault = "default";
|
||||
this.identitySuffix = " generated always as identity";
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+34
-39
@@ -19,10 +19,7 @@ import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.AlterColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.Column;
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.IdentityType;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -33,8 +30,6 @@ import java.util.List;
|
||||
*/
|
||||
public class PlatformDdl {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlatformDdl.class);
|
||||
|
||||
protected final DatabasePlatform platform;
|
||||
|
||||
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
|
||||
@@ -70,6 +65,12 @@ public class PlatformDdl {
|
||||
protected String foreignKeyOnUpdate = "on update";
|
||||
|
||||
protected String identitySuffix = " auto_increment";
|
||||
protected String identityStartWith = "start with";
|
||||
protected String identityIncrementBy = "increment by";
|
||||
protected String identityCache = "cache";
|
||||
protected String sequenceStartWith = "start with";
|
||||
protected String sequenceIncrementBy = "increment by";
|
||||
protected String sequenceCache = "cache";
|
||||
|
||||
protected String alterTableIfExists = "";
|
||||
|
||||
@@ -156,8 +157,7 @@ public class PlatformDdl {
|
||||
* Return the identity type to use given the support in the underlying database
|
||||
* platform for sequences and identity/autoincrement.
|
||||
*/
|
||||
public IdType useIdentityType(IdentityType modelIdentity) {
|
||||
|
||||
public IdType useIdentityType(IdType modelIdentity) {
|
||||
if (modelIdentity == null) {
|
||||
// use the default
|
||||
return dbIdentity.getIdType();
|
||||
@@ -169,8 +169,7 @@ public class PlatformDdl {
|
||||
* Determine the id type to use based on requested identityType and
|
||||
* the support for that in the database platform.
|
||||
*/
|
||||
private IdType identityType(IdentityType modelIdentity, IdType platformIdType, boolean supportsSequence, boolean supportsIdentity) {
|
||||
|
||||
private IdType identityType(IdType modelIdentity, IdType platformIdType, boolean supportsSequence, boolean supportsIdentity) {
|
||||
switch (modelIdentity) {
|
||||
case GENERATOR:
|
||||
return IdType.GENERATOR;
|
||||
@@ -188,10 +187,21 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Modify and return the column definition for autoincrement or identity definition.
|
||||
*/
|
||||
public String asIdentityColumn(String columnDefn) {
|
||||
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
|
||||
return columnDefn + identitySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQl2003 standard identity definition.
|
||||
*/
|
||||
protected String asIdentityStandardOptions(String columnDefn, DdlIdentity identity) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(columnDefn.length() + 60);
|
||||
sb.append(columnDefn).append(identity.optionGenerated());
|
||||
sb.append(identity.identityOptions(identityStartWith, identityIncrementBy, identityCache));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the table and column comments are included inline.
|
||||
*/
|
||||
@@ -224,13 +234,13 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Write all the table columns converting to platform types as necessary.
|
||||
*/
|
||||
public void writeTableColumns(DdlBuffer apply, List<Column> columns, boolean useIdentity) throws IOException {
|
||||
public void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) throws IOException {
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (i > 0) {
|
||||
apply.append(",");
|
||||
}
|
||||
apply.newLine();
|
||||
writeColumnDefinition(apply, columns.get(i), useIdentity);
|
||||
writeColumnDefinition(apply, columns.get(i), identity);
|
||||
}
|
||||
|
||||
for (Column column : columns) {
|
||||
@@ -248,14 +258,16 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Write the column definition to the create table statement.
|
||||
*/
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, Column column, boolean useIdentity) throws IOException {
|
||||
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) throws IOException {
|
||||
|
||||
boolean identityColumn = useIdentity && isTrue(column.isPrimaryKey());
|
||||
String platformType = convert(column.getType(), identityColumn);
|
||||
String columnDefn = convert(column.getType());
|
||||
if (identity.useIdentity() && isTrue(column.isPrimaryKey())) {
|
||||
columnDefn = asIdentityColumn(columnDefn, identity);
|
||||
}
|
||||
|
||||
buffer.append(" ");
|
||||
buffer.append(lowerColumnName(column.getName()), 29);
|
||||
buffer.append(platformType);
|
||||
buffer.append(columnDefn);
|
||||
if (!Boolean.TRUE.equals(column.isPrimaryKey())) {
|
||||
String defaultValue = convertDefaultValue(column.getDefaultValue());
|
||||
if (defaultValue != null) {
|
||||
@@ -301,15 +313,14 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Convert the standard type to the platform specific type.
|
||||
*/
|
||||
public String convert(String type, boolean identity) {
|
||||
public String convert(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
if (type.contains("[]")) {
|
||||
return convertArrayType(type);
|
||||
}
|
||||
String platformType = typeConverter.convert(type);
|
||||
return identity ? asIdentityColumn(platformType) : platformType;
|
||||
return typeConverter.convert(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,16 +365,10 @@ public class PlatformDdl {
|
||||
/**
|
||||
* Generate and return the create sequence DDL.
|
||||
*/
|
||||
public String createSequence(String sequenceName, int initialValue, int allocationSize) {
|
||||
|
||||
public String createSequence(String sequenceName, DdlIdentity identity) {
|
||||
StringBuilder sb = new StringBuilder("create sequence ");
|
||||
sb.append(sequenceName);
|
||||
if (initialValue > 1) {
|
||||
sb.append(" start with ").append(initialValue);
|
||||
}
|
||||
if (allocationSize > 1) {
|
||||
sb.append(" increment by ").append(allocationSize);
|
||||
}
|
||||
sb.append(identity.sequenceOptions(sequenceStartWith, sequenceIncrementBy, sequenceCache));
|
||||
sb.append(";");
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -515,13 +520,12 @@ public class PlatformDdl {
|
||||
|
||||
public void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, String defaultValue) throws IOException {
|
||||
|
||||
String convertedType = convert(column.getType(), false);
|
||||
String convertedType = convert(column.getType());
|
||||
|
||||
buffer.append("alter table ").append(tableName)
|
||||
.append(" ").append(addColumn).append(" ").append(column.getName())
|
||||
.append(" ").append(convertedType);
|
||||
|
||||
|
||||
// Add default value also to history table if it is not excluded
|
||||
if (defaultValue != null) {
|
||||
if (!onHistoryTable || !isTrue(column.isHistoryExclude())) {
|
||||
@@ -572,8 +576,7 @@ public class PlatformDdl {
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnType(String tableName, String columnName, String type) {
|
||||
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type, false) + alterColumnSuffix;
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type) + alterColumnSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -583,7 +586,6 @@ public class PlatformDdl {
|
||||
* </p>
|
||||
*/
|
||||
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
|
||||
|
||||
String suffix = notnull ? columnSetNotnull : columnSetNull;
|
||||
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix;
|
||||
}
|
||||
@@ -592,7 +594,6 @@ public class PlatformDdl {
|
||||
* Alter table adding the check constraint.
|
||||
*/
|
||||
public String alterTableAddCheckConstraint(String tableName, String checkConstraintName, String checkConstraint) {
|
||||
|
||||
return "alter table " + tableName + " " + addConstraint + " " + maxConstraintName(checkConstraintName) + " " + checkConstraint;
|
||||
}
|
||||
|
||||
@@ -627,12 +628,6 @@ public class PlatformDdl {
|
||||
buffer.append(")");
|
||||
}
|
||||
|
||||
protected void appendWithSpace(String content, StringBuilder buffer) {
|
||||
if (hasValue(content)) {
|
||||
buffer.append(" ").append(content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the table to lower case.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
public class Postgres9Ddl extends PostgresDdl {
|
||||
|
||||
public Postgres9Ddl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map bigint, integer and smallint into their equivalent serial types.
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "bigserial";
|
||||
}
|
||||
if ("integer".equalsIgnoreCase(columnDefn)) {
|
||||
return "serial";
|
||||
}
|
||||
if ("smallint".equalsIgnoreCase(columnDefn)) {
|
||||
return "smallserial";
|
||||
}
|
||||
return columnDefn;
|
||||
}
|
||||
}
|
||||
@@ -37,23 +37,6 @@ public class PostgresDdl extends PlatformDdl {
|
||||
return NativeDbArray.logicalToNative(logicalArrayType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map bigint, integer and smallint into their equivalent serial types.
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn) {
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "bigserial";
|
||||
}
|
||||
if ("integer".equalsIgnoreCase(columnDefn)) {
|
||||
return "serial";
|
||||
}
|
||||
if ("smallint".equalsIgnoreCase(columnDefn)) {
|
||||
return "smallserial";
|
||||
}
|
||||
return columnDefn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException {
|
||||
apply.append(" partition by range (").append(partitionColumn).append(")");
|
||||
@@ -63,4 +46,12 @@ public class PostgresDdl extends PlatformDdl {
|
||||
public String dropIndex(String indexName, String tableName, boolean concurrent) {
|
||||
return (concurrent ? dropIndexConcurrentlyIfExists : dropIndexIfExists) + maxConstraintName(indexName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify and return the column definition for autoincrement or identity definition.
|
||||
*/
|
||||
@Override
|
||||
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
|
||||
return asIdentityStandardOptions(columnDefn, identity);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-11
@@ -114,18 +114,22 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
* Generate and return the create sequence DDL.
|
||||
*/
|
||||
@Override
|
||||
public String createSequence(String sequenceName, int initialValue, int allocationSize) {
|
||||
|
||||
StringBuilder sb = new StringBuilder("create sequence ");
|
||||
sb.append(sequenceName);
|
||||
sb.append(" as bigint ");
|
||||
if (initialValue > 1) {
|
||||
sb.append(" start with ").append(initialValue);
|
||||
public String createSequence(String sequenceName, DdlIdentity identity) {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("create sequence ").append(sequenceName).append(" as bigint");
|
||||
final int start = identity.getStart();
|
||||
if (start > 1) {
|
||||
sb.append(" start with ").append(start);
|
||||
} else {
|
||||
sb.append(" start with 1 ");
|
||||
sb.append(" start with 1");
|
||||
}
|
||||
if (allocationSize > 1) {
|
||||
sb.append(" increment by ").append(allocationSize);
|
||||
final int increment = identity.getIncrement();
|
||||
if (increment > 1) {
|
||||
sb.append(" increment by ").append(increment);
|
||||
}
|
||||
final int cache = identity.getCache();
|
||||
if (cache > 1) {
|
||||
sb.append(" cache ").append(increment);
|
||||
}
|
||||
sb.append(";");
|
||||
return sb.toString();
|
||||
@@ -157,7 +161,7 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
String tableName = alter.getTableName();
|
||||
String columnName = alter.getColumnName();
|
||||
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
|
||||
type = convert(type, false);
|
||||
type = convert(type);
|
||||
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
|
||||
String notnullClause = notnull ? " not null" : "";
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class PlatformTypeConverter {
|
||||
} else {
|
||||
// scale - varchar(10)
|
||||
int scale = Integer.parseInt(columnDefinition.substring(open + 1, close));
|
||||
return dbType.renderType(scale, 0) + suffix;
|
||||
return dbType.renderType(scale, -1) + suffix;
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
@@ -33,6 +33,10 @@ import java.util.List;
|
||||
* <attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="draft" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="identityType" type="{http://ebean-orm.github.io/xml/ns/dbmigration}identityType" />
|
||||
* <attribute name="identityStart" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="identityIncrement" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="identityCache" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="identityGenerated" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="sequenceName" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="sequenceInitial" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
* <attribute name="sequenceAllocate" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
|
||||
@@ -68,6 +72,17 @@ public class CreateTable {
|
||||
protected Boolean draft;
|
||||
@XmlAttribute(name = "identityType")
|
||||
protected IdentityType identityType;
|
||||
@XmlAttribute(name = "identityStart")
|
||||
@XmlSchemaType(name = "positiveInteger")
|
||||
protected BigInteger identityStart;
|
||||
@XmlAttribute(name = "identityIncrement")
|
||||
@XmlSchemaType(name = "positiveInteger")
|
||||
protected BigInteger identityIncrement;
|
||||
@XmlAttribute(name = "identityCache")
|
||||
@XmlSchemaType(name = "positiveInteger")
|
||||
protected BigInteger identityCache;
|
||||
@XmlAttribute(name = "identityGenerated")
|
||||
protected String identityGenerated;
|
||||
@XmlAttribute(name = "sequenceName")
|
||||
protected String sequenceName;
|
||||
@XmlAttribute(name = "sequenceInitial")
|
||||
@@ -288,6 +303,86 @@ public class CreateTable {
|
||||
this.identityType = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the identityStart property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public BigInteger getIdentityStart() {
|
||||
return identityStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the identityStart property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public void setIdentityStart(BigInteger value) {
|
||||
this.identityStart = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the identityIncrement property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public BigInteger getIdentityIncrement() {
|
||||
return identityIncrement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the identityIncrement property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public void setIdentityIncrement(BigInteger value) {
|
||||
this.identityIncrement = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the identityCache property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public BigInteger getIdentityCache() {
|
||||
return identityCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the identityCache property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link BigInteger }
|
||||
*/
|
||||
public void setIdentityCache(BigInteger value) {
|
||||
this.identityCache = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the identityGenerated property.
|
||||
*
|
||||
* @return possible object is
|
||||
* {@link String }
|
||||
*/
|
||||
public String getIdentityGenerated() {
|
||||
return identityGenerated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the identityGenerated property.
|
||||
*
|
||||
* @param value allowed object is
|
||||
* {@link String }
|
||||
*/
|
||||
public void setIdentityGenerated(String value) {
|
||||
this.identityGenerated = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the sequenceName property.
|
||||
*
|
||||
|
||||
@@ -62,11 +62,7 @@ public class DdlScript {
|
||||
if (ddl == null) {
|
||||
ddl = new ArrayList<>();
|
||||
}
|
||||
return ddl;
|
||||
}
|
||||
|
||||
public void setDdl(List<String> ddl) {
|
||||
this.ddl = ddl;
|
||||
return this.ddl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,8 @@ import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
|
||||
/**
|
||||
* Reads EbeanServer bean descriptors to build the current model.
|
||||
*/
|
||||
@@ -146,7 +148,7 @@ public class CurrentModel {
|
||||
if (extraDdl != null) {
|
||||
List<DdlScript> ddlScript = extraDdl.getDdlScript();
|
||||
for (DdlScript script : ddlScript) {
|
||||
if (script.isInit() && ExtraDdlXmlReader.matchPlatform(server.getDatabasePlatform().getName(), script.getPlatforms())) {
|
||||
if (script.isInit() && matchPlatform(server.getDatabasePlatform().getPlatform(), script.getPlatforms())) {
|
||||
ddl.append(prefix).append(script.getName()).append('\n');
|
||||
ddl.append(script.getValue());
|
||||
}
|
||||
|
||||
@@ -295,14 +295,14 @@ public class MColumn {
|
||||
for (DbMigrationInfo info : dbMigrationInfos) {
|
||||
if (!info.getPreAdd().isEmpty()) {
|
||||
DdlScript script = new DdlScript();
|
||||
script.setDdl(info.getPreAdd());
|
||||
script.getDdl().addAll(info.getPreAdd());
|
||||
script.setPlatforms(info.joinPlatforms());
|
||||
c.getBefore().add(script);
|
||||
}
|
||||
|
||||
if (!info.getPostAdd().isEmpty()) {
|
||||
DdlScript script = new DdlScript();
|
||||
script.setDdl(info.getPostAdd());
|
||||
script.getDdl().addAll(info.getPostAdd());
|
||||
script.setPlatforms(info.joinPlatforms());
|
||||
c.getAfter().add(script);
|
||||
}
|
||||
@@ -341,14 +341,14 @@ public class MColumn {
|
||||
for (DbMigrationInfo info : dbMigrationInfos) {
|
||||
if (!info.getPreAlter().isEmpty()) {
|
||||
DdlScript script = new DdlScript();
|
||||
script.setDdl(info.getPreAlter());
|
||||
script.getDdl().addAll(info.getPreAlter());
|
||||
script.setPlatforms(info.joinPlatforms());
|
||||
alterColumn.getBefore().add(script);
|
||||
}
|
||||
|
||||
if (!info.getPostAlter().isEmpty()) {
|
||||
DdlScript script = new DdlScript();
|
||||
script.setDdl(info.getPostAlter());
|
||||
script.getDdl().addAll(info.getPostAlter());
|
||||
script.setPlatforms(info.joinPlatforms());
|
||||
alterColumn.getAfter().add(script);
|
||||
}
|
||||
|
||||
@@ -11,13 +11,14 @@ import io.ebeaninternal.dbmigration.migration.DropColumn;
|
||||
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
|
||||
import io.ebeaninternal.dbmigration.migration.DropTable;
|
||||
import io.ebeaninternal.dbmigration.migration.ForeignKey;
|
||||
import io.ebeaninternal.dbmigration.migration.IdentityType;
|
||||
import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
import io.ebeaninternal.server.deploy.PartitionMeta;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@@ -27,6 +28,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
|
||||
import static io.ebeaninternal.dbmigration.model.MTableIdentity.fromCreateTable;
|
||||
import static io.ebeaninternal.dbmigration.model.MTableIdentity.toCreateTable;
|
||||
|
||||
/**
|
||||
* Holds the logical model for a given Table and everything associated to it.
|
||||
@@ -84,18 +87,7 @@ public class MTable {
|
||||
*/
|
||||
private String indexTablespace;
|
||||
|
||||
/**
|
||||
* If set then this overrides the platform default so for UUID generated values
|
||||
* or DB's supporting both sequences and autoincrement.
|
||||
*/
|
||||
private IdentityType identityType;
|
||||
|
||||
/**
|
||||
* DB sequence name.
|
||||
*/
|
||||
private String sequenceName;
|
||||
private int sequenceInitial;
|
||||
private int sequenceAllocate;
|
||||
private IdentityMode identityMode;
|
||||
|
||||
/**
|
||||
* If set to true this table should has history support.
|
||||
@@ -130,6 +122,29 @@ public class MTable {
|
||||
|
||||
private List<String> droppedColumns = new ArrayList<>();
|
||||
|
||||
public MTable(BeanDescriptor<?> descriptor) {
|
||||
this.name = descriptor.getBaseTable();
|
||||
this.identityMode = descriptor.getIdentityMode();
|
||||
this.storageEngine = descriptor.getStorageEngine();
|
||||
this.partitionMeta = descriptor.getPartitionMeta();
|
||||
this.comment = descriptor.getDbComment();
|
||||
if (descriptor.isHistorySupport()) {
|
||||
withHistory = true;
|
||||
BeanProperty whenCreated = descriptor.getWhenCreatedProperty();
|
||||
if (whenCreated != null) {
|
||||
whenCreatedColumn = whenCreated.getDbColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for element collection or intersection table.
|
||||
*/
|
||||
public MTable(String name) {
|
||||
this.name = name;
|
||||
this.identityMode = IdentityMode.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this table structure as a 'draft' table.
|
||||
* <p>
|
||||
@@ -143,7 +158,7 @@ public class MTable {
|
||||
draftTable.whenCreatedColumn = whenCreatedColumn;
|
||||
// compoundKeys
|
||||
// compoundUniqueConstraints
|
||||
draftTable.identityType = identityType;
|
||||
draftTable.identityMode = identityMode;
|
||||
|
||||
for (MColumn col : allColumns()) {
|
||||
draftTable.addColumn(col.copyForDraft());
|
||||
@@ -164,9 +179,7 @@ public class MTable {
|
||||
this.indexTablespace = createTable.getIndexTablespace();
|
||||
this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory());
|
||||
this.draft = Boolean.TRUE.equals(createTable.isDraft());
|
||||
this.sequenceName = createTable.getSequenceName();
|
||||
this.sequenceInitial = toInt(createTable.getSequenceInitial());
|
||||
this.sequenceAllocate = toInt(createTable.getSequenceAllocate());
|
||||
this.identityMode = fromCreateTable(createTable);
|
||||
List<Column> cols = createTable.getColumn();
|
||||
for (Column column : cols) {
|
||||
addColumn(column);
|
||||
@@ -194,13 +207,6 @@ public class MTable {
|
||||
addForeignKey(foreignKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct typically from EbeanServer meta data.
|
||||
*/
|
||||
public MTable(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DropTable migration for this table.
|
||||
*/
|
||||
@@ -208,7 +214,7 @@ public class MTable {
|
||||
DropTable dropTable = new DropTable();
|
||||
dropTable.setName(name);
|
||||
// we must add pk col name & sequence name, as we have to delete the sequence also.
|
||||
if (identityType != IdentityType.GENERATOR && identityType != IdentityType.EXTERNAL) {
|
||||
if (identityMode.isDatabaseIdentity()) {
|
||||
String pkCol = null;
|
||||
for (MColumn column : columns.values()) {
|
||||
if (column.isPrimaryKey()) {
|
||||
@@ -222,7 +228,7 @@ public class MTable {
|
||||
}
|
||||
if (pkCol != null) {
|
||||
dropTable.setSequenceCol(pkCol);
|
||||
dropTable.setSequenceName(sequenceName);
|
||||
dropTable.setSequenceName(identityMode.getSequenceName());
|
||||
}
|
||||
}
|
||||
return dropTable;
|
||||
@@ -244,10 +250,7 @@ public class MTable {
|
||||
createTable.setStorageEngine(storageEngine);
|
||||
createTable.setTablespace(tablespace);
|
||||
createTable.setIndexTablespace(indexTablespace);
|
||||
createTable.setSequenceName(sequenceName);
|
||||
createTable.setSequenceInitial(toBigInteger(sequenceInitial));
|
||||
createTable.setSequenceAllocate(toBigInteger(sequenceAllocate));
|
||||
createTable.setIdentityType(identityType);
|
||||
toCreateTable(identityMode, createTable);
|
||||
if (withHistory) {
|
||||
createTable.setWithHistory(Boolean.TRUE);
|
||||
}
|
||||
@@ -458,10 +461,6 @@ public class MTable {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public void setStorageEngine(String storageEngine) {
|
||||
this.storageEngine = storageEngine;
|
||||
}
|
||||
|
||||
public String getTablespace() {
|
||||
return tablespace;
|
||||
}
|
||||
@@ -519,36 +518,10 @@ public class MTable {
|
||||
return compoundKeys;
|
||||
}
|
||||
|
||||
public void setSequenceName(String sequenceName) {
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
public void setSequenceInitial(int sequenceInitial) {
|
||||
this.sequenceInitial = sequenceInitial;
|
||||
}
|
||||
|
||||
public void setSequenceAllocate(int sequenceAllocate) {
|
||||
this.sequenceAllocate = sequenceAllocate;
|
||||
}
|
||||
|
||||
public void setWhenCreatedColumn(String whenCreatedColumn) {
|
||||
this.whenCreatedColumn = whenCreatedColumn;
|
||||
}
|
||||
|
||||
public String getWhenCreatedColumn() {
|
||||
return whenCreatedColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity type to use for this table.
|
||||
* <p>
|
||||
* If set then this overrides the platform default so for UUID generated values
|
||||
* or DB's supporting both sequences and autoincrement.
|
||||
*/
|
||||
public void setIdentityType(IdentityType identityType) {
|
||||
this.identityType = identityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of columns that make the primary key.
|
||||
*/
|
||||
@@ -671,14 +644,6 @@ public class MTable {
|
||||
droppedColumns.add(columnName);
|
||||
}
|
||||
|
||||
private int toInt(BigInteger value) {
|
||||
return (value == null) ? 0 : value.intValue();
|
||||
}
|
||||
|
||||
private BigInteger toBigInteger(int value) {
|
||||
return (value == 0) ? null : BigInteger.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are duplicate foreign keys.
|
||||
* <p>
|
||||
@@ -774,10 +739,6 @@ public class MTable {
|
||||
}
|
||||
}
|
||||
|
||||
public void setPartitionMeta(PartitionMeta partitionMeta) {
|
||||
this.partitionMeta = partitionMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear foreign key as this element collection table logically references
|
||||
* back to multiple tables.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package io.ebeaninternal.dbmigration.model;
|
||||
|
||||
import io.ebean.annotation.IdentityGenerated;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebeaninternal.dbmigration.migration.CreateTable;
|
||||
import io.ebeaninternal.dbmigration.migration.IdentityType;
|
||||
import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Helper to convert between IdentityMode and CreateTable
|
||||
*/
|
||||
public class MTableIdentity {
|
||||
|
||||
/**
|
||||
* Return the IdentityMode from CreateTable.
|
||||
*/
|
||||
public static IdentityMode fromCreateTable(CreateTable createTable) {
|
||||
|
||||
IdType type = fromType(createTable.getIdentityType());
|
||||
IdentityGenerated generated = fromGenerated(createTable.getIdentityGenerated());
|
||||
int start = toInt(createTable.getIdentityStart(), createTable.getSequenceInitial());
|
||||
int increment = toInt(createTable.getIdentityIncrement(), createTable.getSequenceAllocate());
|
||||
int cache = toInt(createTable.getIdentityCache(), null);
|
||||
String seqName = createTable.getSequenceName();
|
||||
|
||||
return new IdentityMode(type, generated, start, increment, cache, seqName);
|
||||
}
|
||||
|
||||
private static IdentityGenerated fromGenerated(String identityGenerated) {
|
||||
if (identityGenerated == null) {
|
||||
return IdentityGenerated.AUTO;
|
||||
}
|
||||
return IdentityGenerated.valueOf(identityGenerated.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IdentityMode to the CreateTable model.
|
||||
*/
|
||||
public static void toCreateTable(IdentityMode identityMode, CreateTable createTable) {
|
||||
|
||||
if (!identityMode.isPlatformDefault()) {
|
||||
createTable.setIdentityType(toType(identityMode.getIdType()));
|
||||
}
|
||||
final String seqName = identityMode.getSequenceName();
|
||||
if (seqName != null && !seqName.isEmpty()) {
|
||||
createTable.setSequenceName(seqName);
|
||||
}
|
||||
|
||||
createTable.setIdentityStart(toBigInteger(identityMode.getStart()));
|
||||
createTable.setIdentityIncrement(toBigInteger(identityMode.getIncrement()));
|
||||
createTable.setIdentityCache(toBigInteger(identityMode.getCache()));
|
||||
final IdentityGenerated generated = identityMode.getGenerated();
|
||||
if (generated != null && generated != IdentityGenerated.AUTO) {
|
||||
createTable.setIdentityGenerated(generated.name().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static IdType fromType(IdentityType type) {
|
||||
if (type == null) {
|
||||
return IdType.AUTO;
|
||||
}
|
||||
switch (type) {
|
||||
case DEFAULT:
|
||||
return IdType.AUTO;
|
||||
case SEQUENCE:
|
||||
return IdType.SEQUENCE;
|
||||
case IDENTITY:
|
||||
return IdType.IDENTITY;
|
||||
case GENERATOR:
|
||||
return IdType.GENERATOR;
|
||||
case EXTERNAL:
|
||||
return IdType.EXTERNAL;
|
||||
}
|
||||
return IdType.AUTO;
|
||||
}
|
||||
|
||||
private static IdentityType toType(IdType type) {
|
||||
if (type == null) {
|
||||
// intersection or element collection table
|
||||
return null;
|
||||
}
|
||||
switch (type) {
|
||||
case SEQUENCE:
|
||||
return IdentityType.SEQUENCE;
|
||||
case IDENTITY:
|
||||
return IdentityType.IDENTITY;
|
||||
case EXTERNAL:
|
||||
return IdentityType.EXTERNAL;
|
||||
case GENERATOR:
|
||||
return IdentityType.GENERATOR;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int toInt(BigInteger firstVal, BigInteger secVal) {
|
||||
if (firstVal != null) {
|
||||
return firstVal.intValue();
|
||||
}
|
||||
return (secVal == null) ? 0 : secVal.intValue();
|
||||
}
|
||||
|
||||
private static BigInteger toBigInteger(int value) {
|
||||
return (value == 0) ? null : BigInteger.valueOf(value);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
package io.ebeaninternal.dbmigration.model.build;
|
||||
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebeaninternal.dbmigration.migration.IdentityType;
|
||||
import io.ebeaninternal.dbmigration.model.MColumn;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import io.ebeaninternal.dbmigration.model.visitor.BeanVisitor;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.InheritInfo;
|
||||
|
||||
/**
|
||||
@@ -35,19 +32,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
MTable table = new MTable(descriptor.getBaseTable());
|
||||
table.setStorageEngine(descriptor.getStorageEngine());
|
||||
table.setPartitionMeta(descriptor.getPartitionMeta());
|
||||
table.setComment(descriptor.getDbComment());
|
||||
if (descriptor.isHistorySupport()) {
|
||||
table.setWithHistory(true);
|
||||
BeanProperty whenCreated = descriptor.getWhenCreatedProperty();
|
||||
if (whenCreated != null) {
|
||||
table.setWhenCreatedColumn(whenCreated.getDbColumn());
|
||||
}
|
||||
}
|
||||
setIdentity(descriptor, table);
|
||||
|
||||
MTable table = new MTable(descriptor);
|
||||
// add the table to the model
|
||||
ctx.addTable(table);
|
||||
|
||||
@@ -66,43 +51,4 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
|
||||
return new ModelBuildPropertyVisitor(ctx, table, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity type to use for this table.
|
||||
* <p>
|
||||
* Takes into account the requested identity type and the underlying support in the
|
||||
* database platform.
|
||||
* </p>
|
||||
*/
|
||||
private void setIdentity(BeanDescriptor<?> descriptor, MTable table) {
|
||||
|
||||
if (IdType.GENERATOR == descriptor.getIdType()) {
|
||||
// explicit generator like UUID
|
||||
table.setIdentityType(IdentityType.GENERATOR);
|
||||
return;
|
||||
}
|
||||
if (IdType.EXTERNAL == descriptor.getIdType()) {
|
||||
// externally defined code (lookup table, ISO country code etc)
|
||||
table.setIdentityType(IdentityType.EXTERNAL);
|
||||
return;
|
||||
}
|
||||
|
||||
int initialValue = descriptor.getSequenceInitialValue();
|
||||
int allocationSize = descriptor.getSequenceAllocationSize();
|
||||
|
||||
if (!descriptor.isIdTypePlatformDefault() || initialValue > 0 || allocationSize > 0) {
|
||||
// explicitly set to use sequence or identity (generally not recommended practice)
|
||||
if (IdType.IDENTITY == descriptor.getIdType()) {
|
||||
if (!descriptor.isIdTypePlatformDefault()) {
|
||||
table.setIdentityType(IdentityType.IDENTITY);
|
||||
}
|
||||
} else {
|
||||
// explicit sequence defined
|
||||
table.setIdentityType(IdentityType.SEQUENCE);
|
||||
table.setSequenceName(descriptor.getSequenceName());
|
||||
table.setSequenceInitial(initialValue);
|
||||
table.setSequenceAllocate(allocationSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.extraddl.model;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -11,6 +10,8 @@ import javax.xml.bind.Unmarshaller;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
|
||||
|
||||
/**
|
||||
* Read ExtraDdl from an XML document.
|
||||
*/
|
||||
@@ -18,25 +19,21 @@ public class ExtraDdlXmlReader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExtraDdlXmlReader.class);
|
||||
|
||||
private static final String SQLSERVER = Platform.SQLSERVER.name().toLowerCase();
|
||||
|
||||
/**
|
||||
* Return the combined extra DDL that should be run given the platform name.
|
||||
*/
|
||||
public static String buildExtra(String platformName, boolean drops) {
|
||||
|
||||
ExtraDdl read = ExtraDdlXmlReader.read("/extra-ddl.xml");
|
||||
return buildExtra(platformName, drops, read);
|
||||
public static String buildExtra(Platform platform, boolean drops) {
|
||||
return buildExtra(platform, drops, read("/extra-ddl.xml"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any extra DDL for supporting partitioning given the database platform.
|
||||
*/
|
||||
public static String buildPartitioning(String platformName) {
|
||||
return buildExtra(platformName, false, readBuiltinTablePartitioning());
|
||||
public static String buildPartitioning(Platform platform) {
|
||||
return buildExtra(platform, false, readBuiltinTablePartitioning());
|
||||
}
|
||||
|
||||
private static String buildExtra(String platformName, boolean drops, ExtraDdl read) {
|
||||
private static String buildExtra(Platform platform, boolean drops, ExtraDdl read) {
|
||||
|
||||
if (read == null) {
|
||||
return null;
|
||||
@@ -44,7 +41,7 @@ public class ExtraDdlXmlReader {
|
||||
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
for (DdlScript script : read.getDdlScript()) {
|
||||
if (script.isDrop() == drops && matchPlatform(platformName, script.getPlatforms())) {
|
||||
if (script.isDrop() == drops && matchPlatform(platform, script.getPlatforms())) {
|
||||
logger.debug("include script {}", script.getName());
|
||||
String value = script.getValue();
|
||||
sb.append(value);
|
||||
@@ -58,44 +55,6 @@ public class ExtraDdlXmlReader {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the script platforms is a match/supported for the given platform.
|
||||
*
|
||||
* @param platformName The database platform we are generating/running DDL for
|
||||
* @param platforms The platforms (comma delimited) this script should run for
|
||||
*/
|
||||
public static boolean matchPlatform(String platformName, String platforms) {
|
||||
if (platforms == null || platforms.trim().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String genericMatch = genericPlatformMatch(platformName);
|
||||
|
||||
for (String name : StringHelper.splitNames(platforms)) {
|
||||
if (name.toLowerCase().contains(platformName)) {
|
||||
return true;
|
||||
} else if (genericMatch != null && genericMatch.equals(name.toLowerCase())) {
|
||||
// allow sqlserver ... to match sqlserver17 and sqlserver16 platforms
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a "generic" platform name that can be used. e.g. sqlserver17 -> sqlserver.
|
||||
*/
|
||||
private static String genericPlatformMatch(String platformName) {
|
||||
switch (platformName) {
|
||||
case "sqlserver17":
|
||||
return SQLSERVER;
|
||||
case "sqlserver16":
|
||||
return SQLSERVER;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the builtin extra ddl. (Stored procedures, tvp types etc)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.ebeaninternal.server.cache;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
/**
|
||||
* Bean Id value plus discriminator type.
|
||||
* <p>
|
||||
* Put into L2 cache such that we know the type of a bean with inheritance.
|
||||
*/
|
||||
public class CachedBeanId implements Externalizable {
|
||||
|
||||
private String discValue;
|
||||
private Object id;
|
||||
|
||||
public CachedBeanId(String discValue, Object id) {
|
||||
this.discValue = discValue;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct from serialisation.
|
||||
*/
|
||||
public CachedBeanId() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeUTF(discValue);
|
||||
out.writeObject(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
discValue = in.readUTF();
|
||||
id = in.readObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return discValue + ":" + id;
|
||||
}
|
||||
|
||||
public String getDiscValue() {
|
||||
return discValue;
|
||||
}
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class DefaultCacheHolder {
|
||||
}
|
||||
|
||||
private ServerCacheOptions getQueryOptions(Class<?> cls) {
|
||||
CacheQueryTuning tuning = AnnotationUtil.findAnnotation(cls, CacheQueryTuning.class);
|
||||
CacheQueryTuning tuning = AnnotationUtil.get(cls, CacheQueryTuning.class);
|
||||
if (tuning != null) {
|
||||
return new ServerCacheOptions(tuning).applyDefaults(queryDefault);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.ebean.meta.MetricType.L2;
|
||||
|
||||
/**
|
||||
* The default cache implementation.
|
||||
* <p>
|
||||
@@ -74,12 +72,12 @@ public class DefaultServerCache implements ServerCache {
|
||||
MetricFactory factory = MetricFactory.get();
|
||||
|
||||
String prefix = "l2n.";
|
||||
this.hitCount = factory.createCountMetric(L2, prefix + shortName + ".hit");
|
||||
this.missCount = factory.createCountMetric(L2, prefix + shortName + ".miss");
|
||||
this.putCount = factory.createCountMetric(L2, prefix + shortName + ".put");
|
||||
this.removeCount = factory.createCountMetric(L2, prefix + shortName + ".remove");
|
||||
this.clearCount = factory.createCountMetric(L2, prefix + shortName + ".clear");
|
||||
this.evictCount = factory.createCountMetric(L2, prefix + shortName + ".evict");
|
||||
this.hitCount = factory.createCountMetric(prefix + shortName + ".hit");
|
||||
this.missCount = factory.createCountMetric(prefix + shortName + ".miss");
|
||||
this.putCount = factory.createCountMetric(prefix + shortName + ".put");
|
||||
this.removeCount = factory.createCountMetric(prefix + shortName + ".remove");
|
||||
this.clearCount = factory.createCountMetric(prefix + shortName + ".clear");
|
||||
this.evictCount = factory.createCountMetric(prefix + shortName + ".evict");
|
||||
}
|
||||
|
||||
public void periodicTrim(BackgroundExecutor executor) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DefaultChangeLogRegister implements ChangeLogRegister {
|
||||
* Find and return the ChangeLog annotation in the inheritance hierarchy.
|
||||
*/
|
||||
private ChangeLog getChangeLog(Class<?> beanType) {
|
||||
return AnnotationUtil.findAnnotationRecursive(beanType, ChangeLog.class);
|
||||
return AnnotationUtil.typeGet(beanType, ChangeLog.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,9 @@ import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
|
||||
import io.ebean.config.dbplatform.mysql.MySql55Platform;
|
||||
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
|
||||
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
|
||||
import io.ebean.config.dbplatform.oracle.Oracle11Platform;
|
||||
import io.ebean.config.dbplatform.oracle.OraclePlatform;
|
||||
import io.ebean.config.dbplatform.postgres.Postgres8Platform;
|
||||
import io.ebean.config.dbplatform.postgres.Postgres9Platform;
|
||||
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
|
||||
import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
|
||||
import io.ebean.config.dbplatform.sqlite.SQLitePlatform;
|
||||
@@ -89,10 +90,10 @@ public class DatabasePlatformFactory {
|
||||
if (dbName.equals("postgres") || dbName.equals("postgres9")) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbName.equals("postgres8") || dbName.equals("postgres83")) {
|
||||
return new Postgres8Platform();
|
||||
if (dbName.equals("oracle11") || dbName.equals("oracle10") || dbName.equals("oracle9")) {
|
||||
return new Oracle11Platform();
|
||||
}
|
||||
if (dbName.equals("oracle") || dbName.equals("oracle10") || dbName.equals("oracle9")) {
|
||||
if (dbName.equals("oracle")) {
|
||||
return new OraclePlatform();
|
||||
}
|
||||
if (dbName.equals("sqlserver16")) {
|
||||
@@ -166,7 +167,7 @@ public class DatabasePlatformFactory {
|
||||
} else if (dbProductName.contains("hsql database engine")) {
|
||||
return new HsqldbPlatform();
|
||||
} else if (dbProductName.contains("postgres")) {
|
||||
return readPostgres(connection);
|
||||
return readPostgres(connection, majorVersion);
|
||||
} else if (dbProductName.contains("nuo")) {
|
||||
return new NuoDbPlatform();
|
||||
} else if (dbProductName.contains("sqlite")) {
|
||||
@@ -195,28 +196,23 @@ public class DatabasePlatformFactory {
|
||||
/**
|
||||
* Use a select version() query as it could be Postgres or CockroachDB.
|
||||
*/
|
||||
private static DatabasePlatform readPostgres(Connection connection) {
|
||||
// Postgres driver uses a hardcoded product name so use version() query
|
||||
PreparedStatement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
statement = connection.prepareStatement("SELECT version() AS \"version\"");
|
||||
resultSet = statement.executeQuery();
|
||||
if (resultSet.next()) {
|
||||
String productVersion = resultSet.getString("version").toLowerCase();
|
||||
if (productVersion.contains("cockroach")) {
|
||||
return new CockroachPlatform();
|
||||
private static DatabasePlatform readPostgres(Connection connection, int majorVersion) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("select version() as \"version\"")) {
|
||||
try (ResultSet resultSet = statement.executeQuery()) {
|
||||
if (resultSet.next()) {
|
||||
String productVersion = resultSet.getString("version").toLowerCase();
|
||||
if (productVersion.contains("cockroach")) {
|
||||
return new CockroachPlatform();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.warn("Error running detection query on Postgres", e);
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(resultSet);
|
||||
JdbcClose.close(statement);
|
||||
}
|
||||
|
||||
// Real Postgres
|
||||
if (majorVersion <= 9) {
|
||||
return new Postgres9Platform();
|
||||
}
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class DumpMetricsData {
|
||||
}
|
||||
|
||||
private MetricData create(MetaMetric metric) {
|
||||
MetricData data = new MetricData(metric.getName(), metric.getMetricType().name());
|
||||
MetricData data = new MetricData(metric.getName());
|
||||
list.add(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ public class InternalConfiguration {
|
||||
|
||||
private MultiValueBind createMultiValueBind(Platform platform) {
|
||||
// only Postgres at this stage
|
||||
if (platform == Platform.POSTGRES) {
|
||||
if (platform.base() == Platform.POSTGRES) {
|
||||
return new PostgresMultiValueBind();
|
||||
}
|
||||
return new MultiValueBind();
|
||||
@@ -533,7 +533,7 @@ public class InternalConfiguration {
|
||||
}
|
||||
return new NoDataTimeZone();
|
||||
}
|
||||
if (getPlatform() == Platform.ORACLE) {
|
||||
if (getPlatform().base() == Platform.ORACLE) {
|
||||
return new CloneDataTimeZone(tz);
|
||||
} else {
|
||||
return new SimpleDataTimeZone(tz);
|
||||
|
||||
@@ -699,7 +699,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Create and return a new reference bean matching this beans Id value.
|
||||
*/
|
||||
public T createReference() {
|
||||
return beanDescriptor.createReference(getBeanId(), null);
|
||||
return beanDescriptor.createRef(getBeanId(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.ebeaninternal.dbmigration.ddlgeneration.platform.MySqlDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.NuoDbDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.Oracle10Ddl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.Postgres9Ddl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.PostgresDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SQLiteDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SqlServerDdl;
|
||||
@@ -38,17 +39,16 @@ public class PlatformDdlBuilder {
|
||||
case NUODB:
|
||||
return new NuoDbDdl(platform);
|
||||
case ORACLE:
|
||||
case ORACLE11:
|
||||
return new Oracle10Ddl(platform);
|
||||
case SQLITE:
|
||||
return new SQLiteDdl(platform);
|
||||
case GENERIC:
|
||||
return new PlatformDdl(platform);
|
||||
case POSTGRES9:
|
||||
return new Postgres9Ddl(platform);
|
||||
case POSTGRES:
|
||||
return new PostgresDdl(platform);
|
||||
case COCKROACH:
|
||||
return new CockroachDdl(platform);
|
||||
case SQLANYWHERE:
|
||||
return new PlatformDdl(platform);
|
||||
case SQLSERVER16:
|
||||
case SQLSERVER17:
|
||||
case SQLSERVER:
|
||||
|
||||
@@ -473,6 +473,6 @@ public class BootupClasses implements ClassFilter {
|
||||
* Returns true if this class has the annotation (or meta annotation). Does not search recursively.
|
||||
*/
|
||||
private boolean has(Class<?> cls, Class<? extends Annotation> ann) {
|
||||
return AnnotationUtil.findAnnotation(cls, ann) != null;
|
||||
return AnnotationUtil.has(cls, ann);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,28 +154,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
*/
|
||||
private final EntityType entityType;
|
||||
|
||||
/**
|
||||
* Type of Identity generation strategy used.
|
||||
*/
|
||||
private final IdType idType;
|
||||
|
||||
/**
|
||||
* Set when Id property is marked with GeneratedValue annotation.
|
||||
*/
|
||||
private final boolean idGeneratedValue;
|
||||
|
||||
private final boolean idTypePlatformDefault;
|
||||
|
||||
private final PlatformIdGenerator idGenerator;
|
||||
|
||||
/**
|
||||
* The database sequence name (optional).
|
||||
*/
|
||||
private final String sequenceName;
|
||||
|
||||
private final int sequenceInitialValue;
|
||||
|
||||
private final int sequenceAllocationSize;
|
||||
private final IdentityMode identityMode;
|
||||
private final IdType idType;
|
||||
|
||||
/**
|
||||
* SQL used to return last inserted id. Used for Identity columns where
|
||||
@@ -456,13 +441,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
this.changeLogFilter = deploy.getChangeLogFilter();
|
||||
|
||||
this.defaultSelectClause = deploy.getDefaultSelectClause();
|
||||
this.idType = deploy.getIdType();
|
||||
this.identityMode = deploy.buildIdentityMode();
|
||||
this.idType = identityMode.getIdType();
|
||||
this.idGeneratedValue = deploy.isIdGeneratedValue();
|
||||
this.idTypePlatformDefault = deploy.isIdTypePlatformDefault();
|
||||
this.idGenerator = deploy.getIdGenerator();
|
||||
this.sequenceName = deploy.getSequenceName();
|
||||
this.sequenceInitialValue = deploy.getSequenceInitialValue();
|
||||
this.sequenceAllocationSize = deploy.getSequenceAllocationSize();
|
||||
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
|
||||
this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft();
|
||||
this.concurrencyMode = deploy.getConcurrencyMode();
|
||||
@@ -2071,14 +2053,16 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
/**
|
||||
* Create a non read only reference bean without checking cacheSharableBeans.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createReference(Object id, PersistenceContext pc) {
|
||||
if (inheritInfo != null && !inheritInfo.isConcrete()) {
|
||||
return findReferenceBean(id, pc);
|
||||
}
|
||||
return createRef(id, pc);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createRef(Object id, PersistenceContext pc) {
|
||||
try {
|
||||
if (inheritInfo != null && !inheritInfo.isConcrete()) {
|
||||
return findReferenceBean(id, pc);
|
||||
}
|
||||
|
||||
EntityBean eb = createEntityBean();
|
||||
id = convertSetId(id, eb);
|
||||
EntityBeanIntercept ebi = eb._ebean_getIntercept();
|
||||
@@ -2089,7 +2073,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
return (T) eb;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
@@ -3158,33 +3141,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return idGeneratedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the identity is the platform default (not explicitly set).
|
||||
*/
|
||||
public boolean isIdTypePlatformDefault() {
|
||||
return idTypePlatformDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequence name.
|
||||
*/
|
||||
@Override
|
||||
public String getSequenceName() {
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequence initial value.
|
||||
*/
|
||||
public int getSequenceInitialValue() {
|
||||
return sequenceInitialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequence allocation size.
|
||||
*/
|
||||
public int getSequenceAllocationSize() {
|
||||
return sequenceAllocationSize;
|
||||
public IdentityMode getIdentityMode() {
|
||||
return identityMode;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,6 +46,7 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployOrderColumn;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployIdentityMode;
|
||||
import io.ebeaninternal.server.deploy.parse.DeployBeanInfo;
|
||||
import io.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import io.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
@@ -1001,6 +1002,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
orderProperty.setDbInsertable(orderColumn.isInsertable());
|
||||
orderProperty.setDbUpdateable(orderColumn.isUpdatable());
|
||||
orderProperty.setDbRead(true);
|
||||
orderProperty.setOwningType(targetDesc.getBeanType());
|
||||
|
||||
targetDesc.setOrderColumn(orderProperty);
|
||||
}
|
||||
@@ -1354,42 +1356,39 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IdType.SEQUENCE == desc.getIdType() && !dbIdentity.isSupportsSequence()) {
|
||||
final DeployIdentityMode identityMode = desc.getIdentityMode();
|
||||
if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) {
|
||||
// explicit sequence but not supported by the DatabasePlatform
|
||||
logger.info("Explicit sequence on " + desc.getFullName() + " but not supported by DB Platform - ignored");
|
||||
desc.setIdType(null);
|
||||
identityMode.setIdType(IdType.AUTO);
|
||||
}
|
||||
if (IdType.IDENTITY == desc.getIdType() && !dbIdentity.isSupportsIdentity()) {
|
||||
if (identityMode.isIdentity() && !dbIdentity.isSupportsIdentity()) {
|
||||
// explicit identity but not supported by the DatabasePlatform
|
||||
logger.info("Explicit Identity on " + desc.getFullName() + " but not supported by DB Platform - ignored");
|
||||
desc.setIdType(null);
|
||||
identityMode.setIdType(IdType.AUTO);
|
||||
}
|
||||
|
||||
if (desc.getIdType() == null) {
|
||||
if (identityMode.isAuto()) {
|
||||
if (desc.isPrimaryKeyCompoundOrNonNumeric()) {
|
||||
// assuming that this is a user supplied key like ISO country code or ISO currency code or lookup table code
|
||||
logger.debug("Expecting user defined identity on {} - not using db sequence or autoincrement", desc.getFullName());
|
||||
desc.setIdType(IdType.EXTERNAL);
|
||||
identityMode.setIdType(IdType.EXTERNAL);
|
||||
return;
|
||||
}
|
||||
if (desc.isIdGeneratedValue() || serverConfig.isIdGeneratorAutomatic()) {
|
||||
// use IDENTITY or SEQUENCE based on platform
|
||||
desc.setIdType(dbIdentity.getIdType());
|
||||
desc.setIdTypePlatformDefault();
|
||||
identityMode.setPlatformType(dbIdentity.getIdType());
|
||||
} else {
|
||||
// externally/application supplied Id values
|
||||
desc.setIdType(IdType.EXTERNAL);
|
||||
identityMode.setIdType(IdType.EXTERNAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.getBaseTable() == null) {
|
||||
// no base table so not going to set Identity
|
||||
// of sequence information
|
||||
// no base table so not going to set Identity or sequence information
|
||||
return;
|
||||
}
|
||||
|
||||
if (IdType.IDENTITY == desc.getIdType()) {
|
||||
if (identityMode.isIdentity()) {
|
||||
// used when getGeneratedKeys is not supported (SQL Server 2000, SAP Hana)
|
||||
String selectLastInsertedId = dbIdentity.getSelectLastInsertedId(desc.getBaseTable());
|
||||
String selectLastInsertedIdDraft = (!desc.isDraftable()) ? selectLastInsertedId : dbIdentity.getSelectLastInsertedId(desc.getDraftTable());
|
||||
@@ -1397,21 +1396,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IdType.SEQUENCE == desc.getIdType()) {
|
||||
String seqName = desc.getIdGeneratorName();
|
||||
if (seqName != null) {
|
||||
logger.debug("explicit sequence {} on {}", seqName, desc.getFullName());
|
||||
} else {
|
||||
if (identityMode.isSequence()) {
|
||||
String seqName = identityMode.getSequenceName();
|
||||
if (seqName == null || seqName.isEmpty()) {
|
||||
String primaryKeyColumn = desc.getSinglePrimaryKeyColumn();
|
||||
// use namingConvention to define sequence name
|
||||
seqName = namingConvention.getSequenceName(desc.getBaseTable(), primaryKeyColumn);
|
||||
}
|
||||
|
||||
if (databasePlatform.isSequenceBatchMode()) {
|
||||
// use sequence next step 1 as we are going to batch fetch them instead
|
||||
desc.setSequenceAllocationSize(1);
|
||||
}
|
||||
int stepSize = desc.getSequenceAllocationSize();
|
||||
int stepSize = desc.setIdentitySequenceBatchMode(databasePlatform.isSequenceBatchMode());
|
||||
desc.setIdGenerator(createSequenceIdGenerator(seqName, stepSize));
|
||||
}
|
||||
}
|
||||
@@ -1601,7 +1592,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
*/
|
||||
private boolean isMappedSuperWithNoProperties(Class<?> beanClass) {
|
||||
// do not search recursive here
|
||||
MappedSuperclass annotation = AnnotationUtil.findAnnotation(beanClass, MappedSuperclass.class);
|
||||
MappedSuperclass annotation = AnnotationUtil.get(beanClass, MappedSuperclass.class);
|
||||
if (annotation == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.meta.MetricType;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
@@ -25,12 +24,12 @@ class BeanIudMetrics {
|
||||
|
||||
MetricFactory metricFactory = MetricFactory.get();
|
||||
String prefix = "iud." + beanShortName;
|
||||
this.insert = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".insert");
|
||||
this.update = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".update");
|
||||
this.delete = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".delete");
|
||||
this.insertBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".insertBatch");
|
||||
this.updateBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".updateBatch");
|
||||
this.deleteBatch = metricFactory.createTimedMetric(MetricType.IUD, prefix + ".deleteBatch");
|
||||
this.insert = metricFactory.createTimedMetric(prefix + ".insert");
|
||||
this.update = metricFactory.createTimedMetric(prefix + ".update");
|
||||
this.delete = metricFactory.createTimedMetric(prefix + ".delete");
|
||||
this.insertBatch = metricFactory.createTimedMetric(prefix + ".insertBatch");
|
||||
this.updateBatch = metricFactory.createTimedMetric(prefix + ".updateBatch");
|
||||
this.deleteBatch = metricFactory.createTimedMetric(prefix + ".deleteBatch");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.cache.CacheChangeSet;
|
||||
import io.ebeaninternal.server.cache.CachedBeanData;
|
||||
import io.ebeaninternal.server.cache.CachedBeanId;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
@@ -433,11 +434,19 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
}
|
||||
if (embedded) {
|
||||
return targetDescriptor.cacheEmbeddedBeanExtract((EntityBean) ap);
|
||||
} else if (targetInheritInfo != null) {
|
||||
return createCacheBeanId(ap);
|
||||
} else {
|
||||
return targetDescriptor.getIdProperty().getCacheDataValue((EntityBean) ap);
|
||||
}
|
||||
}
|
||||
|
||||
private Object createCacheBeanId(Object bean) {
|
||||
final BeanDescriptor<?> desc = targetDescriptor.descOf(bean.getClass());
|
||||
final Object id = desc.getIdProperty().getCacheDataValue((EntityBean) bean);
|
||||
return new CachedBeanId(desc.getDiscValue(), id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(Object value) {
|
||||
return targetDescriptor.getIdBinder().cacheKey(value);
|
||||
@@ -451,19 +460,31 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
if (embedded) {
|
||||
setValue(bean, targetDescriptor.cacheEmbeddedBeanLoad((CachedBeanData) cacheData, context));
|
||||
} else {
|
||||
if (cacheData instanceof String) {
|
||||
cacheData = targetDescriptor.getIdProperty().scalarType.parse((String) cacheData);
|
||||
if (cacheData instanceof CachedBeanId) {
|
||||
setValue(bean, refInheritBean((CachedBeanId) cacheData, context));
|
||||
} else {
|
||||
setValue(bean, refBean(targetDescriptor, cacheData, context));
|
||||
}
|
||||
// cacheData is the id value, maybe already in persistence context
|
||||
Object assocBean = targetDescriptor.contextGet(context, cacheData);
|
||||
if (assocBean == null) {
|
||||
assocBean = targetDescriptor.createReference(cacheData, context);
|
||||
}
|
||||
setValue(bean, assocBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object refInheritBean(CachedBeanId cacheId, PersistenceContext context) {
|
||||
final InheritInfo rowInheritInfo = targetInheritInfo.readType(cacheId.getDiscValue());
|
||||
return refBean(rowInheritInfo.desc(), cacheId.getId(), context);
|
||||
}
|
||||
|
||||
private Object refBean(BeanDescriptor<?> desc, Object id, PersistenceContext context) {
|
||||
if (id instanceof String) {
|
||||
id = desc.getIdProperty().scalarType.parse((String) id);
|
||||
}
|
||||
Object bean = desc.contextGet(context, id);
|
||||
if (bean == null) {
|
||||
bean = desc.createRef(id, context);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarDataReader<?> getIdReader() {
|
||||
return targetDescriptor.getIdProperty();
|
||||
@@ -640,14 +661,12 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
|
||||
@Override
|
||||
public void addTenant(SpiQuery<?> query, Object tenantId) {
|
||||
T refBean = targetDescriptor.createReference(tenantId, null);
|
||||
query.where().eq(name, refBean);
|
||||
query.where().eq(name, targetDescriptor.createRef(tenantId, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTenantValue(EntityBean entityBean, Object tenantId) {
|
||||
T refBean = targetDescriptor.createReference(tenantId, null);
|
||||
setValue(entityBean, refBean);
|
||||
setValue(entityBean, targetDescriptor.createRef(tenantId, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.annotation.IdentityGenerated;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployIdentityMode;
|
||||
|
||||
public class IdentityMode {
|
||||
|
||||
public static IdentityMode NONE = new IdentityMode();
|
||||
|
||||
private final IdType type;
|
||||
private final IdentityGenerated generated;
|
||||
private final int start;
|
||||
private final int increment;
|
||||
private final int cache;
|
||||
private final String sequenceName;
|
||||
private final boolean platformDefault;
|
||||
|
||||
/**
|
||||
* Create from deployment.
|
||||
*/
|
||||
public IdentityMode(DeployIdentityMode deploy) {
|
||||
this.type = deploy.getIdType();
|
||||
this.generated = deploy.getGenerated();
|
||||
this.start = deploy.getStart();
|
||||
this.increment = deploy.getIncrement();
|
||||
this.cache = deploy.getCache();
|
||||
this.sequenceName = deploy.getSequenceName();
|
||||
this.platformDefault = deploy.isPlatformDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from migration model CreateTable.
|
||||
*/
|
||||
public IdentityMode(IdType type, IdentityGenerated auto, int start, int increment, int cache, String seqName) {
|
||||
this.type = type;
|
||||
this.generated = auto;
|
||||
this.start = start;
|
||||
this.increment = increment;
|
||||
this.cache = cache;
|
||||
this.sequenceName = seqName;
|
||||
this.platformDefault = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* NONE constructor.
|
||||
*/
|
||||
private IdentityMode() {
|
||||
this.type = null;
|
||||
this.generated = IdentityGenerated.AUTO;
|
||||
this.start = 0;
|
||||
this.increment = 0;
|
||||
this.cache = 0;
|
||||
this.sequenceName = "";
|
||||
this.platformDefault = false;
|
||||
}
|
||||
|
||||
public boolean isPlatformDefault() {
|
||||
return platformDefault;
|
||||
}
|
||||
|
||||
public IdType getIdType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public IdentityGenerated getGenerated() {
|
||||
return generated;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public int getIncrement() {
|
||||
return increment;
|
||||
}
|
||||
|
||||
public int getCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
public String getSequenceName() {
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
public boolean isSequence() {
|
||||
return type == IdType.SEQUENCE;
|
||||
}
|
||||
|
||||
public boolean isIdentity() {
|
||||
return type == IdType.IDENTITY;
|
||||
}
|
||||
|
||||
public boolean isExternal() {
|
||||
return type == IdType.EXTERNAL;
|
||||
}
|
||||
|
||||
public boolean isAuto() {
|
||||
return type == IdType.AUTO;
|
||||
}
|
||||
|
||||
public boolean isDatabaseIdentity() {
|
||||
return type != IdType.EXTERNAL && type != IdType.GENERATOR;
|
||||
}
|
||||
|
||||
public boolean hasOptions() {
|
||||
return start > 0 || cache > 0 || increment > 0;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy.meta;
|
||||
import io.ebean.annotation.Cache;
|
||||
import io.ebean.annotation.DocStore;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.Identity;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
@@ -17,6 +18,7 @@ import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.text.PathProperties;
|
||||
import io.ebeaninternal.api.ConcurrencyMode;
|
||||
import io.ebeaninternal.server.core.CacheOptions;
|
||||
import io.ebeaninternal.server.deploy.IdentityMode;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.ChainedBeanPersistController;
|
||||
@@ -85,24 +87,11 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private DeployBeanProperty orderColumn;
|
||||
|
||||
/**
|
||||
* Type of Identity generation strategy used.
|
||||
*/
|
||||
private IdType idType;
|
||||
|
||||
private Class<?> idClass;
|
||||
|
||||
private DeployBeanPropertyAssocOne<?> idClassProperty;
|
||||
|
||||
/**
|
||||
* Set to true if the identity is default for the platform.
|
||||
*/
|
||||
private boolean idTypePlatformDefault;
|
||||
|
||||
/**
|
||||
* The name of an IdGenerator (optional).
|
||||
*/
|
||||
private String idGeneratorName;
|
||||
private DeployIdentityMode identityMode = DeployIdentityMode.auto();
|
||||
|
||||
private PlatformIdGenerator idGenerator;
|
||||
|
||||
@@ -111,15 +100,6 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
private boolean idGeneratedValue;
|
||||
|
||||
/**
|
||||
* The database sequence name (optional).
|
||||
*/
|
||||
private String sequenceName;
|
||||
|
||||
private int sequenceInitialValue;
|
||||
|
||||
private int sequenceAllocationSize = 50;
|
||||
|
||||
/**
|
||||
* Used with Identity columns but no getGeneratedKeys support.
|
||||
*/
|
||||
@@ -244,8 +224,7 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
public void setPrimaryKeyJoin(TableJoin join) {
|
||||
this.primaryKeyJoin = join;
|
||||
this.idType = IdType.EXTERNAL;
|
||||
this.idGeneratorName = null;
|
||||
this.identityMode.setIdType(IdType.EXTERNAL);
|
||||
this.idGenerator = null;
|
||||
}
|
||||
|
||||
@@ -399,20 +378,44 @@ public class DeployBeanDescriptor<T> {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public void setSequenceInitialValue(int sequenceInitialValue) {
|
||||
this.sequenceInitialValue = sequenceInitialValue;
|
||||
/**
|
||||
* Return the immutable IdentityMode.
|
||||
*/
|
||||
public IdentityMode buildIdentityMode() {
|
||||
return new IdentityMode(identityMode);
|
||||
}
|
||||
|
||||
public void setSequenceAllocationSize(int sequenceAllocationSize) {
|
||||
this.sequenceAllocationSize = sequenceAllocationSize;
|
||||
public DeployIdentityMode getIdentityMode() {
|
||||
return identityMode;
|
||||
}
|
||||
|
||||
public int getSequenceInitialValue() {
|
||||
return sequenceInitialValue;
|
||||
public void setIdentityMode(Identity identity) {
|
||||
this.identityMode = new DeployIdentityMode(identity);
|
||||
}
|
||||
|
||||
public int getSequenceAllocationSize() {
|
||||
return sequenceAllocationSize;
|
||||
/**
|
||||
* Set from <code>@Sequence</code>
|
||||
*/
|
||||
public void setIdentitySequence(int initialValue, int allocationSize, String seqName) {
|
||||
identityMode.setSequence(initialValue, allocationSize, seqName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Potentially set sequence name from <code>@GeneratedValue</code>.
|
||||
*/
|
||||
public void setIdentitySequenceGenerator(String genName) {
|
||||
identityMode.setSequenceGenerator(genName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequence increment to use given sequence batch mode.
|
||||
*/
|
||||
public int setIdentitySequenceBatchMode(boolean sequenceBatchMode) {
|
||||
return identityMode.setSequenceBatchMode(sequenceBatchMode);
|
||||
}
|
||||
|
||||
public void setIdentityType(IdType type) {
|
||||
this.identityMode.setIdType(type);
|
||||
}
|
||||
|
||||
public String[] getProperties() {
|
||||
@@ -760,48 +763,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identity generation type.
|
||||
*/
|
||||
public IdType getIdType() {
|
||||
return idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity generation type.
|
||||
*/
|
||||
public void setIdType(IdType idType) {
|
||||
this.idType = idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the identity type is the platform default.
|
||||
*/
|
||||
public void setIdTypePlatformDefault() {
|
||||
this.idTypePlatformDefault = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when the identity is the platform default.
|
||||
*/
|
||||
public boolean isIdTypePlatformDefault() {
|
||||
return idTypePlatformDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB sequence name (can be null).
|
||||
*/
|
||||
public String getSequenceName() {
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB sequence name.
|
||||
*/
|
||||
private void setSequenceName(String sequenceName) {
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL used to return the last inserted Id.
|
||||
* <p>
|
||||
@@ -824,21 +785,6 @@ public class DeployBeanDescriptor<T> {
|
||||
this.selectLastInsertedIdDraft = selectLastInsertedIdDraft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the IdGenerator that should be used with this type of
|
||||
* bean. A null value could be used to specify the 'default' IdGenerator.
|
||||
*/
|
||||
public String getIdGeneratorName() {
|
||||
return idGeneratorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the IdGenerator that should be used with this type of bean.
|
||||
*/
|
||||
public void setIdGeneratorName(String idGeneratorName) {
|
||||
this.idGeneratorName = idGeneratorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual IdGenerator for this bean type (can be null).
|
||||
*/
|
||||
@@ -851,9 +797,6 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
public void setIdGenerator(PlatformIdGenerator idGenerator) {
|
||||
this.idGenerator = idGenerator;
|
||||
if (idGenerator != null && idGenerator.isDbSequence()) {
|
||||
setSequenceName(idGenerator.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -871,25 +814,25 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the standard UUID generator.
|
||||
* Assign the standard UUID generator if one has not been set.
|
||||
*/
|
||||
public void setUuidGenerator() {
|
||||
this.idType = IdType.EXTERNAL;
|
||||
this.idGeneratorName = PlatformIdGenerator.AUTO_UUID;
|
||||
if (idGenerator == null) {
|
||||
this.identityMode.setIdType(IdType.EXTERNAL);
|
||||
switch (serverConfig.getUuidVersion()) {
|
||||
case VERSION1:
|
||||
this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile());
|
||||
break;
|
||||
|
||||
switch (serverConfig.getUuidVersion()) {
|
||||
case VERSION1:
|
||||
this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile());
|
||||
break;
|
||||
case VERSION1RND:
|
||||
this.idGenerator = UuidV1RndIdGenerator.INSTANCE;
|
||||
break;
|
||||
|
||||
case VERSION1RND:
|
||||
this.idGenerator = UuidV1RndIdGenerator.INSTANCE;
|
||||
break;
|
||||
|
||||
case VERSION4:
|
||||
default:
|
||||
this.idGenerator = UuidV4IdGenerator.INSTANCE;
|
||||
break;
|
||||
case VERSION4:
|
||||
default:
|
||||
this.idGenerator = UuidV4IdGenerator.INSTANCE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,8 +840,7 @@ public class DeployBeanDescriptor<T> {
|
||||
* Assign a custom external IdGenerator.
|
||||
*/
|
||||
public void setCustomIdGenerator(PlatformIdGenerator idGenerator) {
|
||||
this.idType = IdType.EXTERNAL;
|
||||
this.idGeneratorName = idGenerator.getName();
|
||||
this.identityMode.setIdType(IdType.EXTERNAL);
|
||||
this.idGenerator = idGenerator;
|
||||
}
|
||||
|
||||
@@ -951,7 +893,6 @@ public class DeployBeanDescriptor<T> {
|
||||
* is non-numeric (and hence not suitable for db identity or sequence.
|
||||
*/
|
||||
public boolean isPrimaryKeyCompoundOrNonNumeric() {
|
||||
|
||||
DeployBeanProperty id = idProperty();
|
||||
if (id == null) {
|
||||
return false;
|
||||
|
||||
@@ -4,10 +4,13 @@ import io.ebean.annotation.CreatedTimestamp;
|
||||
import io.ebean.annotation.DocCode;
|
||||
import io.ebean.annotation.DocProperty;
|
||||
import io.ebean.annotation.DocSortable;
|
||||
import io.ebean.annotation.Formula;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
import io.ebean.annotation.UpdatedTimestamp;
|
||||
import io.ebean.annotation.WhenCreated;
|
||||
import io.ebean.annotation.WhenModified;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.annotation.WhoCreated;
|
||||
import io.ebean.annotation.WhoModified;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
@@ -31,11 +34,13 @@ import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -190,11 +195,6 @@ public class DeployBeanProperty {
|
||||
|
||||
private final DeployDocPropertyOptions docMapping = new DeployDocPropertyOptions();
|
||||
|
||||
/**
|
||||
* The method used to read the property.
|
||||
*/
|
||||
private Method readMethod;
|
||||
|
||||
private int propertyIndex;
|
||||
|
||||
private BeanPropertyGetter getter;
|
||||
@@ -232,6 +232,8 @@ public class DeployBeanProperty {
|
||||
|
||||
private List<DbMigrationInfo> dbMigrationInfos;
|
||||
|
||||
private Set<Annotation> metaAnnotations;
|
||||
|
||||
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
|
||||
this.desc = desc;
|
||||
this.propertyType = propertyType;
|
||||
@@ -261,29 +263,29 @@ public class DeployBeanProperty {
|
||||
if (field == null) {
|
||||
return 0;
|
||||
}
|
||||
if (AnnotationUtil.findAnnotation(field, Id.class) != null) {
|
||||
if (AnnotationUtil.get(field, Id.class) != null) {
|
||||
return ID_ORDER;
|
||||
} else if (AnnotationUtil.findAnnotation(field, EmbeddedId.class) != null) {
|
||||
} else if (AnnotationUtil.get(field, EmbeddedId.class) != null) {
|
||||
return ID_ORDER;
|
||||
} else if (undirectionalShadow) {
|
||||
return UNIDIRECTIONAL_ORDER;
|
||||
} else if (isAuditProperty()) {
|
||||
return AUDITCOLUMN_ORDER;
|
||||
} else if (AnnotationUtil.findAnnotation(field, Version.class) != null) {
|
||||
} else if (AnnotationUtil.get(field, Version.class) != null) {
|
||||
return VERSIONCOLUMN_ORDER;
|
||||
} else if (AnnotationUtil.findAnnotation(field, SoftDelete.class) != null) {
|
||||
} else if (AnnotationUtil.get(field, SoftDelete.class) != null) {
|
||||
return VERSIONCOLUMN_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean isAuditProperty() {
|
||||
return (AnnotationUtil.findAnnotation(field, WhenCreated.class) != null
|
||||
|| AnnotationUtil.findAnnotation(field, WhenModified.class) != null
|
||||
|| AnnotationUtil.findAnnotation(field, WhoModified.class) != null
|
||||
|| AnnotationUtil.findAnnotation(field, WhoCreated.class) != null
|
||||
|| AnnotationUtil.findAnnotation(field, UpdatedTimestamp.class) != null
|
||||
|| AnnotationUtil.findAnnotation(field, CreatedTimestamp.class) != null);
|
||||
return (AnnotationUtil.has(field, WhenCreated.class)
|
||||
|| AnnotationUtil.has(field, WhenModified.class)
|
||||
|| AnnotationUtil.has(field, WhoModified.class)
|
||||
|| AnnotationUtil.has(field, WhoCreated.class)
|
||||
|| AnnotationUtil.has(field, UpdatedTimestamp.class)
|
||||
|| AnnotationUtil.has(field, CreatedTimestamp.class));
|
||||
}
|
||||
|
||||
public String getFullBeanName() {
|
||||
@@ -453,13 +455,6 @@ public class DeployBeanProperty {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the getter method.
|
||||
*/
|
||||
public Method getReadMethod() {
|
||||
return readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the owning type form a Inheritance heirarchy.
|
||||
*/
|
||||
@@ -672,7 +667,7 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
private String aggregationJoin(int pos, String dbColumn) {
|
||||
String p0 = aggregation.substring(0, pos + 1);
|
||||
aggregationParsed = p0 + "${ta}." + dbColumn + aggregation.substring(aggregation.length() - 1);
|
||||
aggregationParsed = p0 + "${ta}." + dbColumn + aggregation.substring(aggregation.length() - 1);
|
||||
return aggregationParsed;
|
||||
}
|
||||
|
||||
@@ -906,17 +901,6 @@ public class DeployBeanProperty {
|
||||
this.isTransient = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean read method.
|
||||
* <p>
|
||||
* NB: That a BeanReflectGetter is used to actually perform the getting of
|
||||
* property values from a bean. This is due to performance considerations.
|
||||
* </p>
|
||||
*/
|
||||
public void setReadMethod(Method readMethod) {
|
||||
this.readMethod = readMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property type.
|
||||
*/
|
||||
@@ -1122,7 +1106,7 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
public Object /*AnnotatedField*/ getJacksonField() {
|
||||
com.fasterxml.jackson.databind.introspect.AnnotatedClass jac =
|
||||
(com.fasterxml.jackson.databind.introspect.AnnotatedClass) getDesc().getJacksonAnnotatedClass();
|
||||
(com.fasterxml.jackson.databind.introspect.AnnotatedClass) getDesc().getJacksonAnnotatedClass();
|
||||
for (com.fasterxml.jackson.databind.introspect.AnnotatedField candidate : jac.fields()) {
|
||||
if (candidate.getName().equals(getName())) {
|
||||
return candidate;
|
||||
@@ -1130,4 +1114,102 @@ public class DeployBeanProperty {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void initMetaAnnotations(Set<Class<?>> metaAnnotationsFilter) {
|
||||
metaAnnotations = AnnotationUtil.metaFindAllFor(field, metaAnnotationsFilter);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> A getMetaAnnotation(Class<A> annotationType) {
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType) {
|
||||
List<A> result = new ArrayList<>();
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
result.add((A) ann);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Size> getMetaAnnotationSize() {
|
||||
final List<Size> size = getMetaAnnotations(Size.class);
|
||||
final List<Size.List> lists = getMetaAnnotations(Size.List.class);
|
||||
for (Size.List list : lists) {
|
||||
Collections.addAll(size, list.value());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public Formula getMetaAnnotationFormula(Platform platform) {
|
||||
Formula fallback = null;
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
if (ann.annotationType() == Formula.class) {
|
||||
Formula formula = (Formula) ann;
|
||||
final Platform[] platforms = formula.platforms();
|
||||
if (platforms.length == 0) {
|
||||
fallback = formula;
|
||||
} else if (matchPlatform(platforms, platform)) {
|
||||
return formula;
|
||||
}
|
||||
|
||||
} else if (ann.annotationType() == Formula.List.class) {
|
||||
Formula.List formulaList = (Formula.List) ann;
|
||||
for (Formula formula : formulaList.value()) {
|
||||
final Platform[] platforms = formula.platforms();
|
||||
if (platforms.length == 0) {
|
||||
fallback = formula;
|
||||
} else if (matchPlatform(platforms, platform)) {
|
||||
return formula;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public Where getMetaAnnotationWhere(Platform platform) {
|
||||
Where fallback = null;
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
if (ann.annotationType() == Where.class) {
|
||||
Where where = (Where) ann;
|
||||
final Platform[] platforms = where.platforms();
|
||||
if (platforms.length == 0) {
|
||||
fallback = where;
|
||||
} else if (matchPlatform(where.platforms(), platform)) {
|
||||
return where;
|
||||
}
|
||||
|
||||
} else if (ann.annotationType() == Where.List.class) {
|
||||
Where.List whereList = (Where.List) ann;
|
||||
for (Where where : whereList.value()) {
|
||||
final Platform[] platforms = where.platforms();
|
||||
if (platforms.length == 0) {
|
||||
fallback = where;
|
||||
} else if (matchPlatform(where.platforms(), platform)) {
|
||||
return where;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private boolean matchPlatform(Platform[] platforms, Platform match) {
|
||||
for (Platform platform : platforms) {
|
||||
if (platform == match) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package io.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import io.ebean.annotation.Identity;
|
||||
import io.ebean.annotation.IdentityGenerated;
|
||||
import io.ebean.annotation.IdentityType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
|
||||
public class DeployIdentityMode {
|
||||
|
||||
public static DeployIdentityMode auto() {
|
||||
return new DeployIdentityMode(IdType.AUTO);
|
||||
}
|
||||
|
||||
private IdType type;
|
||||
private IdentityGenerated generated;
|
||||
private int start;
|
||||
private int increment;
|
||||
private int cache;
|
||||
private String sequenceName;
|
||||
private boolean platformDefault;
|
||||
|
||||
public DeployIdentityMode(Identity id) {
|
||||
this.type = idType(id.type());
|
||||
this.generated = id.generated();
|
||||
this.start = id.start();
|
||||
this.increment = id.increment();
|
||||
this.cache = id.cache();
|
||||
this.sequenceName = id.sequenceName();
|
||||
}
|
||||
|
||||
private DeployIdentityMode(IdType type) {
|
||||
this.type = type;
|
||||
this.generated = IdentityGenerated.AUTO;
|
||||
this.sequenceName = "";
|
||||
this.start = 0;
|
||||
this.increment = 0;
|
||||
this.cache = 0;
|
||||
}
|
||||
|
||||
public void setPlatformType(IdType type) {
|
||||
this.type = type;
|
||||
this.platformDefault = true;
|
||||
}
|
||||
|
||||
public void setSequence(int initialValue, int allocationSize, String sequenceName) {
|
||||
this.start = initialValue;
|
||||
this.increment = allocationSize;
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
public void setSequenceGenerator(String genName) {
|
||||
if (sequenceName == null || sequenceName.isEmpty()) {
|
||||
sequenceName = genName;
|
||||
}
|
||||
}
|
||||
|
||||
public int setSequenceBatchMode(boolean sequenceBatchMode) {
|
||||
if (sequenceBatchMode) {
|
||||
// Ebean batch fetching multiple sequence values
|
||||
increment = 1;
|
||||
} else if (increment == 0) {
|
||||
// Use JPA default of 50
|
||||
increment = 50;
|
||||
}
|
||||
return increment;
|
||||
}
|
||||
|
||||
public void setIdType(IdType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public void setIncrement(int increment) {
|
||||
this.increment = increment;
|
||||
}
|
||||
|
||||
public void setSequenceName(String sequenceName) {
|
||||
this.sequenceName = sequenceName;
|
||||
}
|
||||
|
||||
public boolean isPlatformDefault() {
|
||||
return platformDefault;
|
||||
}
|
||||
|
||||
public IdType getIdType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public IdentityGenerated getGenerated() {
|
||||
return generated;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public int getIncrement() {
|
||||
return increment;
|
||||
}
|
||||
|
||||
public int getCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
public String getSequenceName() {
|
||||
return sequenceName;
|
||||
}
|
||||
|
||||
public boolean isSequence() {
|
||||
return type == IdType.SEQUENCE;
|
||||
}
|
||||
|
||||
public boolean isIdentity() {
|
||||
return type == IdType.IDENTITY;
|
||||
}
|
||||
|
||||
public boolean isExternal() {
|
||||
return type == IdType.EXTERNAL;
|
||||
}
|
||||
|
||||
public boolean isAuto() {
|
||||
return type == IdType.AUTO;
|
||||
}
|
||||
|
||||
private static IdType idType(IdentityType type) {
|
||||
switch (type) {
|
||||
case AUTO:
|
||||
return IdType.AUTO;
|
||||
case SEQUENCE:
|
||||
return IdType.SEQUENCE;
|
||||
case IDENTITY:
|
||||
return IdType.IDENTITY;
|
||||
case APPLICATION:
|
||||
return IdType.EXTERNAL;
|
||||
default:
|
||||
throw new IllegalStateException("type " + type + " not expected?");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
prop.setMapKey(mapKey.name());
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
Where where = prop.getMetaAnnotationWhere(platform);
|
||||
if (where != null) {
|
||||
prop.setExtraWhere(where.clause());
|
||||
}
|
||||
@@ -138,8 +138,8 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
|
||||
Set<JoinColumn> joinColumns = getAll(prop, JoinColumn.class);
|
||||
if (joinColumns != null) {
|
||||
Set<JoinColumn> joinColumns = annotationJoinColumns(prop);
|
||||
if (!joinColumns.isEmpty()) {
|
||||
prop.getTableJoin().addJoinColumn(util, true, joinColumns, beanTable);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
if (!elementCollection.targetClass().equals(void.class)) {
|
||||
prop.setTargetType(elementCollection.targetClass());
|
||||
}
|
||||
Column column = get(prop, Column.class);
|
||||
Column column = prop.getMetaAnnotation(Column.class);
|
||||
if (column != null) {
|
||||
prop.setDbColumn(column.name());
|
||||
prop.setDbLength(column.length());
|
||||
|
||||
@@ -82,7 +82,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
prop.setId();
|
||||
prop.setNullable(false);
|
||||
}
|
||||
Column column = get(prop, Column.class);
|
||||
Column column = prop.getMetaAnnotation(Column.class);
|
||||
if (column != null && !isEmpty(column.name())) {
|
||||
// have this in for AssocOnes used on
|
||||
// Sql based beans...
|
||||
@@ -100,7 +100,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
prop.setForeignKey(new PropertyForeignKey(dbForeignKey));
|
||||
}
|
||||
|
||||
Where where = get(prop, Where.class);
|
||||
Where where = prop.getMetaAnnotationWhere(platform);
|
||||
if (where != null) {
|
||||
// not expecting this to be used on assoc one properties
|
||||
prop.setExtraWhere(where.clause());
|
||||
@@ -131,12 +131,11 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
for (JoinColumn joinColumn : getAll(prop, JoinColumn.class)) {
|
||||
for (JoinColumn joinColumn : annotationJoinColumns(prop)) {
|
||||
setFromJoinColumn(prop, beanTable, joinColumn);
|
||||
checkForNoConstraint(prop, joinColumn);
|
||||
}
|
||||
|
||||
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
for (JoinColumn joinColumn : joinTable.joinColumns()) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user