Compare commits

..
Author SHA1 Message Date
Robin Bygrave 8115c5e230 [maven-release-plugin] prepare release avaje-ebeanorm-7.18.1 2016-07-11 21:31:25 +12:00
Robin Bygrave ad180c5531 No effective change - reduce test logging 2016-07-11 21:27:34 +12:00
Robin Bygrave b454f46dd4 Bump pom to 7.18.1-SNAPSHOT 2016-07-11 21:27:06 +12:00
Robin Bygrave 8a853b28f3 #772 - DB Migration DDL - alter table add column ... needs type conversion when using multiple platforms. e.g. varchar(20) ... convert to varchar2(20) for Oracle 2016-07-11 21:25:58 +12:00
Robin Bygrave a1be7ba5dd #771 - DB Migration DDL when using multiple platforms ... destination into sub directories rather than file suffix 2016-07-11 21:17:12 +12:00
Robin Bygrave 3914516793 #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:20:26 +12:00
Robin Bygrave 8c5854f77c #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:14:29 +12:00
Robin Bygrave 0bc5b94eae #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:08:26 +12:00
Robin Bygrave 12fa287f35 #769 - DB Migration DDL generation for UUID type when generating multiple platforms 2016-07-11 19:54:50 +12:00
Robin Bygrave 2991cb9ad1 #768 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @ManyToOne reference bean 2016-07-11 15:09:59 +12:00
Robin Bygrave 3b7f5496a8 #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 12:28:31 +12:00
Robin Bygrave 4be703ff6e #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 11:58:02 +12:00
Robin Bygrave d2c5765ac1 No effective change - tidy comments 2016-07-11 11:24:57 +12:00
Robin Bygrave aaf256b9be #766 - RawSql should automatically map column alias with underscore to camelCase ... so item_total should automatically map to bean property itemTotal 2016-07-08 23:44:11 +12:00
Robin Bygrave c7c6410cd9 #765 - ENH: Add ebean.xml with support for named RawSql, also adds EbeanServer.createNamedQuery() 2016-07-08 22:35:04 +12:00
Robin Bygrave 2c3c23725a No effective change - reformat code 2016-07-08 15:37:26 +12:00
Robin Bygrave 92069c0319 #764 - NPE on BeanDescriptorManager.processViewInvalidation(BeanDescriptorManager.java:385) 2016-07-08 15:34:43 +12:00
Robin Bygrave 630ad66ff1 #763 - Internal Code cleanup - remove redundant null checking etc 2016-07-08 15:01:39 +12:00
Robin Bygrave b732b390c7 [maven-release-plugin] prepare for next development iteration 2016-07-07 21:51:15 +12:00
Robin Bygrave 8c62fcdcb2 [maven-release-plugin] prepare release avaje-ebeanorm-7.17.1 2016-07-07 21:50:53 +12:00
Robin Bygrave e458f577fe No effective change - reduce logging for BeanDescriptorManager entity count message from INFO to DEBUG 2016-07-07 21:49:43 +12:00
Robin Bygrave 23434bab8c Bump pom to 7.17.1-SNAPSHOT 2016-07-07 21:45:40 +12:00
Robin Bygrave c47b5a1595 #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:43:15 +12:00
Robin Bygrave 411846347b #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:33:19 +12:00
Robin Bygrave 3722d19424 #761 - Change default for persistBatchOnCascade to be platform specific rather than NONE 2016-07-07 21:19:08 +12:00
Robin Bygrave 04a7310e5d [maven-release-plugin] prepare for next development iteration 2016-07-06 12:27:45 +12:00
Robin Bygrave 3490e90f03 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.3 2016-07-06 12:27:26 +12:00
Robin Bygrave d89817a5c5 #760 - Change @Transactional(batchSize=100) ... to imply batch mode (remove need to also specify batch=PersistBatch.ALL) 2016-07-06 12:26:18 +12:00
Robin Bygrave db1ba5f20e #759 - Use default value of 100 for JDBC buffer fetchSize for findEach() / findEachWhile() - Add global defaults ServerConfig jdbcFetchSizeFindEach, jdbcFetchSizeFindList 2016-07-04 21:56:33 +12:00
Robin Bygrave 4f9a9a5094 No effective change - remove unused method 2016-06-30 14:45:06 +12:00
Robin Bygrave 1c6ac1289d #758 - DDL - @Index(unique=true) on field/property not creating unique index 2016-06-30 13:59:38 +12:00
Robin Bygrave b96be84106 Merge branch 'master' of github.com:ebean-orm/avaje-ebeanorm 2016-06-30 05:38:32 +12:00
Robin Bygrave 3c40293183 #757 - Reduce logging of Commit message of org.avaje.ebean.TXN from INFO to DEBUG 2016-06-30 05:38:16 +12:00
Rob BygraveandGitHub a9a6031986 Merge pull request #755 from MatthewMerrill/patch-1
Javadoc typo in SqlUpdate
2016-06-28 09:32:27 +12:00
Robin Bygrave b82085da42 [maven-release-plugin] prepare for next development iteration 2016-06-28 07:13:26 +12:00
Robin Bygrave 9a17a7752c [maven-release-plugin] prepare release avaje-ebeanorm-7.16.2 2016-06-28 07:13:06 +12:00
Robin Bygrave 92474c2b24 #754 - Logging output for bind log of UpdateQuery does not include bind values for set clause ... 2016-06-28 07:10:59 +12:00
Robin Bygrave 9a00b9df0e #753 - @History "as of" query errors when executed a second time - invalid bind parameter 2016-06-28 07:04:39 +12:00
Robin Bygrave 697f67c14a #753 - @History "as of" query errors when executed a second time - invalid bind parameter 2016-06-28 06:46:16 +12:00
Matthew MerrillandGitHub 2c34bc1636 Example code typo
Change "there where" to "there were" and added space between modify count and next word.
2016-06-27 09:07:45 -07:00
Robin Bygrave 1f9ccf1c8b [maven-release-plugin] prepare for next development iteration 2016-06-23 21:39:03 +12:00
Robin Bygrave a1f10b8704 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.1 2016-06-23 21:38:42 +12:00
Robin Bygrave 3c21950b91 Bump pom to 7.16.1-SNAPSHOT 2016-06-23 21:36:57 +12:00
Robin Bygrave 3b45308ac7 Merge branch 'DevFactory-release/collection-isempty-1' 2016-06-23 13:40:23 +12:00
Robin Bygrave 00e69e1b5d No effective change - remove extra whitespace 2016-06-23 13:39:34 +12:00
Robin Bygrave 11b3f7a813 Merge branch 'release/collection-isempty-1' of https://github.com/DevFactory/avaje-ebeanorm into DevFactory-release/collection-isempty-1
Conflicts:
	src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
2016-06-23 13:24:58 +12:00
Robin Bygrave 2185c8a886 #752 - Refactor: SQL generation for @History support with Postgres, MySql (views/triggers based) such that it more closely aligns with SQL 2011 based SQL 2016-06-23 11:33:01 +12:00
Robin Bygrave f8bda05b37 #751 - @History with @ManyToMany ... intersection table not getting associated history support 2016-06-23 11:05:16 +12:00
Artyom Melnikov 0a3b819991 Fixing squid:S1155 - Collection.isEmpty() should be used to test for emptiness 2016-06-22 13:43:15 +03:00
Rob BygraveandGitHub 5c8b1eb3bb Merge pull request #748 from yuqiyi/master
fix DeployBeanDescriptor.java of the method setView
2016-06-22 22:21:52 +12:00
yuqiyi 824f6dcc7e fix DeployBeanDescriptor.java of the method setView 2016-06-22 18:11:37 +08:00
Robin Bygrave 06e23b85ad #747 - @History findVersionsBetween query with Oracle has incorrect ordering 2016-06-22 20:16:35 +12:00
Robin Bygrave 09219c759b [maven-release-plugin] prepare for next development iteration 2016-06-20 22:57:36 +12:00
182 changed files with 2923 additions and 1246 deletions
+3 -3
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>7.15.1</version>
<version>7.18.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -37,7 +37,7 @@
<scm>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
<tag>avaje-ebeanorm-7.15.1</tag>
<tag>avaje-ebeanorm-7.18.1</tag>
</scm>
<dependencies>
@@ -177,7 +177,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.189</version>
<version>1.4.192</version>
<scope>provided</scope>
</dependency>
@@ -38,6 +38,11 @@ public interface BeanState {
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* Return true if the bean has lazy loading disabled.
*/
boolean isDisableLazyLoad();
/**
* Set the loaded state of the property given it's name.
*
@@ -49,7 +49,7 @@ final class DRawSqlColumnsParser {
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<String>(split.length);
for (int i = 0; i < split.length; i++) {
if (split[i].trim().length() > 0) {
if (!split[i].trim().isEmpty()) {
tmp.add(split[i].trim());
}
}
+17 -2
View File
@@ -161,7 +161,7 @@ public final class Ebean {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
if (defaultName != null && defaultName.trim().length() > 0) {
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
}
@@ -182,7 +182,7 @@ public final class Ebean {
}
private EbeanServer get(String name) {
if (name == null || name.length() == 0) {
if (name == null || name.isEmpty()) {
return defaultServer;
}
// non-synchronized read
@@ -945,6 +945,21 @@ public final class Ebean {
return serverMgr.getDefaultServer().createCsvReader(beanType);
}
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
}
/**
* Create a query for a type of entity bean.
* <p>
@@ -199,6 +199,19 @@ public interface EbeanServer {
*/
<T> UpdateQuery<T> update(Class<T> beanType);
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
/**
* Create a query for an entity bean and synonym for {@link #find(Class)}.
*
+1 -1
View File
@@ -400,6 +400,6 @@ public final class OrderBy<T> implements Serializable {
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
}
@@ -78,6 +78,6 @@ class PrimaryServer {
* Return true if the string is null or empty.
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
}
+2 -2
View File
@@ -606,9 +606,9 @@ public final class RawSql implements Serializable {
}
}
private static String derivePropertyName(String dbAlias, String dbColumn) {
protected static String derivePropertyName(String dbAlias, String dbColumn) {
if (dbAlias != null) {
return dbAlias;
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
}
int dotPos = dbColumn.indexOf('.');
if (dotPos > -1) {
+2 -2
View File
@@ -26,7 +26,7 @@ package com.avaje.ebean;
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = &quot;There where &quot; + modifiedCount + &quot;rows updated&quot;
* String msg = &quot;There were &quot; + modifiedCount + &quot; rows updated&quot;
* </pre>
*
* @see Update
@@ -143,4 +143,4 @@ public interface SqlUpdate {
*/
SqlUpdate setNullParameter(String name, int jdbcType);
}
}
+39 -22
View File
@@ -16,7 +16,7 @@ import java.util.ArrayList;
* This object is used internally with the enhancement of a method with
* Transactional annotation.
* </p>
*
*
* @see TxCallable
* @see TxRunnable
* @see Ebean#execute(TxScope, TxCallable)
@@ -44,27 +44,6 @@ public final class TxScope {
ArrayList<Class<? extends Throwable>> noRollbackFor;
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Helper method to create a TxScope with REQUIRES.
*/
@@ -130,6 +109,44 @@ public final class TxScope {
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
}
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
*/
public void checkBatchMode() {
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
batch = PersistBatch.ALL;
}
}
/**
* Return true if the mode is considered not set.
*/
private boolean notSet(PersistBatch batchMode) {
return batchMode == null || batchMode == PersistBatch.INHERIT;
}
/**
* Return the transaction type.
*/
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Set the disableLazyLoad state.
*/
void setDisableLazyLoad(boolean disableLazyLoad);
/**
* Load bean from another collection.
*/
@@ -20,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected boolean readOnly;
protected boolean disableLazyLoad;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
*/
@@ -84,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
this.filterMany = filterMany;
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoad) {
this.disableLazyLoad = disableLazyLoad;
}
protected void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
@@ -102,7 +102,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
@@ -114,7 +114,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void init() {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
if (disableLazyLoad) {
list = new ArrayList<E>();
} else {
lazyLoadCollection(false);
}
}
}
}
@@ -274,7 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
return s == null || s.trim().isEmpty();
}
/**
@@ -163,6 +163,17 @@ public class ServerConfig {
*/
private int databaseSequenceBatchSize = 20;
/**
* JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver.
*/
private int jdbcFetchSizeFindList;
/**
* JDBC fetchSize hint when using findEach/findEachWhile. Defaults to 100. Note that this does
* not apply to MySql as that gets special treatment (forward only etc).
*/
private int jdbcFetchSizeFindEach = 100;
/**
* Suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
@@ -187,9 +198,11 @@ public class ServerConfig {
private PersistBatch persistBatch = PersistBatch.NONE;
/**
* Use for per request batch mode.
* Use for cascade persist JDBC batch mode. INHERIT means use the platform default
* which is ALL except for SQL Server where it is NONE (as getGeneratedKeys isn't
* supported on SQL Server with JDBC batch).
*/
private PersistBatch persistBatchOnCascade = PersistBatch.NONE;
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 20;
@@ -307,7 +320,7 @@ public class ServerConfig {
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private DbUuid dbUuid = DbUuid.AUTO;
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
private List<IdGenerator> idGenerators = new ArrayList<IdGenerator>();
@@ -719,6 +732,34 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the default JDBC fetchSize hint for findList queries.
*/
public int getJdbcFetchSizeFindList() {
return jdbcFetchSizeFindList;
}
/**
* Set the default JDBC fetchSize hint for findList queries.
*/
public void setJdbcFetchSizeFindList(int jdbcFetchSizeFindList) {
this.jdbcFetchSizeFindList = jdbcFetchSizeFindList;
}
/**
* Return the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public int getJdbcFetchSizeFindEach() {
return jdbcFetchSizeFindEach;
}
/**
* Set the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public void setJdbcFetchSizeFindEach(int jdbcFetchSizeFindEach) {
this.jdbcFetchSizeFindEach = jdbcFetchSizeFindEach;
}
/**
* Return the ChangeLogPrepare.
* <p>
@@ -2405,6 +2446,8 @@ public class ServerConfig {
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
@@ -2460,7 +2503,7 @@ public class ServerConfig {
String[] split = classNames.split("[ ,;]");
for (int i = 0; i < split.length; i++) {
String cn = split[i].trim();
if (cn.length() > 0 && !"class".equalsIgnoreCase(cn)) {
if (!cn.isEmpty() && !"class".equalsIgnoreCase(cn)) {
try {
classes.add(Class.forName(cn));
} catch (ClassNotFoundException e) {
@@ -2489,13 +2532,14 @@ public class ServerConfig {
/**
* Return the PersistBatch mode to use for 'batchOnCascade' taking into account if the database
* platform supports getGeneratedKeys in batch mode.
* <p>
* Used to effectively turn off batchOnCascade for SQL Server - still allows explicit batch mode.
* </p>
*/
public PersistBatch appliedPersistBatchOnCascade() {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
if (persistBatchOnCascade == PersistBatch.INHERIT) {
// use the platform default (ALL except SQL Server which has NONE)
return databasePlatform.getPersistBatchOnCascade();
}
return persistBatchOnCascade;
}
/**
@@ -2571,18 +2615,45 @@ public class ServerConfig {
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres.
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
AUTO,
AUTO_VARCHAR(true, false),
/**
* Store using DB VARCHAR.
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
*/
VARCHAR,
AUTO_BINARY(true, true),
/**
* Store using DB BINARY.
* Store using DB VARCHAR(40).
*/
BINARY
VARCHAR(false, false),
/**
* Store using DB BINARY(16).
*/
BINARY(false, true);
boolean nativeType;
boolean binary;
DbUuid(boolean nativeType, boolean binary) {
this.nativeType = nativeType;
this.binary = binary;
}
/**
* Return true if native UUID type is preferred.
*/
public boolean useNativeType() {
return nativeType;
}
/**
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
*/
public boolean useBinary() {
return binary;
}
}
}
@@ -146,6 +146,6 @@ public final class TableName {
* @return true, if is valid
*/
public boolean isValid() {
return name != null && name.length() > 0;
return name != null && !name.isEmpty();
}
}
@@ -2,6 +2,7 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
@@ -155,11 +156,9 @@ public class DatabasePlatform {
protected boolean forwardOnlyHintOnFindIterate;
/**
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
* batch mode (meaning for batch inserts you should explicitly turn off
* getGeneratedKeys - joy).
* By default we use JDBC batch when cascading (except for SQL Server).
*/
protected boolean disallowBatchOnCascade;
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
protected PlatformDdl platformDdl;
@@ -183,8 +182,11 @@ public class DatabasePlatform {
public DatabasePlatform() {
}
public void configure(Properties properties) {
// by default do nothing
/**
* Configure UUID Storage etc based on ServerConfig settings.
*/
public void configure(ServerConfig serverConfig) {
dbTypeMap.config(nativeUuidType, serverConfig.getDbUuid());
}
/**
@@ -492,7 +494,7 @@ public class DatabasePlatform {
*/
public String convertQuotedIdentifiers(String dbName) {
// Ignore null values e.g. schema name or catalog
if (dbName != null && dbName.length() > 0) {
if (dbName != null && !dbName.isEmpty()) {
if (dbName.charAt(0) == BACK_TICK) {
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
@@ -542,14 +544,10 @@ public class DatabasePlatform {
}
/**
* Return true if the persistBatchOnCascade setting should be ignored.
* <p>
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
* so can't really be transparently used.
* </p>
* Return the platform default JDBC batch mode for persist cascade.
*/
public boolean isDisallowBatchOnCascade() {
return disallowBatchOnCascade;
public PersistBatch getPersistBatchOnCascade() {
return persistBatchOnCascade;
}
/**
@@ -6,11 +6,13 @@ package com.avaje.ebean.config.dbplatform;
public interface DbHistorySupport {
/**
* Return true if the 'As of' predicate is part of the from clause
* (more standard sql2011). So true for Oracle total recall and false
* for Postgres and MySql (where we use views and history tables).
* Return true if the implementation is SQL2011 standards based.
* <p>
* Non standards based means we need to add additional predicates into the
* JOIN ON clause and add an additional predicate for the base table.
* </p>
*/
boolean isBindWithFromClause();
boolean isStandardsBased();
/**
* Return the number of columns bound in a 'As Of' predicate.
@@ -5,11 +5,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbStandardHistorySupport implements DbHistorySupport {
/**
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return true;
}
@@ -152,4 +152,10 @@ public class DbType {
return sb.toString();
}
/**
* Create a copy of the type with a new default length.
*/
public DbType withLength(int defaultLength) {
return new DbType(name, defaultLength);
}
}
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.ServerConfig;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
@@ -9,6 +11,8 @@ import java.util.Map;
*/
public class DbTypeMap {
private static final DbType UUID_NATIVE = new DbType("uuid", false);
private static final DbType UUID_PLACEHOLDER = new DbType("uuidPlaceholder");
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
@@ -66,7 +70,7 @@ public class DbTypeMap {
/**
* Return the DbTypeMap with standard (not platform specific) types.
*
* <p>
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
* These types get translated to specific database platform types during DDL generation.
*/
@@ -104,8 +108,6 @@ public class DbTypeMap {
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
// DB native UUID support (H2 and Postgres)
put(DbType.UUID, new DbType("uuid"));
put(Types.ARRAY, new DbType("array"));
if (logicalTypes) {
@@ -116,6 +118,7 @@ public class DbTypeMap {
put(DbType.JSONClob, new DbType("jsonclob"));
put(DbType.JSONBlob, new DbType("jsonblob"));
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
} else {
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
@@ -123,6 +126,7 @@ public class DbTypeMap {
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
put(DbType.UUID, UUID_PLACEHOLDER);
}
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
@@ -133,7 +137,6 @@ public class DbTypeMap {
put(Types.DATE, new DbType("date"));
put(Types.TIME, new DbType("time"));
put(Types.TIMESTAMP, new DbType("timestamp"));
}
/**
@@ -191,4 +194,17 @@ public class DbTypeMap {
public DbType get(int jdbcType) {
return typeMap.get(jdbcType);
}
/**
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
*/
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
if (nativeUuidType && dbUuid.useNativeType()) {
put(DbType.UUID, UUID_NATIVE);
} else if (dbUuid.useBinary()) {
put(DbType.UUID, get(Types.BINARY).withLength(16));
} else {
put(DbType.UUID, get(Types.VARCHAR).withLength(40));
}
}
}
@@ -9,11 +9,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbViewHistorySupport implements DbHistorySupport {
/**
* Return false for view based implementations where we append extra 'as of' predicates to the end.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return false;
}
@@ -9,9 +9,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* H2 database trigger used to populate history tables to support the @History feature.
@@ -54,7 +52,6 @@ public class H2HistoryTrigger implements Trigger {
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
int count = 0;
List<String> columns = new ArrayList<String>();
while (rs.next()) {
if (++count > 1) {
insertSql.append(",");
@@ -66,7 +63,6 @@ public class H2HistoryTrigger implements Trigger {
this.effectEndPosition = count - 1;
}
insertSql.append(columnName);
columns.add(columnName);
}
insertSql.append(") values (");
for (int i = 0; i < count; i++) {
@@ -1,9 +1,11 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
import java.util.Properties;
/**
* H2 specific platform.
@@ -19,9 +21,7 @@ public class H2Platform extends DatabasePlatform {
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
this.dbIdentity.setIdType(IdType.SEQUENCE);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
@@ -34,6 +34,18 @@ public class H2Platform extends DatabasePlatform {
// so no changes to dbTypeMap required
}
@Override
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String idType = properties.getProperty("ebean.h2.idtype");
if (idType != null) {
this.dbIdentity.setIdType(IdType.valueOf(idType));
}
}
}
/**
* Return a H2 specific sequence IdGenerator that supports batch fetching
* sequence values.
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
import java.sql.Types;
/**
@@ -18,6 +20,7 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
public MsSqlServer2000Platform() {
super();
this.name = "mssqlserver2000";
this.persistBatchOnCascade = PersistBatch.NONE;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
@@ -1,5 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
import java.sql.Types;
@@ -21,7 +22,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
this.name = "mssqlserver2005";
// effectively disable persistBatchOnCascade mode for SQL Server
// due to lack of support for getGeneratedKeys in batch mode
this.disallowBatchOnCascade = true;
this.persistBatchOnCascade = PersistBatch.NONE;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
@@ -64,12 +64,15 @@ public class PostgresPlatform extends DatabasePlatform {
}
@Override
public void configure(Properties properties) {
super.configure(properties);
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
}
}
}
@@ -164,9 +164,6 @@ public class DbMigration {
* </p>
*/
public void addPlatform(DbPlatformName platform, String prefix) {
if (!prefix.endsWith("-")) {
prefix += "-";
}
platforms.add(new Pair(getPlatform(platform), prefix));
}
@@ -204,13 +201,20 @@ public class DbMigration {
// use this flag to stop other plugins like full DDL generation
if (!online) {
DbOffline.setRunningMigration();
DbOffline.setGenerateMigration();
if (databasePlatform == null || !platforms.isEmpty()) {
// for multiple platform generation set the general platform
// to H2 so that it runs offline without DB connection
setPlatform(DbPlatformName.H2);
}
}
setDefaults();
try {
Request request = createRequest();
generateExtraDdl(request);
if (platforms.isEmpty()) {
generateExtraDdl(request.migrationDir, databasePlatform);
}
String pendingVersion = generatePendingDrop();
if (pendingVersion != null) {
@@ -234,15 +238,15 @@ public class DbMigration {
* migration runner.
* </p>
*/
private void generateExtraDdl(Request request) throws IOException {
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
if (databasePlatform != null) {
if (dbPlatform != null) {
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (ExtraDdlXmlReader.matchPlatform(databasePlatform.getName(), script.getPlatforms())) {
writeExtraDdl(request, script);
if (ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
writeExtraDdl(migrationDir, script);
}
}
}
@@ -252,13 +256,13 @@ public class DbMigration {
/**
* Write (or override) the "repeatable" migration script.
*/
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
String fullName = repeatableMigrationName(script.getName());
logger.info("writing repeatable script {}", fullName);
File file = new File(request.migrationDir, fullName);
File file = new File(migrationDir, fullName);
FileWriter writer = new FileWriter(file);
writer.write(script.getValue());
writer.flush();
@@ -363,14 +367,16 @@ public class DbMigration {
logger.warn("migration already exists, not generating DDL");
} else {
if (databasePlatform != null) {
if (!platforms.isEmpty()) {
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
} else if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
}
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
}
}
@@ -426,7 +432,10 @@ public class DbMigration {
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter platformWriter = createDdlWriter(pair);
platformWriter.processMigration(dbMigration, platformBuffer, writePath, fullVersion);
File subPath = platformWriter.subPath(writePath, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
generateExtraDdl(subPath, pair.platform);
}
}
@@ -14,7 +14,7 @@ public class DbOffline {
private static final String KEY = "ebean.dboffline";
private static boolean runningMigration;
private static boolean generateMigration;
/**
* Set the platform to use when creating the next EbeanServer instance.
@@ -55,23 +55,23 @@ public class DbOffline {
* Return true if the migration is running. This typically means don't run the
* plugins like full DDL generation.
*/
public static boolean isRunningMigration() {
return runningMigration;
public static boolean isGenerateMigration() {
return generateMigration;
}
/**
* Called when the migration is running is order to stop other plugins
* like the full DDL generation from executing.
*/
public static void setRunningMigration() {
runningMigration = true;
public static void setGenerateMigration() {
generateMigration = true;
}
/**
* Reset the offline platform and runningMigration flag.
*/
public static void reset() {
runningMigration = false;
generateMigration = false;
System.clearProperty(KEY);
logger.debug("reset");
}
@@ -831,9 +831,10 @@ public class BaseTableDdl implements TableDdl {
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable) throws IOException {
String convertedType = platformDdl.convert(column.getType(), false);
buffer.append("alter table ").append(tableName)
.append(" add column ").append(column.getName())
.append(" ").append(column.getType());
.append(" ").append(convertedType);
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
@@ -26,6 +26,8 @@ import java.util.List;
*/
public class PlatformDdl {
protected final DatabasePlatform platform;
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
/**
@@ -98,6 +100,7 @@ public class PlatformDdl {
protected final DbDefaultValue dbDefaultValue;
public PlatformDdl(DatabasePlatform platform) {
this.platform = platform;
this.dbIdentity = platform.getDbIdentity();
this.dbDefaultValue = platform.getDbDefaultValue();
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
@@ -107,6 +110,7 @@ public class PlatformDdl {
* Set configuration options.
*/
public void configure(ServerConfig serverConfig) {
platform.configure(serverConfig);
historyDdl.configure(serverConfig, this);
naming = serverConfig.getConstraintNaming();
}
@@ -11,7 +11,6 @@ import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import java.io.IOException;
import java.util.List;
/**
* Reads EbeanServer bean descriptors to build the current model.
@@ -24,6 +23,8 @@ public class CurrentModel {
private final DbConstraintNaming.MaxLength maxLength;
private final boolean platformTypes;
private ModelContainer model;
private ChangeSet changeSet;
@@ -31,32 +32,31 @@ public class CurrentModel {
private DdlWrite write;
/**
* Construct with a given EbeanServer instance.
* Construct with a given EbeanServer instance for DDL create all generation, not migration.
*/
public CurrentModel(SpiEbeanServer server) {
this(server, server.getServerConfig().getConstraintNaming());
this(server, server.getServerConfig().getConstraintNaming(), true);
}
/**
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
* <p>
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* </p>
*/
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
this(server, constraintNaming, false);
}
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = maxLength(server, constraintNaming);
this.platformTypes = platformTypes;
}
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
}
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
if (naming.getMaxLength() != null) {
return naming.getMaxLength();
@@ -73,7 +73,7 @@ public class CurrentModel {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
@@ -104,7 +104,7 @@ public class MTable {
/**
* Compound unique constraints.
*/
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
private List<MCompoundUniqueConstraint> uniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
/**
* Compound foreign keys.
@@ -216,7 +216,7 @@ public class MTable {
createTable.getForeignKey().add(compoundKey.createForeignKey());
}
for (MCompoundUniqueConstraint constraint : compoundUniqueConstraints) {
for (MCompoundUniqueConstraint constraint : uniqueConstraints) {
UniqueConstraint uq = new UniqueConstraint();
uq.setName(constraint.getName());
String[] columns = constraint.getColumns();
@@ -404,8 +404,8 @@ public class MTable {
return columns;
}
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
return compoundUniqueConstraints;
public List<MCompoundUniqueConstraint> getUniqueConstraints() {
return uniqueConstraints;
}
public List<MCompoundForeignKey> getCompoundKeys() {
@@ -476,21 +476,21 @@ public class MTable {
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
String[] cols = new String[columns.size()];
for (int i = 0; i < columns.size(); i++) {
cols[i] = columns.get(i).getName();
}
addCompoundUniqueConstraint(cols, oneToOne, constraintName);
addUniqueConstraint(cols, oneToOne, constraintName);
}
/**
@@ -9,6 +9,8 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
import com.avaje.ebean.dbmigration.migration.Migration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileWriter;
@@ -21,6 +23,8 @@ import java.util.List;
*/
public class PlatformDdlWriter {
private static final Logger logger = LoggerFactory.getLogger(PlatformDdlWriter.class);
private final ServerConfig serverConfig;
private final DatabasePlatform platform;
@@ -67,7 +71,7 @@ public class PlatformDdlWriter {
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
if (!write.isApplyEmpty()) {
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
FileWriter applyWriter = createWriter(resourcePath, fullVersion, config.getApplySuffix());
try {
writeApplyDdl(applyWriter, write);
applyWriter.flush();
@@ -77,28 +81,12 @@ public class PlatformDdlWriter {
}
}
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
String fileName = fullVersion;
if (!platformPrefix.isEmpty()) {
fileName += "-"+platformPrefix;
}
if (subPath != null && !subPath.isEmpty()) {
path = subPath(path, subPath);
}
fileName += suffix;
File applyFile = new File(path, fileName);
File applyFile = new File(path, fullVersion + suffix);
return new FileWriter(applyFile);
}
protected File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
subPath.mkdirs();
}
return subPath;
}
/**
* Write the 'Apply' DDL buffers to the writer.
*/
@@ -127,4 +115,17 @@ public class PlatformDdlWriter {
return platform.createDdlHandler(serverConfig);
}
/**
* Return a sub directory (for multi-platform ddl generation).
*/
public File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
if (!subPath.mkdirs()) {
logger.error("failed to create directories for " + subPath.getAbsolutePath());
}
}
return subPath;
}
}
@@ -29,10 +29,13 @@ public class ModelBuildContext {
private final DbConstraintNaming.MaxLength maxLength;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
private final boolean platformTypes;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
this.model = model;
this.constraintNaming = naming;
this.maxLength = maxLength;
this.platformTypes = platformTypes;
}
/**
@@ -132,7 +135,7 @@ public class ModelBuildContext {
}
// can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar)
int dbType = p.getDbType();
int dbType = p.getDbType(platformTypes);
if (dbType == 0) {
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
}
@@ -85,6 +85,11 @@ public class ModelBuildIntersectionTable {
String tableName = intersectionTableJoin.getTable();
MTable table = new MTable(tableName);
if (!manyProp.isExcludedFromHistory()) {
if (localDesc.isHistorySupport()) {
table.setWithHistory(true);
}
}
table.setPkName(ctx.primaryKeyName(tableName));
TableJoinColumn[] columns = intersectionTableJoin.columns();
@@ -10,7 +10,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
@@ -45,30 +45,30 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
this.ctx = ctx;
this.table = table;
this.beanDescriptor = beanDescriptor;
addCompoundUniqueConstraint(beanDescriptor.getCompoundUniqueConstraints());
addIndexes(beanDescriptor.getIndexDefinitions());
}
/**
* Add unique constraints defined via JPA UniqueConstraint annotations.
*/
private void addCompoundUniqueConstraint(CompoundUniqueConstraint[] constraints) {
private void addIndexes(IndexDefinition[] indexes) {
if (constraints != null) {
for (int i = 0; i < constraints.length; i++) {
CompoundUniqueConstraint constraint = constraints[i];
String[] columns = constraint.getColumns();
if (indexes != null) {
for (int i = 0; i < indexes.length; i++) {
IndexDefinition index = indexes[i];
String[] columns = index.getColumns();
indexSet.add(columns);
if (constraint.isUnique()) {
String uqName = constraint.getName();
if (index.isUnique()) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
uqName = determineUniqueConstraintName(columns);
}
table.addCompoundUniqueConstraint(columns, false, uqName);
table.addUniqueConstraint(columns, false, uqName);
} else {
// 'just' an index (not a unique constraint)
String idxName = constraint.getName();
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(columns);
}
@@ -216,7 +216,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
} else {
String uqName = determineUniqueConstraintName(p.getName());
table.addCompoundUniqueConstraint(modelColumns, true, uqName);
table.addUniqueConstraint(modelColumns, true, uqName);
indexSetAdd(modelColumns);
}
}
@@ -260,15 +260,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
}
String indexName = p.getIndexName();
if (indexName != null) {
// single column non-unique index
if (indexName.trim().isEmpty()) {
indexName = determineIndexName(col.getName());
}
ctx.addIndex(indexName, table.getName(), p.getDbColumn());
}
lastColumn = col;
table.addColumn(col);
}
@@ -109,7 +109,7 @@ public class PathProperties implements FetchPath {
String path = entry.getKey();
String props = entry.getValue().getPropertiesAsString();
if (path == null || path.length() == 0) {
if (path == null || path.isEmpty()) {
query.select(props);
} else {
query.fetch(path, props);
@@ -108,7 +108,7 @@ class PathPropertiesParser {
private void addCurrentProperty() {
String w = currentWord();
if (w.length() > 0) {
if (!w.isEmpty()) {
currentPathProps.addProperty(w);
}
}
@@ -23,7 +23,7 @@ public final class TimeStringParser implements StringParser {
*/
@SuppressWarnings("deprecation")
public Object parse(String value) {
if (value == null || value.trim().length() == 0) {
if (value == null || value.trim().isEmpty()) {
return null;
}
@@ -12,9 +12,12 @@ public class CamelCaseHelper {
*/
public static String toCamelFromUnderscore(String underscore) {
StringBuilder result = new StringBuilder();
String[] vals = underscore.split("_");
if (vals.length == 1) {
return underscore;
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < vals.length; i++) {
String lower = vals[i].toLowerCase();
if (i > 0) {
@@ -123,7 +123,7 @@ public class StringHelper {
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<String, String>();
if ((allNameValuePairs == null) || (allNameValuePairs.length() == 0)) {
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
@@ -155,7 +155,7 @@ public class StringHelper {
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
/**
@@ -189,7 +189,7 @@ public class StringHelper {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (key.length() > 0) {
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
@@ -251,7 +251,7 @@ public class StringHelper {
if (endPos == -1) {
if (startPos <= str.length()) {
String lastValue = str.substring(startPos, str.length());
if (keepEmpties || lastValue.length() != 0) {
if (keepEmpties || !lastValue.isEmpty()) {
list.add(lastValue);
}
}
@@ -260,7 +260,7 @@ public class StringHelper {
} else {
// get the delimited value... add it..
String value = str.substring(startPos, endPos);
if (keepEmpties || value.length() != 0) {
if (keepEmpties || !value.isEmpty()) {
list.add(value);
}
// recursively search as we are not at the end yet...
@@ -398,7 +398,7 @@ public class StringHelper {
int additionalSize, int startPos, int endPos) {
if (source == null) {
return source;
return null;
}
char match0 = match.charAt(0);
@@ -223,14 +223,14 @@ public interface SpiQuery<T> extends Query<T> {
Timestamp getAsOf();
/**
* Add a table alias for a @History entity involved in a 'As Of' query.
* Increment the counter of tables used in 'As Of' query.
*/
void addAsOfTableAlias(String tableAlias);
void incrementAsOfTableCount();
/**
* Return the list of table alias involved in a 'As Of' query that have @History support.
* Return the table alias used for the base table.
*/
List<String> getAsOfTableAlias();
int getAsOfTableCount();
void addSoftDeletePredicate(String softDeletePredicate);
@@ -564,6 +564,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
boolean tuneFetchProperties(OrmQueryDetail detail);
/**
* If this is a RawSql based entity set the default RawSql if not set.
*/
void setDefaultRawSqlIfRequired();
/**
* Set to true if this query has been tuned by autoTune.
*/
@@ -625,6 +630,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
void setGeneratedSql(String generatedSql);
/**
* Set the JDBC fetchSize buffer hint if not explicitly set.
*/
void setDefaultFetchBuffer(int fetchSize);
/**
* Return the hint for Statement.setFetchSize().
*/
@@ -40,7 +40,7 @@ public class ExtraDdlXmlReader {
* @param platforms The platforms (comma delimited) this script should run for
*/
public static boolean matchPlatform(String platformName, String platforms) {
if (platforms == null || platforms.trim().length() == 0) {
if (platforms == null || platforms.trim().isEmpty()) {
return true;
}
String[] names = platforms.split("[,;]");
@@ -45,9 +45,8 @@ public class ProfileOriginNodeUsage {
if (path != null) {
ElPropertyValue elGetValue = rootDesc.getElGetValue(path);
if (elGetValue == null) {
desc = null;
logger.warn("AutoTune: Can't find join for path[" + path + "] for " + rootDesc.getName());
return;
} else {
BeanProperty beanProperty = elGetValue.getBeanProperty();
if (beanProperty instanceof BeanPropertyAssoc<?>) {
@@ -14,14 +14,14 @@ import java.util.Set;
*/
public class DefaultBeanState implements BeanState {
private final EntityBean entityBean;
private final EntityBeanIntercept intercept;
public DefaultBeanState(EntityBean entityBean){
this.entityBean = entityBean;
this.intercept = entityBean._ebean_getIntercept();
}
private final EntityBean entityBean;
private final EntityBeanIntercept intercept;
public DefaultBeanState(EntityBean entityBean) {
this.entityBean = entityBean;
this.intercept = entityBean._ebean_getIntercept();
}
public void setPropertyLoaded(String propertyName, boolean loaded) {
intercept.setPropertyLoaded(propertyName, loaded);
@@ -31,52 +31,57 @@ public class DefaultBeanState implements BeanState {
return intercept.isReference();
}
public boolean isNew() {
return intercept.isNew();
}
public boolean isNewOrDirty() {
return intercept.isNewOrDirty();
}
public boolean isDirty() {
return intercept.isDirty();
}
public Set<String> getLoadedProps() {
return intercept.getLoadedPropertyNames();
}
public Set<String> getChangedProps() {
return intercept.getDirtyPropertyNames();
public boolean isNew() {
return intercept.isNew();
}
public Map<String,ValuePair> getDirtyValues() {
public boolean isNewOrDirty() {
return intercept.isNewOrDirty();
}
public boolean isDirty() {
return intercept.isDirty();
}
public Set<String> getLoadedProps() {
return intercept.getLoadedPropertyNames();
}
public Set<String> getChangedProps() {
return intercept.getDirtyPropertyNames();
}
public Map<String, ValuePair> getDirtyValues() {
return intercept.getDirtyValues();
}
public boolean isReadOnly() {
return intercept.isReadOnly();
}
public void setReadOnly(boolean readOnly){
intercept.setReadOnly(readOnly);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
entityBean.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
entityBean.removePropertyChangeListener(listener);
}
public void setLoaded() {
intercept.setLoaded();
}
public boolean isReadOnly() {
return intercept.isReadOnly();
}
public void setReadOnly(boolean readOnly) {
intercept.setReadOnly(readOnly);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
entityBean.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
entityBean.removePropertyChangeListener(listener);
}
public void setLoaded() {
intercept.setLoaded();
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoading) {
intercept.setDisableLazyLoad(disableLazyLoading);
}
@Override
public boolean isDisableLazyLoad() {
return intercept.isDisableLazyLoad();
}
}
@@ -122,22 +122,20 @@ public class DefaultContainer implements SpiContainer {
// generate and run DDL if required
// if there are any other tasks requiring action in their plugins, do them as well
if (!DbOffline.isRunningMigration()) {
if (!DbOffline.isGenerateMigration()) {
server.executePlugins(online);
}
// initialise prior to registering with clusterManager
server.initialise();
if (online) {
if (clusterManager.isClustering()) {
// register the server once it has been created
clusterManager.registerServer(server);
// initialise prior to registering with clusterManager
server.initialise();
if (online) {
if (clusterManager.isClustering()) {
// register the server once it has been created
clusterManager.registerServer(server);
}
}
// start any services after registering with clusterManager
server.start();
}
// start any services after registering with clusterManager
server.start();
DbOffline.reset();
return server;
}
@@ -244,7 +242,7 @@ public class DefaultContainer implements SpiContainer {
if (dbPlatform == null) {
DatabasePlatformFactory factory = new DatabasePlatformFactory();
DatabasePlatform db = factory.create(config);
db.configure(config.getProperties());
db.configure(config);
config.setDatabasePlatform(db);
logger.info("DatabasePlatform name:" + config.getName() + " platform:" + db.getName());
}
@@ -557,7 +557,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
InheritInfo inheritInfo = desc.getInheritInfo();
if (inheritInfo == null) {
return (T)desc.contextRef(pc, null, id);
return (T)desc.contextRef(pc, null, false, id);
}
BeanProperty idProp = desc.getIdProperty();
@@ -683,6 +683,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (txScope == null) {
// create a TxScope with default settings
txScope = new TxScope();
} else {
// check for implied batch mode via setting batchSize
txScope.checkBatchMode();
}
SpiTransaction suspended = null;
@@ -884,6 +887,21 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return createQuery(beanType);
}
@Override
public <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
if (desc == null) {
throw new PersistenceException(beanType.getName() + " is NOT an Entity Bean registered with this server?");
}
RawSql rawSql = desc.getNamedRawSql(namedQuery);
if (rawSql != null) {
DefaultOrmQuery<T> query = createQuery(beanType);
query.setRawSql(rawSql);
return query;
}
throw new PersistenceException("No named query called " + namedQuery + " for bean:" + beanType.getName());
}
public <T> DefaultOrmQuery<T> createQuery(Class<T> beanType) {
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
if (desc == null) {
@@ -942,6 +960,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private <T> SpiOrmQueryRequest<T> createQueryRequest(SpiQuery<T> query, Transaction t) {
query.setDefaultRawSqlIfRequired();
if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) {
// use deployment FetchType.LAZY/EAGER annotations
// to define the 'default' select clause
@@ -137,7 +137,7 @@ public class InternalConfiguration {
this.dataTimeZone = initDataTimeZone();
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
this.cQueryEngine = new CQueryEngine(databasePlatform, binder, asOfTableMapping, serverConfig.getAsOfSysPeriod(), draftTableMap);
this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
/**
@@ -235,7 +235,7 @@ public class InternalConfiguration {
if (historySupport == null) {
return new Binder(typeManager, 0, false, jsonHandler, dataTimeZone);
}
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isBindWithFromClause(), jsonHandler, dataTimeZone);
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isStandardsBased(), jsonHandler, dataTimeZone);
}
/**
@@ -513,4 +513,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public boolean isAuditReads() {
return !query.isDisableReadAudit() && beanDescriptor.isReadAuditing();
}
/**
* Return the base table alias for this query.
*/
public String getBaseTableAlias() {
return query.getAlias() == null ? beanDescriptor.getBaseTableAlias() : query.getAlias();
}
/**
* Set the JDBC buffer fetchSize hint if not set explicitly.
*/
public void setDefaultFetchBuffer(int fetchSize) {
query.setDefaultFetchBuffer(fetchSize);
}
}
@@ -548,7 +548,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(Boolean.FALSE, getBeanId(), null);
return beanDescriptor.createReference(Boolean.FALSE, false, getBeanId(), null);
}
/**
@@ -46,9 +46,11 @@ abstract class AssocOneHelp {
return existing;
}
Object ref = target.contextRef(pc, ctx.isReadOnly(), id);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
boolean disableLazyLoading = ctx.isDisableLazyLoading();
Object ref = target.contextRef(pc, ctx.isReadOnly(), disableLazyLoading, id);
if (!disableLazyLoading) {
ctx.register(property.name, ((EntityBean) ref)._ebean_getIntercept());
}
return ref;
}
@@ -53,9 +53,11 @@ class AssocOneHelpRefInherit extends AssocOneHelp {
}
// for inheritance hierarchy create the correct type for this row...
Object ref = desc.contextRef(pc, ctx.isReadOnly(), id);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
boolean disableLazyLoading = ctx.isDisableLazyLoading();
Object ref = desc.contextRef(pc, ctx.isReadOnly(), disableLazyLoading, id);
if (disableLazyLoading) {
ctx.register(property.name, ((EntityBean) ref)._ebean_getIntercept());
}
return ref;
}
@@ -109,6 +109,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
private final ConcurrentHashMap<String, ElComparator<T>> comparatorCache = new ConcurrentHashMap<String, ElComparator<T>>();
private final Map<String, RawSql> namedRawSql;
public void merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
@@ -176,7 +178,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
*/
private final ConcurrencyMode concurrencyMode;
private final CompoundUniqueConstraint[] compoundUniqueConstraints;
private final IndexDefinition[] indexDefinitions;
private final String[] dependentTables;
@@ -412,6 +414,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
this.rootBeanType = PersistenceContextUtil.root(beanType);
this.prototypeEntityBean = createPrototypeEntityBean(beanType);
this.namedRawSql = deploy.getNamedRawSql();
this.inheritInfo = deploy.getInheritInfo();
this.beanFinder = deploy.getBeanFinder();
@@ -431,7 +434,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
this.concurrencyMode = deploy.getConcurrencyMode();
this.updateChangesOnly = deploy.isUpdateChangesOnly();
this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints();
this.indexDefinitions = deploy.getIndexDefinitions();
this.readAuditing = deploy.isReadAuditing();
this.draftable = deploy.isDraftable();
@@ -443,7 +446,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
this.baseTableVersionsBetween = deploy.getBaseTableVersionsBetween();
this.dependentTables = deploy.getDependentTables();
this.dbComment = deploy.getDbComment();
this.autoTunable = EntityType.ORM.equals(entityType) && (beanFinder == null);
this.autoTunable = EntityType.ORM == entityType && (beanFinder == null);
// helper object used to derive lists of properties
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
@@ -985,6 +988,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
return this;
}
/**
* Return the named RawSql query.
*/
public RawSql getNamedRawSql(String named) {
return namedRawSql.get(named);
}
/**
* Return the type of DocStoreMode that should occur for this type of persist request
* given the transactions requested mode.
@@ -1559,9 +1569,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* Create a reference bean based on the id.
*/
@SuppressWarnings("unchecked")
public T createReference(Boolean readOnly, Object id, PersistenceContext pc) {
public T createReference(Boolean readOnly, boolean disableLazyLoad, Object id, PersistenceContext pc) {
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
if (cacheSharableBeans && !disableLazyLoad && !Boolean.FALSE.equals(readOnly)) {
CachedBeanData d = cacheHelp.beanCacheGetData(id);
if (d != null) {
Object shareableBean = d.getSharableBean();
@@ -1578,7 +1588,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
id = convertSetId(id, eb);
EntityBeanIntercept ebi = eb._ebean_getIntercept();
ebi.setBeanLoader(ebeanServer);
if (disableLazyLoad) {
ebi.setDisableLazyLoad(true);
} else {
ebi.setBeanLoader(ebeanServer);
}
ebi.setReference(idPropertyIndex);
if (Boolean.TRUE == readOnly) {
ebi.setReadOnly(true);
@@ -1750,8 +1764,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Create a reference bean and put it in the persistence context (and return it).
*/
public Object contextRef(PersistenceContext pc, Boolean readOnly, Object id) {
return createReference(readOnly, id, pc);
public Object contextRef(PersistenceContext pc, Boolean readOnly, boolean disableLazyLoad, Object id) {
return createReference(readOnly, disableLazyLoad, id, pc);
}
/**
@@ -2169,14 +2183,14 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* Return true if this is an embedded bean.
*/
public boolean isEmbedded() {
return EntityType.EMBEDDED.equals(entityType);
return EntityType.EMBEDDED == entityType;
}
/**
* Return the compound unique constraints.
*/
public CompoundUniqueConstraint[] getCompoundUniqueConstraints() {
return compoundUniqueConstraints;
public IndexDefinition[] getIndexDefinitions() {
return indexDefinitions;
}
/**
@@ -2295,15 +2309,10 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
}
/**
* Returns true if this bean is based on a table (or possibly view) and
* returns false if this bean is based on a raw sql select statement.
* <p>
* When false querying this bean is based on a supplied sql select statement
* placed in the orm xml file (as opposed to Ebean generated sql).
* </p>
* Returns true if this bean is based on RawSql.
*/
public boolean isSqlSelectBased() {
return EntityType.SQL.equals(entityType);
public boolean isRawSqlBased() {
return EntityType.SQL == entityType;
}
/**
@@ -266,7 +266,7 @@ final class BeanDescriptorCacheHelp<T> {
bc.checkEmptyLazyLoad();
for (int i = 0; i < idList.size(); i++) {
Object id = idList.get(i);
Object refBean = targetDescriptor.createReference(readOnly, id, persistenceContext);
Object refBean = targetDescriptor.createReference(readOnly, false, id, persistenceContext);
many.add(bc, (EntityBean) refBean);
}
return true;
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Model;
import com.avaje.ebean.RawSqlBuilder;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.cache.ServerCacheManager;
@@ -22,10 +23,10 @@ import com.avaje.ebean.plugin.BeanType;
import com.avaje.ebeaninternal.api.ConcurrencyMode;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.TransactionEventTable;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.core.InternalConfiguration;
import com.avaje.ebeaninternal.server.core.Message;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.id.IdBinderEmbedded;
@@ -47,6 +48,12 @@ import com.avaje.ebeaninternal.server.properties.BeanPropertiesReader;
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo;
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfoFactory;
import com.avaje.ebeaninternal.server.properties.EnhanceBeanPropertyInfoFactory;
import com.avaje.ebeaninternal.xmlmapping.XmlMappingReader;
import com.avaje.ebeaninternal.xmlmapping.model.XmAliasMapping;
import com.avaje.ebeaninternal.xmlmapping.model.XmColumnMapping;
import com.avaje.ebeaninternal.xmlmapping.model.XmEbean;
import com.avaje.ebeaninternal.xmlmapping.model.XmEntity;
import com.avaje.ebeaninternal.xmlmapping.model.XmRawSql;
import com.avaje.ebeanservice.docstore.api.DocStoreBeanAdapter;
import com.avaje.ebeanservice.docstore.api.DocStoreFactory;
import org.slf4j.Logger;
@@ -56,12 +63,16 @@ import javax.persistence.MappedSuperclass;
import javax.persistence.PersistenceException;
import javax.persistence.Transient;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -116,7 +127,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private final DocStoreFactory docStoreFactory;
private int enhancedClassCount;
private int entityBeanCount;
private final boolean updateChangesOnly;
@@ -124,7 +135,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private final String serverName;
private Map<Class<?>, DeployBeanInfo<?>> deplyInfoMap = new HashMap<Class<?>, DeployBeanInfo<?>>();
private Map<Class<?>, DeployBeanInfo<?>> deployInfoMap = new HashMap<Class<?>, DeployBeanInfo<?>>();
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<Class<?>, BeanTable>();
@@ -301,6 +312,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
try {
createListeners();
readEntityDeploymentInitial();
readXmlMapping();
readEmbeddedDeployment();
readEntityBeanTable();
readEntityDeploymentAssociations();
@@ -319,8 +331,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
logStatus();
deplyInfoMap.clear();
deplyInfoMap = null;
deployInfoMap.clear();
deployInfoMap = null;
return asOfTableMap;
@@ -330,6 +342,62 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
private void readXmlMapping() {
try {
ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader();
Enumeration<URL> resources = classLoader.getResources("ebean.xml");
List<XmEbean> mappings = new ArrayList<XmEbean>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
InputStream is = url.openStream();
mappings.add(XmlMappingReader.read(is));
is.close();
}
for (XmEbean mapping : mappings) {
List<XmEntity> entityDeploy = mapping.getEntity();
for (XmEntity deploy : entityDeploy) {
readEntityMapping(classLoader, deploy);
}
}
} catch (IOException e) {
throw new RuntimeException("Error reading ebean.xml", e);
}
}
private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) {
String entityClassName = entityDeploy.getClazz();
Class<?> entityClass;
try {
entityClass = Class.forName(entityClassName, false, classLoader);
} catch (Exception e) {
logger.error("Could not load entity bean class "+entityClassName+" for ebean.xml entry");
return;
}
DeployBeanInfo<?> info = deployInfoMap.get(entityClass);
if (info == null) {
logger.error("No entity bean for ebean.xml entry "+entityClassName);
} else {
for (XmRawSql sql : entityDeploy.getRawSql()) {
RawSqlBuilder builder = RawSqlBuilder.parse(sql.getQuery().getValue());
for (XmColumnMapping columnMapping : sql.getColumnMapping()) {
builder.columnMapping(columnMapping.getColumn(), columnMapping.getProperty());
}
for (XmAliasMapping aliasMapping : sql.getAliasMapping()) {
builder.tableAliasMapping(aliasMapping.getAlias(), aliasMapping.getProperty());
}
info.addRawSql(sql.getName(), builder.create());
}
}
}
/**
* Return the Encrypt key given the table and column name.
*/
@@ -381,7 +449,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (String depTable : viewInvalidation) {
List<BeanDescriptor<?>> list = tableToViewDescMap.get(depTable.toLowerCase());
if (list == null) {
if (list != null) {
for (int i = 0; i < list.size(); i++) {
list.get(i).queryCacheClear();
}
@@ -557,7 +625,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void logStatus() {
logger.info("Entities enhanced[" + enhancedClassCount + "]");
logger.debug("Entities[{}]", entityBeanCount);
}
private <T> BeanDescriptor<T> createEmbedded(Class<T> beanClass) {
@@ -569,7 +637,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Return the bean deploy info for the given class.
*/
public <T> DeployBeanInfo<T> getDeploy(Class<T> cls) {
return (DeployBeanInfo<T>) deplyInfoMap.get(cls);
return (DeployBeanInfo<T>) deployInfoMap.get(cls);
}
private void registerBeanDescriptor(BeanDescriptor<?> desc) {
@@ -601,12 +669,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (Class<?> entityClass : bootupClasses.getEntities()) {
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
deplyInfoMap.put(entityClass, info);
deployInfoMap.put(entityClass, info);
}
for (Class<?> entityClass : bootupClasses.getEmbeddables()) {
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
readDeployAssociations(info);
deplyInfoMap.put(entityClass, info);
deployInfoMap.put(entityClass, info);
}
}
@@ -618,7 +686,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private void readEntityBeanTable() {
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
BeanTable beanTable = createBeanTable(info);
beanTableMap.put(beanTable.getBeanType(), beanTable);
}
@@ -632,18 +700,18 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private void readEntityDeploymentAssociations() {
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
readDeployAssociations(info);
}
}
private void readInheritedIdGenerators() {
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
InheritInfo inheritInfo = descriptor.getInheritInfo();
if (inheritInfo != null && !inheritInfo.isRoot()) {
DeployBeanInfo<?> rootBeanInfo = deplyInfoMap.get(inheritInfo.getRoot().getType());
DeployBeanInfo<?> rootBeanInfo = deployInfoMap.get(inheritInfo.getRoot().getType());
PlatformIdGenerator rootIdGen = rootBeanInfo.getDescriptor().getIdGenerator();
if (rootIdGen != null) {
descriptor.setIdGenerator(rootIdGen);
@@ -668,20 +736,20 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// We only perform 'circular' checks etc after we have
// all the DeployBeanDescriptors created and in the map.
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
checkMappedBy(info);
}
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
secondaryPropsJoins(info);
}
// Set inheritance info
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
setInheritanceInfo(info);
}
for (DeployBeanInfo<?> info : deplyInfoMap.values()) {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
registerBeanDescriptor(new BeanDescriptor(this, info.getDescriptor()));
}
}
@@ -695,7 +763,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
if (!oneProp.isTransient()) {
DeployBeanInfo<?> assoc = deplyInfoMap.get(oneProp.getTargetType());
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
if (assoc != null) {
oneProp.getTableJoin().setInheritInfo(assoc.getDescriptor().getInheritInfo());
}
@@ -704,7 +772,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
if (!manyProp.isTransient()) {
DeployBeanInfo<?> assoc = deplyInfoMap.get(manyProp.getTargetType());
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
if (assoc != null) {
manyProp.getTableJoin().setInheritInfo(assoc.getDescriptor().getInheritInfo());
}
@@ -763,7 +831,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private DeployBeanDescriptor<?> getTargetDescriptor(DeployBeanPropertyAssoc<?> prop) {
Class<?> targetType = prop.getTargetType();
DeployBeanInfo<?> info = deplyInfoMap.get(targetType);
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
if (info == null) {
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
throw new PersistenceException(msg);
@@ -1141,7 +1209,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// already assigned (So custom or UUID)
return;
}
if (desc.propertiesId().size() == 0) {
if (desc.propertiesId().isEmpty()) {
// bean doesn't have an Id property
if (desc.isBaseTableType() && desc.getBeanFinder() == null) {
// expecting an id property
@@ -1348,7 +1416,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
checkInheritedClasses(beanClass);
if (!beanClass.getName().startsWith("com.avaje.ebean.meta")) {
enhancedClassCount++;
entityBeanCount++;
}
}
@@ -27,6 +27,7 @@ import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypeBoolean;
import com.avaje.ebeaninternal.server.type.ScalarTypeEnum;
import com.avaje.ebeaninternal.server.type.ScalarTypeLogicalType;
import com.avaje.ebeaninternal.util.ValueUtil;
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
@@ -255,10 +256,6 @@ public class BeanProperty implements ElPropertyValue, Property {
final String softDeleteDbPredicate;
final boolean indexed;
final String indexName;
public BeanProperty(DeployBeanProperty deploy) {
this(null, deploy);
}
@@ -268,8 +265,6 @@ public class BeanProperty implements ElPropertyValue, Property {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
this.indexed = deploy.isIndexed();
this.indexName = deploy.getIndexName();
this.unidirectionalShadow = deploy.isUndirectionalShadow();
this.discriminator = deploy.isDiscriminator();
this.localEncrypted = deploy.isLocalEncrypted();
@@ -370,9 +365,6 @@ public class BeanProperty implements ElPropertyValue, Property {
this.descriptor = source.descriptor;
this.name = InternString.intern(source.getName());
this.propertyIndex = source.propertyIndex;
this.indexed = source.isIndexed();
this.indexName = source.getIndexName();
this.dbColumn = InternString.intern(override.getDbColumn());
// override with sqlFormula not currently supported
this.sqlFormulaJoin = null;
@@ -422,7 +414,7 @@ public class BeanProperty implements ElPropertyValue, Property {
this.generatedProperty = source.getGeneratedProperty();
this.getter = source.getter;
this.setter = source.setter;
this.dbType = source.getDbType();
this.dbType = source.getDbType(true);
this.scalarType = source.scalarType;
this.lob = isLobType(dbType);
this.propertyType = source.getPropertyType();
@@ -631,14 +623,6 @@ public class BeanProperty implements ElPropertyValue, Property {
return this;
}
public boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
/**
* Return true if this object is part of an inheritance hierarchy.
*/
@@ -1104,9 +1088,14 @@ public class BeanProperty implements ElPropertyValue, Property {
/**
* Return the database jdbc data type this is mapped to.
*
* @param platformTypes Set as false when we want logical platform agnostic types.
*/
public int getDbType() {
return dbType;
public int getDbType(boolean platformTypes) {
if (platformTypes || !(scalarType instanceof ScalarTypeLogicalType)) {
return dbType;
}
return ((ScalarTypeLogicalType)scalarType).getLogicalType();
}
/**
@@ -322,7 +322,7 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty {
BeanProperty idProp = target.getIdProperty();
BeanProperty[] others = target.propertiesBaseScalar();
if (descriptor.isSqlSelectBased()) {
if (descriptor.isRawSqlBased()) {
String dbColumn = owner.getDbColumn();
return new ImportedIdSimple(owner, dbColumn, idProp, 0);
}
@@ -1028,7 +1028,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
if (isManyToMany()) {
if (liveBean == null) {
// add new relationship (Map not allowed here)
liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, id, null));
liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, false, id, null));
}
} else {
@@ -422,7 +422,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
// cacheData is the id value, maybe already in persistence context
Object assocBean = targetDescriptor.contextGet(context, cacheData);
if (assocBean == null) {
assocBean = targetDescriptor.createReference(Boolean.FALSE, cacheData, context);
assocBean = targetDescriptor.createReference(Boolean.FALSE, false, cacheData, context);
}
setValue(bean, assocBean);
}
@@ -84,4 +84,9 @@ public interface DbReadContext {
* Return true if the underlying query is a 'asDraft' query.
*/
boolean isDraftQuery();
/**
* Return true if this request disables lazy loading.
*/
boolean isDisableLazyLoading();
}
@@ -51,14 +51,14 @@ public abstract class DeployParser {
*/
public abstract Set<String> getIncludes();
public void setEncrypted(boolean encrytped) {
this.encrypted = encrytped;
}
public void setEncrypted(boolean encrypted) {
this.encrypted = encrypted;
}
public String parse(String source) {
if (source == null) {
return source;
return null;
}
pos = -1;
@@ -3,7 +3,7 @@ package com.avaje.ebeaninternal.server.deploy;
/**
* Holds multiple column unique constraints defined for an entity.
*/
public class CompoundUniqueConstraint {
public class IndexDefinition {
private final String[] columns;
@@ -11,7 +11,16 @@ public class CompoundUniqueConstraint {
private final boolean unique;
public CompoundUniqueConstraint(String[] columns, String name, boolean unique) {
/**
* A single column index.
*/
public IndexDefinition(String column, String name, boolean unique) {
this.columns = new String[]{column};
this.unique = unique;
this.name = name;
}
public IndexDefinition(String[] columns, String name, boolean unique) {
this.columns = columns;
this.unique = unique;
this.name = name;
@@ -20,7 +29,7 @@ public class CompoundUniqueConstraint {
/**
* Create a unique constraint given the column names.
*/
public CompoundUniqueConstraint(String[] columns) {
public IndexDefinition(String[] columns) {
this.columns = columns;
this.unique = true;
this.name = null;
@@ -144,15 +144,13 @@ public class ImportedIdEmbedded implements ImportedId {
*/
public BeanProperty findMatchImport(String matchDbColumn) {
BeanProperty p = null;
for (int i = 0; i < imported.length; i++) {
p = imported[i].findMatchImport(matchDbColumn);
BeanProperty p = imported[i].findMatchImport(matchDbColumn);
if (p != null) {
return p;
}
}
return p;
return null;
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import com.avaje.ebean.RawSql;
import com.avaje.ebean.annotation.Cache;
import com.avaje.ebean.annotation.DocStore;
import com.avaje.ebean.annotation.DocStoreMode;
@@ -23,7 +24,7 @@ import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController;
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistListener;
import com.avaje.ebeaninternal.server.deploy.ChainedBeanPostLoad;
import com.avaje.ebeaninternal.server.deploy.ChainedBeanQueryAdapter;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo;
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
@@ -35,14 +36,18 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Describes Beans including their deployment information.
*/
public class DeployBeanDescriptor<T> {
private static final Map<String, RawSql> EMPTY_RAW_MAP = new HashMap<String, RawSql>();
private static class PropOrder implements Comparator<DeployBeanProperty> {
public int compare(DeployBeanProperty o1, DeployBeanProperty o2) {
@@ -66,6 +71,8 @@ public class DeployBeanDescriptor<T> {
*/
private LinkedHashMap<String, DeployBeanProperty> propMap = new LinkedHashMap<String, DeployBeanProperty>();
private Map<String, RawSql> namedRawSql;
private EntityType entityType;
private DeployBeanPropertyAssocOne<?> unidirectional;
@@ -108,7 +115,7 @@ public class DeployBeanDescriptor<T> {
private boolean updateChangesOnly;
private List<CompoundUniqueConstraint> compoundUniqueConstraints;
private List<IndexDefinition> indexDefinitions;
/**
* The base database table.
@@ -283,7 +290,7 @@ public class DeployBeanDescriptor<T> {
docStoreUpdate = docStore.update();
docStoreDelete = docStore.delete();
String doc = docStore.doc();
if (doc.length() > 0) {
if (!doc.isEmpty()) {
docStorePathProperties = PathProperties.parse(doc);
}
}
@@ -388,7 +395,7 @@ public class DeployBeanDescriptor<T> {
public void setCache(Cache cache) {
String naturalKey = null;
if (cache.naturalKey().length() > 0) {
if (!cache.naturalKey().isEmpty()) {
// find the property and mark as natural key property
String propName = cache.naturalKey().trim();
DeployBeanProperty beanProperty = getBeanProperty(propName);
@@ -440,21 +447,21 @@ public class DeployBeanDescriptor<T> {
/**
* Add a compound unique constraint.
*/
public void addCompoundUniqueConstraint(CompoundUniqueConstraint c) {
if (compoundUniqueConstraints == null) {
compoundUniqueConstraints = new ArrayList<CompoundUniqueConstraint>();
public void addIndex(IndexDefinition c) {
if (indexDefinitions == null) {
indexDefinitions = new ArrayList<IndexDefinition>();
}
compoundUniqueConstraints.add(c);
indexDefinitions.add(c);
}
/**
* Return the compound unique constraints (can be null).
*/
public CompoundUniqueConstraint[] getCompoundUniqueConstraints() {
if (compoundUniqueConstraints == null) {
public IndexDefinition[] getIndexDefinitions() {
if (indexDefinitions == null) {
return null;
} else {
return compoundUniqueConstraints.toArray(new CompoundUniqueConstraint[compoundUniqueConstraints.size()]);
return indexDefinitions.toArray(new IndexDefinition[indexDefinitions.size()]);
}
}
@@ -583,7 +590,7 @@ public class DeployBeanDescriptor<T> {
*/
public void setView(String viewName, String[] dependentTables) {
this.entityType = EntityType.VIEW;
this.dependentTables = this.dependentTables;
this.dependentTables = dependentTables;
setBaseTable(new TableName(viewName), "", "");
}
@@ -835,7 +842,7 @@ public class DeployBeanDescriptor<T> {
return null;
}
String selectClause = sb.toString();
if (selectClause.length() == 0) {
if (selectClause.isEmpty()) {
throw new IllegalStateException("Bean " + getFullName() + " has no properties?");
}
return selectClause.substring(0, selectClause.length() - 1);
@@ -1047,4 +1054,21 @@ public class DeployBeanDescriptor<T> {
if (docStorePersist != DocStoreMode.DEFAULT) return docStorePersist;
return serverConfig.getDocStoreConfig().getPersist();
}
/**
* Return the named RawSql queries.
*/
public Map<String, RawSql> getNamedRawSql() {
return (namedRawSql != null) ? namedRawSql : EMPTY_RAW_MAP;
}
/**
* Add a named RawSql from ebean.xml file.
*/
public void addRawSql(String name, RawSql rawSql) {
if (namedRawSql == null) {
namedRawSql = new HashMap<String, RawSql>();
}
namedRawSql.put(name, rawSql);
}
}
@@ -22,7 +22,6 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.properties.BeanPropertyGetter;
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypeEnum;
import com.avaje.ebeaninternal.server.type.ScalarTypeWrapper;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyOptions;
@@ -192,9 +191,6 @@ public class DeployBeanProperty {
private int sortOrder;
private boolean indexed;
private String indexName;
private boolean excludedFromHistory;
private boolean draft;
@@ -386,7 +382,7 @@ public class DeployBeanProperty {
* Set a specific DB column definition.
*/
public void setDbColumnDefn(String dbColumnDefn) {
if (dbColumnDefn == null || dbColumnDefn.trim().length() == 0) {
if (dbColumnDefn == null || dbColumnDefn.trim().isEmpty()) {
this.dbColumnDefn = null;
} else {
this.dbColumnDefn = InternString.intern(dbColumnDefn);
@@ -849,22 +845,6 @@ public class DeployBeanProperty {
return desc.getFullName() + "." + name;
}
public boolean isIndexed() {
return indexed;
}
public void setIndexed() {
this.indexed = true;
}
public String getIndexName() {
return indexName;
}
public void setIndexName(String indexName) {
this.indexName = indexName;
}
public boolean isExcludedFromHistory() {
return excludedFromHistory;
}
@@ -178,7 +178,7 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
* Set the default mapKey to use when returning a Map.
*/
public void setMapKey(String mapKey) {
if (mapKey != null && mapKey.length() > 0) {
if (mapKey != null && !mapKey.isEmpty()) {
this.mapKey = mapKey;
}
}
@@ -188,7 +188,7 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
* list, set or map.
*/
public void setFetchOrderBy(String orderBy) {
if (orderBy != null && orderBy.length() > 0) {
if (orderBy != null && !orderBy.isEmpty()) {
fetchOrderBy = orderBy;
}
}
@@ -32,7 +32,7 @@ public abstract class AnnotationBase {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
return s == null || s.trim().isEmpty();
}
@@ -12,7 +12,7 @@ import com.avaje.ebean.annotation.UpdateMode;
import com.avaje.ebean.annotation.View;
import com.avaje.ebean.config.TableName;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,13 +68,11 @@ public class AnnotationClass extends AnnotationParser {
if (override != null) {
String propertyName = override.name();
Column column = override.column();
if (column != null) {
DeployBeanProperty beanProperty = descriptor.getBeanProperty(propertyName);
if (beanProperty == null) {
logger.error("AttributeOverride property [" + propertyName + "] not found on " + descriptor.getFullName());
} else {
readColumn(column, beanProperty);
}
DeployBeanProperty beanProperty = descriptor.getBeanProperty(propertyName);
if (beanProperty == null) {
logger.error("AttributeOverride property [" + propertyName + "] not found on " + descriptor.getFullName());
} else {
readColumn(column, beanProperty);
}
}
}
@@ -120,12 +118,12 @@ public class AnnotationClass extends AnnotationParser {
Index index = cls.getAnnotation(Index.class);
if (index != null) {
descriptor.addCompoundUniqueConstraint(new CompoundUniqueConstraint(index.columnNames(), index.name(), index.unique()));
descriptor.addIndex(new IndexDefinition(index.columnNames(), index.name(), index.unique()));
}
UniqueConstraint uc = cls.getAnnotation(UniqueConstraint.class);
if (uc != null) {
descriptor.addCompoundUniqueConstraint(new CompoundUniqueConstraint(uc.columnNames()));
descriptor.addIndex(new IndexDefinition(uc.columnNames()));
}
View view = cls.getAnnotation(View.class);
@@ -136,7 +134,7 @@ public class AnnotationClass extends AnnotationParser {
if (table != null) {
UniqueConstraint[] uniqueConstraints = table.uniqueConstraints();
for (UniqueConstraint c : uniqueConstraints) {
descriptor.addCompoundUniqueConstraint(new CompoundUniqueConstraint(c.columnNames()));
descriptor.addIndex(new IndexDefinition(c.columnNames()));
}
}
@@ -7,6 +7,7 @@ import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.config.dbplatform.PlatformIdGenerator;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
@@ -314,8 +315,7 @@ public class AnnotationFields extends AnnotationParser {
if (hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
prop.setIndexed();
prop.setIndexName(index.name());
descriptor.addIndex(new IndexDefinition(prop.getDbColumn(), index.name(), index.unique()));
}
}
@@ -1,12 +1,13 @@
package com.avaje.ebeaninternal.server.deploy.parse;
import java.util.HashMap;
import com.avaje.ebean.RawSql;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.util.HashMap;
/**
* Wraps information about a bean during deployment parsing.
*/
@@ -75,4 +76,10 @@ public class DeployBeanInfo<T> {
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
}
/**
* Add named RawSql from ebean.xml.
*/
public void addRawSql(String name, RawSql rawSql) {
descriptor.addRawSql(name, rawSql);
}
}
@@ -188,7 +188,7 @@ public class DeployInheritInfo {
public void setDiscriminatorValue(String value) {
if (value != null) {
value = value.trim();
if (value.length() != 0) {
if (!value.isEmpty()) {
discriminatorStringValue = value;
// convert the value if desired
if (discriminatorType == Types.INTEGER) {
@@ -70,7 +70,7 @@ public class SqlReservedWords {
public static synchronized void addKeyword(String keyword){
if (keyword != null){
keyword = keyword.trim().toUpperCase();
if (keyword.length() > 0){
if (!keyword.isEmpty()){
keywords.add(keyword);
}
}
@@ -24,7 +24,7 @@ public class StringHelper {
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<String, String>();
if ((allNameValuePairs == null) || (allNameValuePairs.length() == 0)) {
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
@@ -56,7 +56,7 @@ public class StringHelper {
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
/**
@@ -90,7 +90,7 @@ public class StringHelper {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (key.length() > 0) {
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
@@ -105,7 +105,7 @@ public class BatchedPstmtHolder {
firstError = ex;
errorSql = bs.getSql();
} else {
logger.error(null, ex);
logger.error("Error executing batched PreparedStatement", ex);
}
isError = true;
@@ -113,8 +113,7 @@ public class BatchedPstmtHolder {
try {
bs.close();
} catch (SQLException ex) {
// error closing PreparedStatement
logger.error(null, ex);
logger.error("Error closing batched PreparedStatement", ex);
}
}
}
@@ -33,7 +33,7 @@ public class Binder {
private final int asOfBindCount;
private final boolean bindAsOfWithFromClause;
private final boolean asOfStandardsBased;
private final DbExpressionHandler dbExpressionHandler;
@@ -42,12 +42,12 @@ public class Binder {
/**
* Set the PreparedStatement with which to bind variables to.
*/
public Binder(TypeManager typeManager, int asOfBindCount, boolean bindAsOfWithFromClause,
public Binder(TypeManager typeManager, int asOfBindCount, boolean asOfStandardsBased,
DbExpressionHandler dbExpressionHandler, DataTimeZone dataTimeZone) {
this.typeManager = typeManager;
this.asOfBindCount = asOfBindCount;
this.bindAsOfWithFromClause = bindAsOfWithFromClause;
this.asOfStandardsBased = asOfStandardsBased;
this.dbExpressionHandler = dbExpressionHandler;
this.dataTimeZone = dataTimeZone;
}
@@ -60,12 +60,10 @@ public class Binder {
}
/**
* Return true if the 'as of' predicates are in the from/join clause in which case the timestamp is
* bound early (before all the other predicates ala Oracle). Return false if the 'as of' predicates are
* appended to the end of the predicates and the timestamp is bound last (Postgres, MySql).
* Return true if the 'as of' history support is SQL2011 standards based.
*/
public boolean isBindAsOfWithFromClause() {
return bindAsOfWithFromClause;
public boolean isAsOfStandardsBased() {
return asOfStandardsBased;
}
/**
@@ -839,16 +839,6 @@ public final class DefaultPersister implements Persister {
this.publish = request.isPublish();
}
private SaveManyPropRequest(BeanPropertyAssocMany<?> many, EntityBean parentBean, SpiTransaction t) {
this.insertedParent = false;
this.many = many;
this.parentBean = parentBean;
this.transaction = t;
this.cascade = true;
this.deleteMissingChildren = false;
this.publish = false;
}
public boolean isSaveIntersection() {
return transaction.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName());
}
@@ -1304,7 +1294,7 @@ public final class DefaultPersister implements Persister {
// convert into a list of reference objects and perform delete by object
List<Object> refList = new ArrayList<Object>(childIds.size());
for (Object id : childIds) {
refList.add(targetDesc.createReference(null, id, null));
refList.add(targetDesc.createReference(null, false, id, null));
}
deleteList(refList, t, softDelete);
@@ -107,6 +107,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
private final SpiQuery<T> query;
private final boolean disableLazyLoading;
private Map<String, String> currentPathMap;
private String currentPrefix;
@@ -197,6 +199,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
this.lazyLoadManyProperty = query.getLazyLoadMany();
this.readOnly = request.isReadOnly();
this.disableLazyLoading = query.isDisableLazyLoading();
this.objectGraphNode = query.getParentNode();
this.profilingListener = query.getProfilingListener();
@@ -239,6 +242,11 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
return query.isAsDraft();
}
@Override
public boolean isDisableLazyLoading() {
return disableLazyLoading;
}
public Boolean isReadOnly() {
return readOnly;
}
@@ -466,18 +466,20 @@ public class CQueryBuilder {
String inheritanceWhere = select.getInheritanceWhereSql();
boolean hasWhere = false;
if (inheritanceWhere.length() > 0) {
if (!inheritanceWhere.isEmpty()) {
sb.append(" where");
sb.append(inheritanceWhere);
hasWhere = true;
}
int asOfCount = query.getAsOfTableCount();
if (asOfCount > 0 && !historySupport.isStandardsBased()) {
hasWhere = appendWhere(hasWhere, sb);
sb.append(historySupport.getAsOfPredicate(request.getBaseTableAlias()));
}
if (request.isFindById() || query.getId() != null) {
if (hasWhere) {
sb.append(" and ");
} else {
sb.append(" where ");
}
appendWhere(hasWhere, sb);
BeanDescriptor<?> desc = request.getBeanDescriptor();
String idSql = desc.getIdBinderIdSql();
@@ -515,24 +517,6 @@ public class CQueryBuilder {
sb.append(dbFilterMany);
}
List<String> asOfTableAlias = query.getAsOfTableAlias();
if (asOfTableAlias != null && !historySupport.isBindAtFromClause()) {
// append the effective date predicates for each table alias
// that maps to a @History entity involved in this query
// Do this when history using separate tables/views (PG, MySql etc)
if (!hasWhere) {
sb.append(" where ");
} else {
sb.append("and ");
}
for (int i = 0; i < asOfTableAlias.size(); i++) {
if (i > 0) {
sb.append(" and ");
}
sb.append(historySupport.getAsOfPredicate(asOfTableAlias.get(i)));
}
}
if (!query.isIncludeSoftDeletes()) {
List<String> softDeletePredicates = query.getSoftDeletePredicates();
if (softDeletePredicates != null) {
@@ -565,6 +549,18 @@ public class CQueryBuilder {
}
/**
* Append where or and based on the hasWhere flag.
*/
private boolean appendWhere(boolean hasWhere, StringBuilder sb) {
if (hasWhere) {
sb.append(" and ");
} else {
sb.append(" where ");
}
return true;
}
/**
* Convert the dbOrderBy clause to be safe for adding to select. This is done when 'distinct' is
* used.
@@ -575,7 +571,7 @@ public class CQueryBuilder {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
}
@@ -134,7 +134,7 @@ public class CQueryBuilderRawSql {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
private String getOrderBy(CQueryPredicates predicates, RawSql.Sql sql) {
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.core.QueryIterator;
import com.avaje.ebean.ValuePair;
import com.avaje.ebean.Version;
@@ -19,6 +20,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -34,15 +36,22 @@ public class CQueryEngine {
private static final String T0 = "t0";
private final int defaultFetchSizeFindList;
private final int defaultFetchSizeFindEach;
private final boolean forwardOnlyHintOnFindIterate;
private final CQueryBuilder queryBuilder;
private final CQueryHistorySupport historySupport;
public CQueryEngine(DatabasePlatform dbPlatform, Binder binder, Map<String, String> asOfTableMapping, String asOfSysPeriod, Map<String, String> draftTableMap) {
public CQueryEngine(ServerConfig serverConfig, DatabasePlatform dbPlatform, Binder binder, Map<String, String> asOfTableMapping, Map<String, String> draftTableMap) {
this.defaultFetchSizeFindEach = serverConfig.getJdbcFetchSizeFindEach();
this.defaultFetchSizeFindList = serverConfig.getJdbcFetchSizeFindList();
this.forwardOnlyHintOnFindIterate = dbPlatform.isForwardOnlyHintOnFindIterate();
this.historySupport = new CQueryHistorySupport(dbPlatform.getHistorySupport(), asOfTableMapping, asOfSysPeriod);
this.historySupport = new CQueryHistorySupport(dbPlatform.getHistorySupport(), asOfTableMapping, serverConfig.getAsOfSysPeriod());
this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap));
}
@@ -90,11 +99,7 @@ public class CQueryEngine {
BeanIdList list = rcQuery.findIds();
if (request.isLogSql()) {
String logSql = rcQuery.getGeneratedSql();
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
logSql = Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
}
request.logSql(logSql);
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog());
}
if (request.isLogSummary()) {
@@ -114,6 +119,14 @@ public class CQueryEngine {
}
}
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog) {
String logSql = sql;
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
logSql = Str.add(logSql, "; --bind(", bindLog, ")");
}
request.logSql(logSql);
}
/**
* Build and execute the row count query.
*/
@@ -125,11 +138,7 @@ public class CQueryEngine {
int rowCount = rcQuery.findRowCount();
if (request.isLogSql()) {
String logSql = rcQuery.getGeneratedSql();
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
logSql = Str.add(logSql, "; --bind(", rcQuery.getBindLog(), ")");
}
request.logSql(logSql);
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog());
}
if (request.isLogSummary()) {
@@ -137,7 +146,6 @@ public class CQueryEngine {
}
if (request.getQuery().isFutureFetch()) {
logger.debug("Future findRowCount completed!");
request.getTransaction().end();
}
@@ -158,7 +166,9 @@ public class CQueryEngine {
request.setCancelableQuery(cquery);
try {
if (defaultFetchSizeFindEach > 0) {
request.setDefaultFetchBuffer(defaultFetchSizeFindEach);
}
if (!cquery.prepareBindExecuteQueryForwardOnly(forwardOnlyHintOnFindIterate)) {
// query has been cancelled already
logger.trace("Future fetch already cancelled");
@@ -204,15 +214,16 @@ public class CQueryEngine {
SpiQuery<T> query = request.getQuery();
if (query.isVersionsBetween() && !historySupport.isBindAtFromClause()) {
String sysPeriodLower = getSysPeriodLower(query);
if (query.isVersionsBetween() && !historySupport.isStandardsBased()) {
// just add as normal predicates using the lower bound
query.where().gt(getSysPeriodLower(query), query.getVersionStart());
query.where().lt(getSysPeriodLower(query), query.getVersionEnd());
query.where().gt(sysPeriodLower, query.getVersionStart());
query.where().lt(sysPeriodLower, query.getVersionEnd());
}
// order by id asc, lower sys period desc
query.orderBy().asc(request.getBeanDescriptor().getIdProperty().getName());
query.orderBy().desc(getSysPeriodLower(query));
query.orderBy().desc(sysPeriodLower);
CQuery<T> cquery = queryBuilder.buildQuery(request);
try {
@@ -222,6 +233,9 @@ public class CQueryEngine {
}
List<Version<T>> versions = cquery.readVersions();
// just order in memory rather than use NULLS LAST as that
// is not universally supported, not expect huge list here
Collections.sort(versions, OrderVersionDesc.INSTANCE);
deriveVersionDiffs(versions, request);
if (request.isLogSummary()) {
@@ -296,6 +310,9 @@ public class CQueryEngine {
request.setCancelableQuery(cquery);
try {
if (defaultFetchSizeFindList > 0) {
request.setDefaultFetchBuffer(defaultFetchSizeFindList);
}
if (!cquery.prepareBindExecuteQuery()) {
// query has been cancelled already
logger.trace("Future fetch already cancelled");
@@ -197,7 +197,7 @@ public class CQueryFetchIds {
dataReader = null;
}
} catch (SQLException e) {
logger.error(null, e);
logger.error("Error closing DataReader", e);
}
try {
if (pstmt != null) {
@@ -205,7 +205,7 @@ public class CQueryFetchIds {
pstmt = null;
}
} catch (SQLException e) {
logger.error(null, e);
logger.error("Error closing PreparedStatement", e);
}
}
@@ -228,6 +228,11 @@ public class CQueryFetchIds {
return Boolean.FALSE;
}
@Override
public boolean isDisableLazyLoading() {
return false;
}
public boolean isRawSql() {
return false;
}
@@ -31,11 +31,10 @@ public class CQueryHistorySupport {
}
/**
* Return true if the bind of 'as of' timestamp occurs with the from clause
* rather than at the end.
* Return true if the underlying history support is standards based.
*/
public boolean isBindAtFromClause() {
return dbHistorySupport.isBindWithFromClause();
public boolean isStandardsBased() {
return dbHistorySupport.isStandardsBased();
}
/**
@@ -70,6 +70,8 @@ public class CQueryPlan {
protected final DataTimeZone dataTimeZone;
private final int asOfTableCount;
/**
* Key used to identify the query plan in audit logging.
*/
@@ -86,6 +88,7 @@ public class CQueryPlan {
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.planKey = request.getQueryPlanKey();
this.autoTuned = request.getQuery().isAutoTuned();
this.asOfTableCount = request.getQuery().getAsOfTableCount();
if (sqlRes != null) {
this.sql = sqlRes.getSql();
this.rowNumberIncluded = sqlRes.isIncludesRowNumberColumn();
@@ -111,6 +114,7 @@ public class CQueryPlan {
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
this.autoTuned = false;
this.asOfTableCount = 0;
this.sql = sql;
this.sqlTree = sqlTree;
this.rawSql = rawSql;
@@ -151,6 +155,10 @@ public class CQueryPlan {
return dataBind;
}
public int getAsOfTableCount() {
return asOfTableCount;
}
public boolean isAutoTuned() {
return autoTuned;
}
@@ -126,7 +126,7 @@ public class CQueryPredicates {
updateProperties.bind(binder, dataBind);
}
if (query.isVersionsBetween() && binder.isBindAsOfWithFromClause()) {
if (query.isVersionsBetween() && binder.isAsOfStandardsBased()) {
// sql2011 based versions between timestamp syntax
Timestamp start = query.getVersionStart();
Timestamp end = query.getVersionEnd();
@@ -136,13 +136,13 @@ public class CQueryPredicates {
dataBind.append(", ");
}
List<String> historyTableAlias = query.getAsOfTableAlias();
if (historyTableAlias != null && binder.isBindAsOfWithFromClause()) {
int asOfTableCount = request.getQueryPlan().getAsOfTableCount();
if (asOfTableCount > 0) {
// bind the asOf value for each table alias as part of the from/join clauses
// there is one effective date predicate per table alias
Timestamp asOf = query.getAsOf();
dataBind.append("asOf ").append(asOf);
for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) {
for (int i = 0; i < asOfTableCount * binder.getAsOfBindCount(); i++) {
binder.bindObject(dataBind, asOf);
}
dataBind.append(", ");
@@ -167,16 +167,6 @@ public class CQueryPredicates {
filterMany.bind(dataBind);
}
if (historyTableAlias != null && !binder.isBindAsOfWithFromClause()) {
// bind the asOf value for each table alias after all the normal predicates
// there is one effective date predicate per table alias
Timestamp asOf = query.getAsOf();
dataBind.append(" asOf ").append(asOf);
for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) {
binder.bindObject(dataBind, asOf);
}
}
if (having != null) {
having.bind(dataBind);
}
@@ -305,7 +295,7 @@ public class CQueryPredicates {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
private String parse(String expr, DeployParser deployParser) {
@@ -106,8 +106,8 @@ public class DefaultDbSqlContext implements DbSqlContext {
tableJoins.add(joinKey);
sb.append(" ");
sb.append(type);
sb.append(" ").append(type);
boolean addAsOfOnClause = false;
if (draftSupport != null) {
appendTable(table, draftSupport.getDraftTable(table));
@@ -117,32 +117,32 @@ public class DefaultDbSqlContext implements DbSqlContext {
} else {
// check if there is an associated history table and if so
// use the unionAll view - we expect an additional predicate to match
appendTable(table, historySupport.getAsOfView(table));
String asOfView = historySupport.getAsOfView(table);
appendTable(table, asOfView);
if (asOfView != null) {
addAsOfOnClause = !historySupport.isStandardsBased();
}
}
sb.append(a2);
sb.append(" on ");
for (int i = 0; i < cols.length; i++) {
TableJoinColumn pair = cols[i];
if (i > 0) {
sb.append(" and ");
}
sb.append(a2);
sb.append(".").append(pair.getForeignDbColumn());
sb.append(a2).append(".").append(pair.getForeignDbColumn());
sb.append(" = ");
sb.append(a1);
sb.append(".").append(pair.getLocalDbColumn());
sb.append(a1).append(".").append(pair.getLocalDbColumn());
}
// add on any inheritance where clause
if (inheritance != null && inheritance.length() > 0) {
sb.append(" and ");
sb.append(a2);
sb.append(".");
sb.append(inheritance);
if (inheritance != null && !inheritance.isEmpty()) {
sb.append(" and ").append(a2).append(".").append(inheritance);
}
if (addAsOfOnClause) {
sb.append(" and ").append(historySupport.getAsOfPredicate(a2));
}
sb.append(" ");
@@ -0,0 +1,29 @@
package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.Version;
import java.sql.Timestamp;
import java.util.Comparator;
/**
* Compare Version beans in descending order with nulls last.
*/
class OrderVersionDesc implements Comparator<Version<?>> {
static final OrderVersionDesc INSTANCE = new OrderVersionDesc();
@Override
public int compare(Version<?> o1, Version<?> o2) {
Timestamp v1 = o1.getStart();
if (v1 == null) {
return 1;
}
Timestamp v2 = o2.getStart();
if (v2 == null) {
return -1;
}
return v1.compareTo(v2) * -1;
}
}
@@ -111,7 +111,7 @@ public class SqlTreeBuilder {
this.queryDetail = query.getDetail();
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.getQuery().getAlias() == null ? request.getBeanDescriptor().getBaseTableAlias() : request.getQuery().getAlias());
this.alias = new SqlTreeAlias(request.getBaseTableAlias());
this.ctx = new DefaultDbSqlContext(alias, tableAliasPlaceHolder, columnAliasPrefix, !subQuery, historySupport, draftSupport);
}
@@ -417,7 +417,7 @@ public class SqlTreeBuilder {
// This makes sense for transient properties used to
// hold sum() count() type values (with SqlSelect)
for (String propName : queryProps.getSelectProperties()) {
if (propName.length() > 0) {
if (!propName.isEmpty()) {
addProperty(selectProps, desc, queryProps, propName);
}
}
@@ -81,7 +81,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
* Table alias set if this bean node includes a join to a intersection
* table and that table has history support.
*/
protected String intersectionAsOfTableAlias;
private boolean intersectionAsOfTableAlias;
/**
* Construct for Raw SQL.
@@ -128,7 +128,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
// the bean has an Id property and we want to use it
this.readId = withId && (desc.getIdProperty() != null);
this.disableLazyLoad = disableLazyLoad || !readId || desc.isSqlSelectBased() || temporalVersions;
this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions;
this.partialObject = props.isPartialObject();
this.properties = props.getProps();
@@ -303,7 +303,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readId && !temporalVersions) {
createListProxies(localDesc, ctx, localBean);
createListProxies(localDesc, ctx, localBean, disableLazyLoad);
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
@@ -360,7 +360,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies(BeanDescriptor<?> localDesc, DbReadContext ctx, EntityBean localBean) {
private void createListProxies(BeanDescriptor<?> localDesc, DbReadContext ctx, EntityBean localBean, boolean disableLazyLoad) {
BeanPropertyAssocMany<?> fetchedMany = ctx.getManyProperty();
@@ -371,8 +371,13 @@ public class SqlTreeNodeBean implements SqlTreeNode {
if (fetchedMany == null || !fetchedMany.equals(manys[i])) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = manys[i].createReferenceIfNull(localBean);
if (ref != null && !ref.isRegisteredWithLoadContext()) {
ctx.register(manys[i].getName(), ref);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(manys[i].getName(), ref);
}
}
}
}
@@ -433,15 +438,14 @@ public class SqlTreeNodeBean implements SqlTreeNode {
public void appendWhere(DbSqlContext ctx) {
// Only apply inheritance to root node as any join will alreay have the inheritance join include - see TableJoin
// Only apply inheritance to root node as any join will already have the inheritance join include - see TableJoin
if (inheritInfo != null && nodeBeanProp == null) {
if (!inheritInfo.isRoot()) {
// restrict to this type and
// sub types of this type.
// restrict to this type and sub types of this type.
if (ctx.length() > 0) {
ctx.append(" and");
}
ctx.append(" ").append(ctx.getTableAlias(prefix)).append(".");// tableAlias
ctx.append(" ").append(ctx.getTableAlias(prefix)).append(".");
ctx.append(inheritInfo.getWhere()).append(" ");
}
}
@@ -501,11 +505,10 @@ public class SqlTreeNodeBean implements SqlTreeNode {
// if history on this bean type add it's alias
// for each alias we add an effect date predicate
if (desc.isHistorySupport()) {
query.addAsOfTableAlias(baseTableAlias);
query.incrementAsOfTableCount();
}
if (intersectionAsOfTableAlias != null) {
// adds the 'as of' predicate for this intersection table
query.addAsOfTableAlias(intersectionAsOfTableAlias);
if (intersectionAsOfTableAlias) {
query.incrementAsOfTableCount();
}
for (int i = 0; i < children.length; i++) {
children[i].addAsOfTableAlias(query);
@@ -531,7 +534,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
if (!manyProp.isExcludedFromHistory()) {
intersectionAsOfTableAlias = alias2;
intersectionAsOfTableAlias = true;
}
return nodeBeanProp.addJoin(joinType, alias2, alias, ctx);
@@ -38,6 +38,8 @@ import java.util.Set;
*/
public class DefaultOrmQuery<T> implements SpiQuery<T> {
public static final String DEFAULT_QUERY_NAME = "default";
private final Class<T> beanType;
private final BeanDescriptor<T> beanDescriptor;
@@ -144,10 +146,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private DefaultExpressionList<T> havingExpressions;
/**
* The list of table alias associated with @History entity beans.
*/
private List<String> asOfTableAlias;
private int asOfTableCount;
/**
* Set for flashback style 'as of' query.
@@ -281,21 +280,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return softDeletePredicates;
}
/**
* This table alias is for a @History entity involved in the query and as
* such we need to add a 'as of predicate' to the query using this alias.
*/
@Override
public void addAsOfTableAlias(String tableAlias) {
if (asOfTableAlias == null) {
asOfTableAlias = new ArrayList<String>();
}
asOfTableAlias.add(tableAlias);
public void incrementAsOfTableCount() {
asOfTableCount++;
}
@Override
public List<String> getAsOfTableAlias() {
return asOfTableAlias;
public int getAsOfTableCount() {
return asOfTableCount;
}
@Override
@@ -709,6 +701,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return forUpdate;
}
@Override
public void setDefaultRawSqlIfRequired() {
if (beanDescriptor.isRawSqlBased() && rawSql == null) {
rawSql = beanDescriptor.getNamedRawSql(DEFAULT_QUERY_NAME);
}
}
@Override
public DefaultOrmQuery<T> setAutoTune(boolean autoTune) {
this.autoTune = autoTune;
@@ -1171,7 +1170,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public DefaultOrmQuery<T> order(String orderByClause) {
if (orderByClause == null || orderByClause.trim().length() == 0) {
if (orderByClause == null || orderByClause.trim().isEmpty()) {
this.orderBy = null;
} else {
this.orderBy = new OrderBy<T>(this, orderByClause);
@@ -1376,6 +1375,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
this.generatedSql = generatedSql;
}
@Override
public void setDefaultFetchBuffer(int fetchSize) {
if (bufferFetchSizeHint == 0) {
bufferFetchSizeHint = fetchSize;
}
}
@Override
public Query<T> setBufferFetchSizeHint(int bufferFetchSizeHint) {
this.bufferFetchSizeHint = bufferFetchSizeHint;
@@ -134,7 +134,7 @@ public class OrmQueryDetailParser {
}
}
String whereClause = sb.toString().trim();
if (whereClause.length() > 0) {
if (!whereClause.isEmpty()) {
rawWhereClause = whereClause;
}
@@ -146,11 +146,10 @@ public class OrmQueryDetailParser {
}
private void readSelect() {
String path = null;
String props = parser.nextWord();
if (props.startsWith("(")) {
props = props.substring(1, props.length() - 1);
OrmQueryProperties base = new OrmQueryProperties(path, props);
OrmQueryProperties base = new OrmQueryProperties(null, props);
detail.setBase(base);
parser.nextWord();
} else {
@@ -236,7 +236,7 @@ public class OrmQueryProperties implements Serializable {
@SuppressWarnings("unchecked")
public void configureBeanQuery(SpiQuery<?> query) {
if (trimmedProperties != null && trimmedProperties.length() > 0) {
if (trimmedProperties != null && !trimmedProperties.isEmpty()) {
query.select(trimmedProperties);
}
@@ -122,7 +122,7 @@ public class OrmQueryPropertiesParser {
String temp;
for (int i = 0; i < res.length; i++) {
temp = res[i].trim();
if (temp.length() > 0) {
if (!temp.isEmpty()) {
if (count > 0) {
sb.append(",");
}
@@ -72,6 +72,7 @@ public class OrmUpdateProperties {
@Override
public void bind(Binder binder, DataBind dataBind) throws SQLException {
binder.bindObject(dataBind, value);
dataBind.append(value).append(",");
}
}
@@ -105,6 +106,7 @@ public class OrmUpdateProperties {
public void bind(Binder binder, DataBind dataBind) throws SQLException {
for (Object val : bindValues) {
binder.bindObject(dataBind, val);
dataBind.append(val).append(",");
}
}
}
@@ -268,7 +268,7 @@ public class TCsvReader<T> implements CsvReader<T> {
strValue = strValue.trim();
if (strValue.length() == 0) {
if (strValue.isEmpty()) {
return;
}
@@ -402,12 +402,7 @@ public class TransactionManager {
public void notifyOfCommit(SpiTransaction transaction) {
try {
if (transaction.isExplicit()) {
if (TXN_LOGGER.isInfoEnabled()) {
TXN_LOGGER.info(transaction.getLogPrefix() + "Commit");
}
} else if (TXN_LOGGER.isDebugEnabled()) {
if (TXN_LOGGER.isDebugEnabled()) {
TXN_LOGGER.debug(transaction.getLogPrefix() + "Commit");
}
@@ -11,6 +11,7 @@ import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.dbmigration.DbOffline;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutable;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
@@ -156,6 +157,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final boolean postgres;
private final boolean offlineMigrationGeneration;
// OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath
/**
@@ -198,6 +201,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
this.extraTypeFactory = new DefaultTypeFactory(config);
this.postgres = isPostgres(config.getDatabasePlatform());
this.offlineMigrationGeneration = DbOffline.isGenerateMigration();
initialiseStandard(jsonDateTime, config);
initialiseJavaTimeTypes(jsonDateTime, config);
@@ -961,15 +965,13 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
nativeMap.put(Types.BIT, booleanType);
}
boolean nativeUuidType = databasePlatform.isNativeUuidType();
ServerConfig.DbUuid dbUuid = config.getDbUuid();
if (nativeUuidType && dbUuid == ServerConfig.DbUuid.AUTO) {
// DB has native support for UUID
if (offlineMigrationGeneration || (databasePlatform.isNativeUuidType() && dbUuid.useNativeType())) {
typeMap.put(UUID.class, new ScalarTypeUUIDNative());
} else {
// Store UUID as binary(16) or varchar(40)
ScalarType<?> uuidType = (ServerConfig.DbUuid.BINARY == dbUuid) ? new ScalarTypeUUIDBinary() : new ScalarTypeUUIDVarchar();
ScalarType<?> uuidType = dbUuid.useBinary() ? new ScalarTypeUUIDBinary() : new ScalarTypeUUIDVarchar();
typeMap.put(UUID.class, uuidType);
}
@@ -35,7 +35,7 @@ public class ScalarTypeChar extends ScalarTypeBaseVarchar<Character> {
public Character read(DataReader dataReader) throws SQLException {
String string = dataReader.getString();
if (string == null || string.length() == 0) {
if (string == null || string.isEmpty()) {
return null;
} else {
return string.charAt(0);
@@ -0,0 +1,12 @@
package com.avaje.ebeaninternal.server.type;
/**
* Marks types that can be mapped differently to different DB platforms.
*/
public interface ScalarTypeLogicalType {
/**
* Return the DB agnostic logical type.
*/
int getLogicalType();
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -13,12 +14,17 @@ import java.util.UUID;
/**
* Base UUID type for string formatting, json handling etc.
*/
public abstract class ScalarTypeUUIDBase extends ScalarTypeBase<UUID> {
public abstract class ScalarTypeUUIDBase extends ScalarTypeBase<UUID> implements ScalarTypeLogicalType {
public ScalarTypeUUIDBase(boolean jdbcNative, int jdbcType) {
super(UUID.class, jdbcNative, jdbcType);
}
@Override
public int getLogicalType() {
return DbType.UUID;
}
@Override
public boolean isMutable() {
return false;

Some files were not shown because too many files have changed in this diff Show More