Compare commits

...
Author SHA1 Message Date
rob bygrave c6c5073e47 [maven-release-plugin] prepare release ebean-10.4.2 2017-08-04 21:33:19 +12:00
rob bygrave 2a58b954e9 #1062 - Multi-tenant - Update statements should include tenantId in where clause 2017-08-04 21:16:14 +12:00
Koen De GrooteandRob Bygrave 9772623880 Added the Serializable interface to classes that extend/implement a Comparator with an anonymous/typed class. (#1078) 2017-08-03 23:29:56 +12:00
rob bygrave 27b6183aad Merge branch 'master' of github.com:ebean-orm/ebean 2017-08-03 23:28:35 +12:00
David HofmannandRob Bygrave 55e19618f8 fix connection leak in JTA managed transactions (#1077) 2017-08-03 23:28:21 +12:00
rob bygrave 5c60ba4d7f Update test for WriteJson to just use PathProperties 2017-08-03 23:01:22 +12:00
rob bygrave b9cc584086 #1080 - NOT IN expression using entity beans / reference beans uses "in" 2017-08-03 20:31:18 +12:00
Koen De GrooteandRob Bygrave bf5a8c2fad Changed some boolean checks to use the recommended method of comparing floating point values in Java. (#1075) 2017-07-22 13:00:24 +12:00
rob bygrave 66138e5ea2 #1070 Fix for - Create test for bean cache not being cleared with delete or update queries 2017-07-21 23:31:23 +12:00
Rien Nentjes 75fb89ef76 Create test for bean cache not being cleared with delete or update queries 2017-07-14 11:04:43 +02:00
rob bygrave a2cb468222 No effective change - add test resource ebean.mf to hint to enhancement agent packages to enhance 2017-07-11 21:11:54 +12:00
rob bygrave 166bcd7c45 #1061 - findCount query is not cached in L2 query cache 2017-07-06 21:51:52 +12:00
rob bygrave 95aed6af54 #1060 - findSingleAttributeList doesn't store result in L2 query cache 2017-07-06 21:35:20 +12:00
rob bygrave 7a697c12af No effective change - moved mssql-jdbc down with other test scope dependencies 2017-07-06 21:11:40 +12:00
rob bygrave 23278ce30b #1058 - Refactor - PlatformPrefix isn't actually used in PlatformDddlWriter, removing. 2017-07-06 20:30:20 +12:00
Koen De GrooteandRob Bygrave 36a5610e25 Using Regular expression objects for splitting and replacing in strings. (#1059)
* Where possible, replace .split() and .replace() methods with compiled Regex patterns.
This prevents a regular expression from being compiled multiple times during runtime.

* Forgot making one instance `private static final`.
2017-07-06 20:14:51 +12:00
rob bygrave 08263c4588 [maven-release-plugin] prepare for next development iteration 2017-07-05 21:41:12 +12:00
rob bygrave 1e88a52208 [maven-release-plugin] prepare release ebean-10.4.1 2017-07-05 21:40:58 +12:00
rob bygrave e770a42175 Bump to 10.4.1-SNAPSHOT (due to ServerConfig h2ProductionMode removal) 2017-07-05 21:39:12 +12:00
Thibault MeyerandRob Bygrave 35b467c04f JSON simple implementation for MSSQL (#1057)
- Use JSON_VALUE
  - Use NVARCHAR type

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-07-03 20:45:48 +12:00
Roland PramlandRob Bygrave 2001539755 Sqlserver support (#1053)
* made some tests sqlserver ready (No effective code change in src/main)

* FIX enhance packages and let all testcases inherit from BaseTestCase, so that they can be launched directly from eclipse

* ADD sqldriver in pom and datasource

* FIX: DDL-generation for sqlserver - not yet all sqlserver tests passing
mvn verify -Ddatasource.default=mssql => Tests run: 1980, Failures: 22, Errors: 44, Skipped: 16

* BaseDdlHandlerTest checks against correct sqlserver-ddl now
2017-07-03 20:27:37 +12:00
rob bygrave e49c4bfe5a #867 - ENH: Add ability to globally use quoted identifiers on all tables and columns 2017-07-02 21:07:58 +12:00
rob bygrave 15be31fd5f #1051 - Remove ServerConfig h2ProductionMode ... means for testing with h2 explicitly set ddlGenerate and ddlRun 2017-07-02 11:42:56 +12:00
rob bygrave 4777ec46be #1050 - Bump db-migration to 10.1.10 2017-07-02 11:12:03 +12:00
rob bygrave 80ab731aec Use older postgres jdbc driver 2017-06-25 22:56:21 +12:00
rob bygrave 080bafe18f #1048 - Fix connection leak on failed findIterate() 2017-06-25 22:39:04 +12:00
rob bygrave e913f88f52 Fix test - TestCommitAndContinue ... close extra transactions used in asserts 2017-06-25 21:43:37 +12:00
rob bygrave e94c5484a0 #1047 - Fix connection leak on failed beginTransaction() 2017-06-25 21:42:51 +12:00
rob bygrave 4af00c51d3 travis - dist: trusty ... to get PG 9.6 2017-06-25 19:57:31 +12:00
rob bygrave 23d1256dbf Update to postgres 9.6 for travis test runs 2017-06-25 19:43:05 +12:00
rob bygrave ed0ef46d2e No effective change - update postgresql jdbc driver 2017-06-25 19:03:07 +12:00
rob bygrave 1860ded735 [maven-release-plugin] prepare for next development iteration 2017-06-25 16:01:50 +12:00
rob bygrave d432854b82 [maven-release-plugin] prepare release ebean-10.3.2 2017-06-25 16:01:37 +12:00
rob bygrave 93582c8ea3 Downgrade postgres jdbc driver for commit and continue test 2017-06-25 15:54:14 +12:00
rob bygrave 520d35b1d6 #963 - NullPointerException on no version provided (when setVersion(null) is used) 2017-06-25 14:44:13 +12:00
rob bygrave 8ca3599cbf #1046 Bump DB migration to 10.1.9 - fix for Checksum mismatch does not stop migration 2017-06-25 14:29:46 +12:00
rob bygrave 283ae74219 Update javadoc on ScalarTypeConverter. Should look to officially deprecate this in favor of AttributeConverter. 2017-06-24 11:35:58 +12:00
rob bygrave cebd3f92a4 #1045 - MySql - DbMigration generate wrong comment syntax - should be alter table comment = syntax 2017-06-24 11:23:21 +12:00
rob bygrave 4b2481d3ea #1039 Fix for - reset of dirty flag on L2 cached entities after lazy load 2017-06-23 23:20:17 +12:00
rob bygrave f1f2a416d3 No effective change - reformat only 2017-06-23 23:19:22 +12:00
rob bygrave 74dd97a55f No effective change 2017-06-23 23:18:57 +12:00
rob bygrave 3f04f7f363 Merge branch 'master' of https://github.com/SamhammerAG/ebean into SamhammerAG-master 2017-06-23 19:52:55 +12:00
rob bygrave 800f854a12 #1043 Additional test for RawSql with upper case SQL 2017-06-23 19:46:47 +12:00
rob bygrave bef9e6d54f Merge branch 'master' of github.com:ebean-orm/ebean 2017-06-23 19:43:45 +12:00
Tigran_DadaiantsandRob Bygrave 0e4c0ae6c3 #1043 RawSql should automatically map upper-case column alias to lower-case bean property (#1044) 2017-06-23 19:43:15 +12:00
rob bygrave a0ea9887df No effective change - remove unused imports 2017-06-23 19:37:24 +12:00
Roland PramlandRob Bygrave 0413c22e6e no effective code change - fixed warnings about serialization, override, raw-types (#1032) 2017-06-23 19:33:03 +12:00
rob bygrave 989ae44a6d Merge branch 'pr/id-in-as-collection' of https://github.com/FOCONIS/ebean into FOCONIS-pr/id-in-as-collection 2017-06-23 19:28:25 +12:00
rob bygrave 100d314e63 #1035 Update for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB
If use Modify mode we need to listen for both adds and removes to support sorting (can't rely on undoDelete() due to ordering)
2017-06-19 23:34:44 +12:00
rob bygrave dbf4e99187 #1035 tests for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB 2017-06-19 23:32:58 +12:00
Roland PramlandRob Bygrave 7b8a85106c FIX: deleting and adding same bean in beanCollection leads to deletion in DB (#1035) 2017-06-19 22:50:20 +12:00
rob bygrave 58c5f01e2b #1042 - JtaTransaction is TenantMode.DB aware 2017-06-19 22:28:15 +12:00
Roland PramlandRob Bygrave bc74d35651 FIX: correct behavior of "startsWith, "contains" etc (#1031)
* FIX: correct behavior of "startsWith" if string contains "like"-wildcards

* Removed likeClasues with disabled escaping in database platforms as bind values are properly escaped now.
2017-06-19 22:21:26 +12:00
Roland PramlandRob Bygrave a1f95bf25e Pr/id in as collection2 (#1034)
* ENH: Changed  idIn(List) to idIn(Collection)

* ADD: sanity checks in IdBinder & special case if ID-list is empty
2017-06-19 22:05:56 +12:00
rob bygrave c454e1f8a7 No effective change - add test 2017-06-19 21:53:35 +12:00
Koen De GrooteandRob Bygrave 5a3669e1db Noticed that this boolean parameter was ignored. (#1041)
After some quick analysis, implemented that way it probably should be used.

Of course, this could have been on purpose, please advise.
2017-06-19 21:39:58 +12:00
rob bygrave 7a2e0b3695 Bump to the later agent 2017-06-19 21:34:18 +12:00
AWoelfel ce6d6269cd Step to reproduce reset of dirty flag on L2 cached entities after lazy load 2017-06-08 15:07:32 +02:00
Roland Praml 7d800b7080 ENH: Changed idIn(List) to idIn(Collection) 2017-05-29 15:22:48 +02:00
rob bygrave 136154e247 [maven-release-plugin] prepare for next development iteration 2017-05-21 21:56:29 +12:00
170 changed files with 1622 additions and 513 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
dist: trusty
sudo: required
language: java
jdk:
@@ -7,7 +8,7 @@ git:
depth: 3
addons:
postgresql: "9.4"
postgresql: "9.6"
services:
- postgresql
+13 -6
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>10.3.1</version>
<version>10.4.2</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -17,7 +17,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-10.3.1</tag>
<tag>ebean-10.4.2</tag>
</scm>
<dependencies>
@@ -67,7 +67,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-dbmigration</artifactId>
<version>10.1.8</version>
<version>10.1.10</version>
</dependency>
<dependency>
@@ -130,7 +130,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212.jre7</version>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
@@ -160,7 +160,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>10.1.7</version>
<version>10.3.1</version>
<scope>test</scope>
</dependency>
@@ -187,6 +187,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.1.3.jre8-preview</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@@ -225,7 +232,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>10.1.7</version>
<version>10.3.1</version>
<executions>
<execution>
<id>test</id>
@@ -10,6 +10,7 @@ import javax.persistence.PessimisticLockException;
* </p>
*/
public class AcquireLockException extends PessimisticLockException {
private static final long serialVersionUID = -8585962352965876691L;
/**
* Create with a message and cause.
@@ -2,6 +2,7 @@ package io.ebean;
import io.ebean.RawSql.ColumnMapping;
import java.util.regex.Pattern;
import javax.persistence.PersistenceException;
import java.util.ArrayList;
@@ -10,6 +11,8 @@ import java.util.ArrayList;
*/
final class DRawSqlColumnsParser {
private static final Pattern COLINFO_SPLIT = Pattern.compile("\\s(?=[^\\)]*(?:\\(|$))");
private final int end;
private final String sqlSelect;
@@ -44,7 +47,7 @@ final class DRawSqlColumnsParser {
String colInfo = sqlSelect.substring(start, pos++);
colInfo = colInfo.trim();
String[] split = colInfo.split("\\s(?=[^\\)]*(?:\\(|$))");
String[] split = COLINFO_SPLIT.split(colInfo);
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<>(split.length);
for (String aSplit : split) {
@@ -6,6 +6,7 @@ import javax.persistence.PersistenceException;
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
/**
* Create with a message and cause.
@@ -4,6 +4,7 @@ package io.ebean;
* Thrown when a duplicate is attempted on a unique constraint.
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
/**
* Create with a message and cause.
@@ -7,7 +7,6 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -308,9 +307,9 @@ public interface ExpressionFactory {
Expression idIn(Object... idValues);
/**
* Id IN a list of Id values.
* Id IN a collection of Id values.
*/
Expression idIn(List<?> idList);
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
+2 -2
View File
@@ -836,9 +836,9 @@ public interface ExpressionList<T> {
ExpressionList<T> idIn(Object... idValues);
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
ExpressionList<T> idIn(List<?> idValues);
ExpressionList<T> idIn(Collection<?> idValues);
/**
* Id Equal to - ID property is equal to the value.
+4 -4
View File
@@ -6,22 +6,22 @@ package io.ebean;
public enum LikeType {
/**
* You need to put in your own wildcards.
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word.
* The % wildcard is added to the end of the search word and search word is escaped.
*/
STARTS_WITH,
/**
* The % wildcard is added to the beginning of the search word.
* The % wildcard is added to the beginning of the search word and search word is escaped.
*/
ENDS_WITH,
/**
* The % wildcard is added to the beginning and end of the search word.
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
+1
View File
@@ -129,6 +129,7 @@ public interface Transaction extends AutoCloseable {
/**
* Synonym for end() to support AutoClosable.
*/
@Override
void close();
/**
@@ -1027,7 +1027,7 @@ public final class EntityBeanIntercept implements Serializable {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
} else if (Double.compare(oldValue, newValue) != 0) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
@@ -1042,7 +1042,7 @@ public final class EntityBeanIntercept implements Serializable {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
} else if (Float.compare(oldValue, newValue) != 0) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
@@ -47,8 +47,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
@@ -148,9 +147,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
public void setModifyListening(ModifyListenMode mode) {
this.modifyListenMode = mode;
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
this.modifyListening = modifyRemoveListening || modifyAddListening;
this.modifyListening = mode != null && ModifyListenMode.NONE != mode;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
@@ -173,14 +170,14 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
@Override
public void modifyAddition(E bean) {
if (modifyAddListening) {
if (modifyListening) {
getModifyHolder().modifyAddition(bean);
}
}
@Override
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
if (modifyListening) {
getModifyHolder().modifyRemoval(bean);
}
}
+9 -9
View File
@@ -232,7 +232,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
modifyAddition(element);
}
list.add(index, element);
@@ -247,7 +247,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
@@ -262,7 +262,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
@@ -273,7 +273,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
@@ -286,7 +286,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E aList : list) {
getModifyHolder().modifyRemoval(aList);
}
@@ -380,7 +380,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
@@ -392,7 +392,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
@@ -406,7 +406,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (list.remove(bean)) {
@@ -424,7 +424,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public boolean retainAll(Collection<?> retainBeans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
+2 -2
View File
@@ -211,7 +211,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
@@ -313,7 +313,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
+6 -6
View File
@@ -210,7 +210,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
@@ -225,7 +225,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
boolean changed = false;
for (E bean : addCollection) {
if (set.add(bean)) {
@@ -243,7 +243,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E bean : set) {
modifyRemoval(bean);
}
@@ -285,7 +285,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
@@ -299,7 +299,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (set.remove(bean)) {
@@ -316,7 +316,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
@@ -44,21 +44,29 @@ class ModifyHolder<E> implements Serializable {
}
}
private boolean undoDeletion(E bean) {
return (bean != null) && modifyDeletions.remove(bean);
}
void modifyAddition(E bean) {
if (bean != null) {
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
if (!undoDeletion(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
private boolean undoAddition(Object bean) {
return (bean != null) && modifyAdditions.remove(bean);
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove(bean)) {
if (!undoAddition(bean)) {
modifyDeletions.add((E) bean);
}
}
@@ -2,6 +2,8 @@ package io.ebean.config;
import io.ebean.config.dbplatform.DatabasePlatform;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Inheritance;
import javax.persistence.Table;
@@ -14,16 +16,15 @@ import java.lang.annotation.Annotation;
*/
public abstract class AbstractNamingConvention implements NamingConvention {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
private static final Pattern COLUMN_REPLACE = Pattern.compile("{column}", Pattern.LITERAL);
/**
* The Constant DEFAULT_SEQ_FORMAT.
*/
public static final String DEFAULT_SEQ_FORMAT = "{table}_seq";
/**
* Sequence Format that includes the Primary Key column
*/
public static final String TABLE_PKCOLUMN_SEQ_FORMAT = "{table}_{column}_seq";
/**
* The catalog.
*/
@@ -83,11 +84,11 @@ public abstract class AbstractNamingConvention implements NamingConvention {
@Override
public String getSequenceName(String tableName, String pkColumn) {
String s = sequenceFormat.replace("{table}", tableName);
String s = TABLE_REPLACE.matcher(sequenceFormat).replaceAll(Matcher.quoteReplacement(tableName));
if (pkColumn == null) {
pkColumn = "";
}
return s.replace("{column}", pkColumn);
return COLUMN_REPLACE.matcher(s).replaceAll(Matcher.quoteReplacement(pkColumn));
}
/**
@@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
/**
* Configuration for the DB migration processing.
@@ -443,7 +444,7 @@ public class DbMigrationConfig {
/**
* Create the MigrationRunner to run migrations if necessary.
*/
public MigrationRunner createRunner(ClassLoader classLoader) {
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
MigrationConfig runnerConfig = new MigrationConfig();
runnerConfig.setMetaTable(metaTable);
@@ -454,6 +455,9 @@ public class DbMigrationConfig {
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
runnerConfig.setClassLoader(classLoader);
if (properties != null) {
runnerConfig.load(properties);
}
return new MigrationRunner(runnerConfig);
}
}
@@ -31,7 +31,7 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
@Override
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
return propertyName;
return quoteIdentifiers(propertyName);
}
@Override
@@ -47,8 +47,11 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
@Override
public String getForeignKey(String prefix, String fkProperty) {
prefix = databasePlatform.unQuote(prefix);
fkProperty = databasePlatform.unQuote(fkProperty);
// add fkProperty as init caps
return prefix + fkProperty.substring(0, 1).toUpperCase() + fkProperty.substring(1);
String fullName = prefix + fkProperty.substring(0, 1).toUpperCase() + fkProperty.substring(1);
return quoteIdentifiers(fullName);
}
}
@@ -1,5 +1,7 @@
package io.ebean.config;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,6 +20,8 @@ final class PropertyMapLoader {
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
private static final Pattern OTHER_PROPS_REPLACE = Pattern.compile("\\", Pattern.LITERAL);
/**
* Load the <code>test-ebean.properties</code>.
*/
@@ -109,7 +113,7 @@ final class PropertyMapLoader {
otherProps = p.remove("load.properties.override");
}
if (otherProps != null) {
otherProps = otherProps.replace("\\", "/");
otherProps = OTHER_PROPS_REPLACE.matcher(otherProps).replaceAll(Matcher.quoteReplacement("/"));
InputStream is = findInputStream(otherProps);
if (is != null) {
logger.debug("loading properties from {}", otherProps);
@@ -1,27 +1,24 @@
package io.ebean.config;
/**
* Matches the functionality of javax.persistence.AttributeConverter
* <p>
* In general AttributeConverter should be used in preference to this
* ScalarTypeConverter as it is JPA standard and offers the same functionality.
* </p>
* <p>
* For Ebean we will look to deprecate this interface in preference to AttributeConverter.
* </p>
* <p>
* Used to convert between a value object and a known scalar type. The value
* object is the logical type used in your application and the scalar type is
* the value used to persist than to the DB.
* </p>
* <p>
* The Value object should be immutable and scalar (aka not compound) and
* converts to and from a known scalar type which Ebean will use to persist the
* value.
* </p>
* <p>
* This is an easier alternative to implementing the
* io.ebean.server.type.ScalarType interface.
* </p>
* <p>
* Note that Ebean will automatically try to detect Immutable Scalar Value
* Objects and automatically support them via reflection. This however would not
* be appropriate when the logical type is different from the type you wish to
* use for persistence - for example, if the logical type was long and you
* wanted to use java.sql.Timestamp for persistence. In this case you would want
* to implement this interface rather than let Ebean automatically support that
* type via reflection.
* </p>
*
* @param <B> The value object type.
* @param <S> The scalar object type that is used to persist the value object.
+31 -36
View File
@@ -27,6 +27,7 @@ import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetaInfoManager;
import java.util.regex.Pattern;
import org.avaje.datasource.DataSourceConfig;
import javax.sql.DataSource;
@@ -75,17 +76,13 @@ import java.util.ServiceLoader;
*/
public class ServerConfig {
private static final Pattern NAMES_SPLIT = Pattern.compile("[ ,;]");
/**
* The EbeanServer name.
*/
private String name = "db";
/**
* When false (default) H2 automatically uses DDL generate and run
* (i.e. assumes we are running tests using in memory h2).
*/
private boolean h2ProductionMode;
/**
* Typically configuration type objects that are passed by this ServerConfig
* to plugins. For example - IgniteConfiguration passed to Ignite plugin.
@@ -319,6 +316,8 @@ public class ServerConfig {
*/
private String databaseBooleanFalse;
private boolean allQuotedIdentifiers;
/**
* The naming convention.
*/
@@ -527,27 +526,6 @@ public class ServerConfig {
this.name = name;
}
/**
* Return true if H2 should be used in production mode.
* <p>
* Otherwise it is assumed we are using H2 for testing and DDL generate and run is turned on.
* </p>
*/
public boolean isH2ProductionMode() {
return h2ProductionMode;
}
/**
* Set to true for H2 to be used in production mode.
* <p>
* Do this when we want to use H2 and not have the DDL generation and run automatically turned on.
* Otherwise it is assumed we are using H2 for testing purposes.
* </p>
*/
public void setH2ProductionMode(boolean h2ProductionMode) {
this.h2ProductionMode = h2ProductionMode;
}
/**
* Return the container / clustering configuration.
* <p/>
@@ -1301,6 +1279,24 @@ public class ServerConfig {
this.namingConvention = namingConvention;
}
/**
* Return true if all DB column and table names should use quoted identifiers.
*/
public boolean isAllQuotedIdentifiers() {
return allQuotedIdentifiers;
}
/**
* Set to true if all DB column and table names should use quoted identifiers.
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
if (allQuotedIdentifiers && namingConvention instanceof UnderscoreNamingConvention) {
// we need to use matching naming convention
this.namingConvention = new MatchingNamingConvention();
}
}
/**
* Return true if this EbeanServer is a Document store only instance (has no JDBC DB).
*/
@@ -1567,11 +1563,6 @@ public class ServerConfig {
*/
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
if (!h2ProductionMode && databasePlatform != null && databasePlatform.isPlatform(Platform.H2)) {
// we are using H2 to run tests so turn on DDL generation and run
this.ddlGenerate = true;
this.ddlRun = true;
}
}
/**
@@ -2504,6 +2495,11 @@ public class ServerConfig {
migrationConfig.loadSettings(p, name);
boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers);
if (quotedIdentifiers != allQuotedIdentifiers) {
// potentially also set to use matching naming convention
setAllQuotedIdentifiers(quotedIdentifiers);
}
namingConvention = createNamingConvention(p, namingConvention);
if (namingConvention != null) {
namingConvention.loadFromProperties(p);
@@ -2610,7 +2606,6 @@ public class ServerConfig {
jsonDateTime = JsonConfig.DateTime.MILLIS;
}
h2ProductionMode = p.getBoolean("h2ProductionMode", h2ProductionMode);
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun);
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
@@ -2641,7 +2636,7 @@ public class ServerConfig {
List<Class<?>> classes = new ArrayList<>();
String[] split = classNames.split("[ ,;]");
String[] split = NAMES_SPLIT.split(classNames);
for (String aSplit : split) {
String cn = aSplit.trim();
if (!cn.isEmpty() && !"class".equalsIgnoreCase(cn)) {
@@ -2662,7 +2657,7 @@ public class ServerConfig {
if (searchPackages != null) {
String[] entries = searchPackages.split("[ ,;]");
String[] entries = NAMES_SPLIT.split(searchPackages);
for (String entry : entries) {
hitList.add(entry.trim());
}
@@ -2755,7 +2750,7 @@ public class ServerConfig {
*/
public DataSource runDbMigration(DataSource dataSource) {
if (migrationConfig.isRunMigration()) {
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader());
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
runner.run(dataSource);
}
return dataSource;
@@ -64,6 +64,11 @@ public class DatabasePlatform {
*/
protected String closeQuote = "\"";
/**
* When set to true all db column names and table names use quoted identifiers.
*/
protected boolean allQuotedIdentifiers;
/**
* For limit/offset, row_number etc limiting of SQL queries.
*/
@@ -175,6 +180,8 @@ public class DatabasePlatform {
protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();
protected char[] specialLikeCharacters = { '%', '_' };
/**
* Instantiates a new database platform.
*/
@@ -191,7 +198,8 @@ public class DatabasePlatform {
/**
* Configure UUID Storage etc based on ServerConfig settings.
*/
public void configure(DbTypeConfig config) {
public void configure(DbTypeConfig config, boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
addGeoTypes(config.getGeometrySRID());
configureIdType(config.getIdType());
dbTypeMap.config(nativeUuidType, config.getDbUuid());
@@ -533,24 +541,33 @@ public class DatabasePlatform {
* naming rules.
* </p>
*
* @param dbName the db name
* @return the string
* @param dbName the db table or column name
* @return the db table or column name with potentially platform specific quoted identifiers
*/
public String convertQuotedIdentifiers(String dbName) {
// Ignore null values e.g. schema name or catalog
if (dbName != null && !dbName.isEmpty()) {
if (dbName.charAt(0) == BACK_TICK) {
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
String quotedName = getOpenQuote();
quotedName += dbName.substring(1, dbName.length() - 1);
quotedName += getCloseQuote();
return quotedName;
return openQuote + dbName.substring(1, dbName.length() - 1) + closeQuote;
} else {
logger.error("Missing backquote on [" + dbName + "]");
}
} else if (allQuotedIdentifiers) {
return openQuote + dbName + closeQuote;
}
}
return dbName;
}
/**
* Remove quoted identifier quotes from the table or column name if present.
*/
public String unQuote(String dbName) {
if (dbName != null && !dbName.isEmpty()) {
if (dbName.startsWith(openQuote)) {
// trim off the open and close quotes
return dbName.substring(1, dbName.length()-1);
}
}
return dbName;
@@ -617,4 +634,37 @@ public class DatabasePlatform {
logger.error("Error closing resultSet", e);
}
}
/**
* Escapes the like string for this DB-Platform
*/
public String escapeLikeString(String value) {
StringBuilder sb = null;
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
boolean escaped = false;
for (char escapeChar: specialLikeCharacters) {
if (ch == escapeChar) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
escapeLikeCharacter(escapeChar, sb);
escaped = true;
break;
}
}
if (!escaped && sb != null) {
sb.append(ch);
}
}
if (sb == null) {
return value;
} else {
return sb.toString();
}
}
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('\\').append(ch);
}
}
@@ -1,12 +1,16 @@
package io.ebean.config.dbplatform;
import io.ebean.dbmigration.migration.IdentityType;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Defines the identity/sequence behaviour for the database.
*/
public class DbIdentity {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
/**
* Set if this DB supports sequences. Note some DB's support both Sequences
* and Identity.
@@ -50,7 +54,8 @@ public class DbIdentity {
if (selectLastInsertedIdTemplate == null) {
return null;
}
return selectLastInsertedIdTemplate.replace("{table}", table);
return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table));
}
/**
@@ -40,10 +40,6 @@ public class H2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
this.likeClause = "like ?";
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
}
@@ -30,7 +30,6 @@ public class MySqlPlatform extends DatabasePlatform {
super();
this.platform = Platform.MYSQL;
this.useExtraTransactionOnIterateSecondaryQueries = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
this.platformDdl = new MySqlDdl(this);
@@ -28,7 +28,6 @@ public class PostgresPlatform extends DatabasePlatform {
super();
this.platform = Platform.POSTGRES;
this.supportsNativeIlike = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
@@ -8,7 +8,6 @@ import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.platform.SqlServerDdl;
import java.sql.Types;
/**
@@ -35,12 +34,14 @@ public class SqlServerPlatform extends DatabasePlatform {
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("1222")
.addDuplicateKey("2601","2627")
.addDataIntegrity("544","8114","8115")
.addDuplicateKey("2601", "2627")
.addDataIntegrity("544", "8114", "8115")
.build();
this.openQuote = "[";
this.closeQuote = "]";
this.specialLikeCharacters = new char[]{'%', '_', '['};
this.likeClause = "like ? COLLATE Latin1_General_BIN";
booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
@@ -61,6 +62,13 @@ public class SqlServerPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.TIME, new DbPlatformType("time"));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2"));
dbTypeMap.put(DbType.JSON, new DbPlatformType("nvarchar(max)"));
dbTypeMap.put(DbType.JSONB, new DbPlatformType("nvarchar(max)"));
}
@Override
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('[').append(ch).append(']');
}
}
@@ -374,7 +374,7 @@ public class DbMigration {
// 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, "");
PlatformDdlWriter writer = createDdlWriter(databasePlatform);
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
}
}
@@ -431,7 +431,7 @@ public class DbMigration {
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter platformWriter = createDdlWriter(pair);
PlatformDdlWriter platformWriter = createDdlWriter(pair.platform);
File subPath = platformWriter.subPath(writePath, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
@@ -439,12 +439,8 @@ public class DbMigration {
}
}
private PlatformDdlWriter createDdlWriter(Pair pair) {
return createDdlWriter(pair.platform, pair.prefix);
}
private PlatformDdlWriter createDdlWriter(DatabasePlatform platform, String prefix) {
return new PlatformDdlWriter(platform, serverConfig, prefix, migrationConfig);
private PlatformDdlWriter createDdlWriter(DatabasePlatform platform) {
return new PlatformDdlWriter(platform, serverConfig, migrationConfig);
}
/**
@@ -54,6 +54,8 @@ public class BaseTableDdl implements TableDdl {
* Used when unique constraints specifically for OneToOne can't be created normally (MsSqlServer).
*/
protected List<Column> externalUnique = new ArrayList<>();
protected List<UniqueConstraint> externalCompoundUnique = new ArrayList<>();
// counters used when constraint names are truncated due to maximum length
// and these counters are used to keep the constraint name unique
@@ -85,6 +87,7 @@ public class BaseTableDdl implements TableDdl {
protected void reset() {
indexSet.clear();
externalUnique.clear();
externalCompoundUnique.clear();
countCheck = 0;
countUnique = 0;
countForeignKey = 0;
@@ -213,6 +216,18 @@ public class BaseTableDdl implements TableDdl {
.append(platformDdl.dropIndex(uqName, tableName))
.endOfStatement();
}
for (UniqueConstraint constraint : externalCompoundUnique) {
String uqName = constraint.getName();
String[] columnNames = StringHelper.delimitedToArray(constraint.getColumnNames(), ",", false);
write.apply()
.append(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames))
.endOfStatement();
write.dropAllForeignKeys()
.append(platformDdl.dropIndex(uqName, tableName))
.endOfStatement();
}
}
protected void writeSequence(DdlWrite writer, CreateTable createTable, String pk) throws IOException {
@@ -406,12 +421,17 @@ public class BaseTableDdl implements TableDdl {
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
List<UniqueConstraint> uniqueConstraints = createTable.getUniqueConstraint();
boolean inlineUniqueCompound = platformDdl.isInlineUniqueOneToOne();
for (UniqueConstraint uniqueConstraint : uniqueConstraints) {
String uqName = uniqueConstraint.getName();
String[] columns = toColumnNamesSplit(uniqueConstraint.getColumnNames());
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(columns, apply);
if (inlineUniqueCompound) {
String uqName = uniqueConstraint.getName();
String[] columns = toColumnNamesSplit(uniqueConstraint.getColumnNames());
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(columns, apply);
} else {
externalCompoundUnique.add(uniqueConstraint);
}
}
}
@@ -832,22 +852,11 @@ 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(convertedType);
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
buffer.append(" not null");
}
if (hasValue(column.getCheckConstraint())) {
buffer.append(" constraint ").append(column.getCheckConstraintName());
buffer.append(" ").append(column.getCheckConstraint());
}
String ddl = platformDdl.alterTableAddColumn(tableName, column, onHistoryTable);
if (hasValue(ddl)) {
buffer.append(ddl);
buffer.endOfStatement();
}
buffer.endOfStatement();
}
protected boolean isFalse(Boolean value) {
@@ -101,4 +101,11 @@ public class MySqlDdl extends PlatformDdl {
apply.append(" comment='").append(tableComment).append("'");
}
/**
* Add table comment as a separate statement (from the create table statement).
*/
@Override
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
apply.append(String.format("alter table %s comment = '%s'", tableName, tableComment)).endOfStatement();
}
}
@@ -17,6 +17,7 @@ import io.ebean.dbmigration.migration.Column;
import io.ebean.dbmigration.migration.DropHistoryTable;
import io.ebean.dbmigration.migration.IdentityType;
import io.ebean.dbmigration.model.MTable;
import io.ebean.util.StringHelper;
import java.io.IOException;
import java.util.List;
@@ -74,6 +75,8 @@ public class PlatformDdl {
protected String dropUniqueConstraint = "drop constraint";
protected String addConstraint = "add constraint";
protected String addColumn = "add column";
protected String columnSetType = "";
@@ -375,6 +378,27 @@ public class PlatformDdl {
appendColumns(columns, buffer);
return buffer.toString();
}
public String alterTableAddColumn(String tableName, Column column, boolean onHistoryTable) throws IOException {
String convertedType = convert(column.getType(), false);
StringBuilder buffer = new StringBuilder(90);
buffer.append("alter table ").append(tableName)
.append(' ').append(addColumn).append(' ').append(column.getName())
.append(' ').append(convertedType);
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
buffer.append(" not null");
}
if (!StringHelper.isNull(column.getCheckConstraint())) {
buffer.append(" constraint ").append(column.getCheckConstraintName());
buffer.append(" ").append(column.getCheckConstraint());
}
}
return buffer.toString();
}
/**
* Return true if unique constraints for OneToOne can be inlined as normal.
@@ -15,6 +15,8 @@ public class SqlServerDdl extends PlatformDdl {
super(platform);
this.identitySuffix = " identity(1,1)";
this.foreignKeyRestrict = "";
this.alterTableIfExists = "";
this.addColumn = "add";
this.inlineUniqueOneToOne = false;
this.columnSetDefault = "add default";
this.dropConstraintIfExists = "drop constraint";
@@ -28,9 +30,23 @@ public class SqlServerDdl extends PlatformDdl {
@Override
public String alterTableDropForeignKey(String tableName, String fkName) {
return "IF OBJECT_ID('" + fkName + "', 'F') IS NOT NULL " + super.alterTableDropForeignKey(tableName, fkName);
int pos = tableName.lastIndexOf('.');
String objectId = fkName;
if (pos != -1) {
objectId = tableName.substring(0, pos + 1) + fkName;
}
return "IF OBJECT_ID('" + objectId + "', 'F') IS NOT NULL " + super.alterTableDropForeignKey(tableName, fkName);
}
@Override
public String dropSequence(String sequenceName) {
return "IF OBJECT_ID('" + sequenceName + "', 'SO') IS NOT NULL drop sequence " + sequenceName;
}
@Override
public String dropIndex(String indexName, String tableName) {
return "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('" + tableName +"','U') AND name = '" + indexName + "') drop index " + indexName + " ON " + tableName;
}
/**
* MsSqlServer specific null handling on unique constraints.
*/
@@ -48,12 +64,37 @@ public class SqlServerDdl extends PlatformDdl {
sb.append(columns[i]);
}
sb.append(") where");
String sep = " ";
for (String column : columns) {
sb.append(" ").append(column).append(" is not null");
sb.append(sep).append(column).append(" is not null");
sep = " and ";
}
return sb.toString();
}
/**
* Generate and return the create sequence DDL.
*/
@Override
public String createSequence(String sequenceName, int initialValue, int allocationSize) {
StringBuilder sb = new StringBuilder("create sequence ");
sb.append(sequenceName);
sb.append(" as bigint ");
if (initialValue > 1) {
sb.append(" start with ").append(initialValue);
} else {
sb.append(" start with 1 ");
}
if (allocationSize > 0 && allocationSize != 50) {
// at this stage ignoring allocationSize 50 as this is the 'default' and
// not consistent with the way Ebean batch fetches sequence values
sb.append(" increment by ").append(allocationSize);
}
sb.append(";");
return sb.toString();
}
@Override
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
@@ -74,7 +115,7 @@ public class SqlServerDdl extends PlatformDdl {
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
String notnullClause = notnull ? " not null" : "";
return "alter table " + tableName + " alter column " + columnName + " " + type + notnullClause;
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + type + notnullClause;
}
@Override
@@ -34,16 +34,25 @@ public class SqlServerHistoryDdl implements PlatformHistoryDdl {
apply.append("alter table ").append(baseTable).newLine()
.append(" add ").append(systemPeriodStart).append(" datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(),").newLine()
.append(" ").append(systemPeriodEnd).append(" datetime2 GENERATED ALWAYS AS ROW END NOT NULL,").newLine()
.append("period for system_time (").append(systemPeriodStart).append("From, ").append(systemPeriodEnd).append("To)").endOfStatement();
.append("period for system_time (").append(systemPeriodStart).append(", ").append(systemPeriodEnd).append(")").endOfStatement();
apply.append("alter table ").append(baseTable).append("set (system_versioning = on)").endOfStatement();
String historyTable = baseTable + "_history"; // history must contain schema, otherwise you'll get
// Setting SYSTEM_VERSIONING to ON failed because history table 'xxx_history' is not specified in two-part name format.
if (historyTable.indexOf('.') == -1) {
historyTable = "dbo." +historyTable; // so add the default schema, if none was specified.
}
apply.append("alter table ").append(baseTable).append(" set (system_versioning = on (history_table=").append(historyTable).append("))").endOfStatement();
DdlBuffer drop = writer.dropAll();
drop.append("IF OBJECT_ID('").append(baseTable).append("', 'U') IS NOT NULL alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
drop.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
String baseTable = dropHistoryTable.getBaseTable();
DdlBuffer apply = writer.applyHistory();
apply.append("alter table ").append(baseTable).append("set (system_versioning = off)").endOfStatement();
apply.append("alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodStart).endOfStatement();
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodEnd).endOfStatement();
}
@@ -1,12 +1,15 @@
package io.ebean.dbmigration.model;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* The version of a migration used so that migrations are processed in order.
*/
public class MigrationVersion implements Comparable<MigrationVersion> {
private static final Pattern SECTION_SPLITTER = Pattern.compile("[\\.-]");
private static final int[] REPEAT_ORDERING = {Integer.MAX_VALUE};
private static final boolean[] REPEAT_UNDERSCORES = {false};
@@ -169,7 +172,7 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
value = value.replace('_', '.');
String[] sections = value.split("[\\.-]");
String[] sections = SECTION_SPLITTER.split(value);
if ("r".equalsIgnoreCase(sections[0])) {
// a "repeatable" version (does not have a version number)
@@ -29,14 +29,11 @@ public class PlatformDdlWriter {
private final DatabasePlatform platform;
private final String platformPrefix;
private final DbMigrationConfig config;
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig, String platformPrefix, DbMigrationConfig config) {
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig, DbMigrationConfig config) {
this.platform = platform;
this.serverConfig = serverConfig;
this.platformPrefix = platformPrefix;
this.config = config;
}
+6 -1
View File
@@ -158,7 +158,12 @@ public class EJson {
if (list == null) {
return null;
}
return ((ModifyAwareList) list).asSet();
if (modifyAware) {
return ((ModifyAwareList) list).asSet();
} else {
return new LinkedHashSet<>(list);
}
}
/**
@@ -12,7 +12,7 @@ public class CamelCaseHelper {
String[] vals = underscore.split("_");
if (vals.length == 1) {
return underscore;
return isUpperCase(underscore) ? underscore.toLowerCase() : underscore;
}
StringBuilder result = new StringBuilder();
@@ -29,4 +29,13 @@ public class CamelCaseHelper {
return result.toString();
}
private static boolean isUpperCase(String underscore) {
for (int i = 0; i < underscore.length(); i++) {
if (Character.isLowerCase(underscore.charAt(i))) {
return false;
}
}
return true;
}
}
@@ -65,4 +65,9 @@ public interface SpiExpressionRequest {
* Append a DB Like clause.
*/
void appendLike();
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
}
@@ -161,6 +161,7 @@ public interface SpiQuery<T> extends Query<T> {
/**
* Return the ForUpdate mode.
*/
@Override
ForUpdate getForUpdateMode();
/**
@@ -1,5 +1,6 @@
package io.ebeaninternal.extraddl.model;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,6 +16,8 @@ public class ExtraDdlXmlReader {
private static final Logger logger = LoggerFactory.getLogger(ExtraDdlXmlReader.class);
private static final Pattern PLATFORM_REGEX_SPLIT = Pattern.compile("[,;]");
/**
* Return the combined extra DDL that should be run given the platform name.
*/
@@ -44,7 +47,8 @@ public class ExtraDdlXmlReader {
if (platforms == null || platforms.trim().isEmpty()) {
return true;
}
String[] names = platforms.split("[,;]");
String[] names = PLATFORM_REGEX_SPLIT.split(platforms);
for (String name : names) {
if (name.trim().toLowerCase().contains(platformName)) {
return true;
@@ -244,17 +244,17 @@ public class DefaultContainer implements SpiContainer {
*/
private void setDatabasePlatform(ServerConfig config) {
DatabasePlatform dbPlatform = config.getDatabasePlatform();
if (dbPlatform == null) {
DatabasePlatform platform = config.getDatabasePlatform();
if (platform == null) {
if (config.getTenantMode().isDynamicDataSource()) {
throw new IllegalStateException("DatabasePlatform must be explicitly set on ServerConfig for TenantMode "+config.getTenantMode());
}
DatabasePlatformFactory factory = new DatabasePlatformFactory();
DatabasePlatform db = factory.create(config);
db.configure(config.getDbTypeConfig());
config.setDatabasePlatform(db);
logger.info("DatabasePlatform name:{} platform:{}", config.getName(), db.getName());
// automatically determine the platform
platform = new DatabasePlatformFactory().create(config);
config.setDatabasePlatform(platform);
}
logger.info("DatabasePlatform name:{} platform:{}", config.getName(), platform.getName());
platform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers());
}
/**
@@ -828,7 +828,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
public Transaction beginTransaction(TxIsolation isolation) {
// start an explicit transaction
SpiTransaction t = transactionManager.createTransaction(true, isolation.getLevel());
transactionScopeManager.set(t);
try {
transactionScopeManager.set(t);
} catch (PersistenceException existingTransactionError) {
t.end();
throw existingTransactionError;
}
return t;
}
@@ -1295,6 +1300,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
public <T> int findCountWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.COUNT, query, t);
Integer result = request.getFromQueryCache();
if (result != null) {
return result;
}
try {
request.initTransIfRequired();
return request.findCount();
@@ -248,19 +248,20 @@ public class InternalConfiguration {
* Return the JSON expression handler for the given database platform.
*/
private DbExpressionHandler getDbExpressionHandler(DatabasePlatform databasePlatform) {
Platform platform = databasePlatform.getPlatform();
if (platform == Platform.POSTGRES) {
return new PostgresJsonExpression();
final Platform platform = databasePlatform.getPlatform();
switch (platform) {
case POSTGRES:
return new PostgresJsonExpression();
case ORACLE:
return new OracleDbExpression();
case SQLSERVER:
return new SqlServerJsonExpression();
default:
return new NotSupportedDbExpression();
}
if (platform == Platform.ORACLE) {
return new OracleDbExpression();
}
return new NotSupportedDbExpression();
}
public JsonContext createJsonContext(SpiEbeanServer server) {
return new DJsonContext(server, jsonFactory, typeManager);
}
@@ -97,6 +97,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return ebeanServer.getDatabasePlatform().getLikeClause();
}
/**
* Return the database platform escaped like string.
*/
@Override
public String escapeLikeString(String value) {
return ebeanServer.getDatabasePlatform().escapeLikeString(value);
}
@Override
public void executeSecondaryQueries(boolean forEach) {
// disable lazy loading leaves loadContext null
@@ -293,7 +301,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
*/
@Override
public int delete() {
return queryEngine.delete(this);
return notifyCache(queryEngine.delete(this), false);
}
/**
@@ -301,7 +309,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
*/
@Override
public int update() {
return queryEngine.update(this);
return notifyCache(queryEngine.update(this), true);
}
private int notifyCache(int rows, boolean update) {
if (rows > 0 && beanDescriptor.isCaching()) {
transaction.getEvent().add(beanDescriptor.getBaseTable(), false, update, !update);
}
return rows;
}
/**
@@ -453,7 +468,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
* Try to get the query result from the query cache.
*/
@Override
public BeanCollection<T> getFromQueryCache() {
@SuppressWarnings("unchecked")
public Object getFromQueryCache() {
if (!query.isUseQueryCache()) {
return null;
@@ -461,16 +477,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
cacheKey = query.queryHash();
BeanCollection<T> cached = beanDescriptor.queryCacheGet(cacheKey);
Object cached = beanDescriptor.queryCacheGet(cacheKey);
if (cached != null && isAuditReads() && readAuditQueryType()) {
// raw sql can't use L2 cache so normal queries only in here
Collection<T> actualDetails = cached.getActualDetails();
List<Object> ids = new ArrayList<>(actualDetails.size());
for (T bean : actualDetails) {
ids.add(beanDescriptor.getIdForJson(bean));
if (cached instanceof BeanCollection) {
// raw sql can't use L2 cache so normal queries only in here
Collection<T> actualDetails = ((BeanCollection<T>)cached).getActualDetails();
List<Object> ids = new ArrayList<>(actualDetails.size());
for (T bean : actualDetails) {
ids.add(beanDescriptor.getIdForJson(bean));
}
beanDescriptor.readAuditMany(queryPlanKey.getPartialKey(), "l2-query-cache", ids);
}
beanDescriptor.readAuditMany(queryPlanKey.getPartialKey(), "l2-query-cache", ids);
}
return cached;
@@ -494,7 +512,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
}
}
public void putToQueryCache(BeanCollection<T> queryResult) {
public void putToQueryCache(Object queryResult) {
beanDescriptor.queryCachePut(cacheKey, queryResult);
}
@@ -535,7 +553,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
* </p>
*/
public boolean isAuditReads() {
return !query.isDisableReadAudit() && beanDescriptor.isReadAuditing();
return beanDescriptor.isReadAuditing() && !query.isDisableReadAudit();
}
/**
@@ -524,7 +524,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
/**
* Prepare the update after potential modifications in a BeanPersistController.
*/
public void postControllerPrepareUpdate() {
private void postControllerPrepareUpdate() {
if (intercept.isNew() && controller != null) {
// 'stateless update' - set dirty properties modified in controller preUpdate
intercept.setNewBeanForUpdate();
@@ -985,6 +985,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
docStoreUpdates.queueIndex(beanDescriptor.getDocStoreQueueId(), idValue);
}
}
break;
default:
break;
}
@@ -1071,31 +1072,38 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return version;
}
public void executeInsert() {
private void setTenantId() {
Object tenantId = transaction.getTenantId();
if (tenantId != null) {
beanDescriptor.setTenantId(entityBean, tenantId);
}
}
private void executeInsert() {
setTenantId();
if (controller == null || controller.preInsert(this)) {
beanManager.getBeanPersister().insert(this);
}
}
public void executeUpdate() {
private void executeUpdate() {
setTenantId();
if (controller == null || controller.preUpdate(this)) {
postControllerPrepareUpdate();
beanManager.getBeanPersister().update(this);
}
}
public void executeSoftDelete() {
private void executeSoftDelete() {
setTenantId();
if (controller == null || controller.preSoftDelete(this)) {
postControllerPrepareUpdate();
beanManager.getBeanPersister().update(this);
}
}
public int executeDelete() {
private int executeDelete() {
setTenantId();
if (controller == null || controller.preDelete(this)) {
return beanManager.getBeanPersister().delete(this);
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.core;
import io.ebean.QueryIterator;
import io.ebean.Version;
import io.ebean.bean.BeanCollection;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeanservice.docstore.api.DocQueryRequest;
@@ -117,13 +116,18 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
/**
* Try to get the query result from the query cache.
*/
BeanCollection<T> getFromQueryCache();
<A> A getFromQueryCache();
/**
* Return the Database platform like clause.
*/
String getDBLikeClause();
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
/**
* Mark the underlying transaction as not being query only.
*/
@@ -0,0 +1,28 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
* Microsoft SQL Server JSON. ARRAY expressions not supported.
*/
public class SqlServerJsonExpression implements DbExpressionHandler {
@Override
public void json(final SpiExpressionRequest request, final String propName,
final String path, final Op operator, final Object value) {
request.append("json_value(").append(propName).append(", '$.").append(path).append("')");
request.append(operator.bind());
}
@Override
public void arrayContains(final SpiExpressionRequest request, final String propName,
final boolean contains, final Object... values) {
throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server");
}
@Override
public void arrayIsEmpty(final SpiExpressionRequest request, final String propName, final boolean empty) {
throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server");
}
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core.bootup;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,6 +22,8 @@ class ManifestReader {
private final Set<String> packageSet = new HashSet<>();
private static final Pattern PACKAGE_DELIMITER = Pattern.compile("[,; ]");
/**
* Read the packages from ebean.mf manifest files found as resources.
*/
@@ -73,7 +76,7 @@ class ManifestReader {
* Collect each individual package splitting by delimiters.
*/
private void add(String packages) {
String[] split = packages.split("[,; ]");
String[] split = PACKAGE_DELIMITER.split(packages);
for (String aSplit : split) {
String pkg = aSplit.trim();
if (!pkg.isEmpty()) {
@@ -1116,6 +1116,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
}
}
/**
* Return true if there is bean or query caching for this type.
*/
public boolean isCaching() {
return cacheHelp.isCaching();
}
/**
* Return true if there is currently bean caching for this type of bean.
*/
@@ -1163,15 +1170,15 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Get a query result from the query cache.
*/
public BeanCollection<T> queryCacheGet(Object id) {
public Object queryCacheGet(Object id) {
return cacheHelp.queryCacheGet(id);
}
/**
* Put a query result into the query cache.
*/
public void queryCachePut(Object id, BeanCollection<T> query) {
cacheHelp.queryCachePut(id, query);
public void queryCachePut(Object id, Object queryResult) {
cacheHelp.queryCachePut(id, queryResult);
}
/**
@@ -3007,6 +3014,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
return versionProperty;
}
/**
* Return the tenant property when multi-tenant partitioning support is used.
*/
public BeanProperty getTenantProperty() {
return tenant;
}
/**
* Scalar properties without the unique id or secondary table properties.
*/
@@ -155,6 +155,13 @@ final class BeanDescriptorCacheHelp<T> {
return beanCache != null;
}
/**
* Return true if there is bean or query caching on this type.
*/
boolean isCaching() {
return beanCache != null || queryCache != null;
}
CacheOptions getCacheOptions() {
return cacheOptions;
}
@@ -183,33 +190,32 @@ final class BeanDescriptorCacheHelp<T> {
/**
* Get a query result from the query cache.
*/
@SuppressWarnings("unchecked")
BeanCollection<T> queryCacheGet(Object id) {
Object queryCacheGet(Object id) {
if (queryCache == null) {
throw new IllegalStateException("No query cache enabled on " + desc + ". Need explicit @Cache(enableQueryCache=true)");
}
BeanCollection<T> list = (BeanCollection<T>) queryCache.get(id);
Object queryResult = queryCache.get(id);
if (queryLog.isDebugEnabled()) {
if (list == null) {
if (queryResult == null) {
queryLog.debug(" GET {}({}) - cache miss", cacheName, id);
} else {
queryLog.debug(" GET {}({}) - hit", cacheName, id);
}
}
return list;
return queryResult;
}
/**
* Put a query result into the query cache.
*/
void queryCachePut(Object id, BeanCollection<T> query) {
void queryCachePut(Object id, Object queryResult) {
if (queryCache == null) {
throw new IllegalStateException("No query cache enabled on " + desc + ". Need explicit @Cache(enableQueryCache=true)");
}
if (queryLog.isDebugEnabled()) {
queryLog.debug(" PUT {}({})", cacheName, id);
}
queryCache.put(id, query);
queryCache.put(id, queryResult);
}
@@ -60,7 +60,7 @@ public class DeployDocPropertyOptions {
}
private void setBoost(float boost) {
if (boost != 1) {
if (Float.compare(boost, 1.0F) != 0) {
mapping.setBoost(boost);
}
}
@@ -16,8 +16,10 @@ public enum ManyType {
private final boolean map;
@SuppressWarnings("rawtypes")
private final Class<? extends Collection> type;
@SuppressWarnings("rawtypes")
ManyType(boolean map, Class<? extends Collection> type) {
this.map = map;
this.type = type;
@@ -31,6 +33,7 @@ public enum ManyType {
* Returns List.class or Set.class and null for Map.
* Not intended to be called for maps.
*/
@SuppressWarnings("rawtypes")
public Class<? extends Collection> getCollectionType() {
return type;
}
@@ -29,6 +29,9 @@ public class GeneratedCounter implements GeneratedProperty {
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Number currVal = (Number) prop.getValue(bean);
if (currVal == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
Integer nextVal = currVal.intValue() + 1;
return BasicTypeConverter.convert(nextVal, numberType);
}
@@ -25,8 +25,11 @@ public class GeneratedCounterInteger implements GeneratedProperty {
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Integer i = (Integer) prop.getValue(bean);
return i + 1;
Integer val = (Integer) prop.getValue(bean);
if (val == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
return val + 1;
}
/**
@@ -25,8 +25,11 @@ public class GeneratedCounterLong implements GeneratedProperty {
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Long i = (Long) prop.getValue(bean);
return i + 1;
Long val = (Long) prop.getValue(bean);
if (val == null) {
throw new IllegalStateException("version property has been set to null on bean: " + bean);
}
return val + 1;
}
/**
@@ -172,6 +172,9 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getIdInValueExprDelete(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
if (!idInExpandedForm) {
return getIdInValueExpr(size);
}
@@ -199,7 +202,9 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getIdInValueExpr(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
StringBuilder sb = new StringBuilder();
if (!idInExpandedForm) {
@@ -130,6 +130,9 @@ public final class IdBinderSimple implements IdBinder {
@Override
public String getIdInValueExpr(int size) {
if (size <= 0) {
throw new IndexOutOfBoundsException("The size must be at least 1");
}
StringBuilder sb = new StringBuilder(2 * size + 10);
sb.append(" in");
sb.append(" (?");
@@ -1,11 +1,12 @@
package io.ebeaninternal.server.el;
import java.io.Serializable;
import java.util.Comparator;
/**
* Comparator for use with the expression objects.
*/
public interface ElComparator<T> extends Comparator<T> {
public interface ElComparator<T> extends Comparator<T>, Serializable {
/**
* Compare given 2 beans.
@@ -10,6 +10,8 @@ import java.util.Comparator;
*/
public final class ElComparatorCompound<T> implements Comparator<T>, ElComparator<T> {
private static final long serialVersionUID = -1523163475050929750L;
private final ElComparator<T>[] array;
public ElComparatorCompound(ElComparator<T>[] array) {
@@ -7,6 +7,8 @@ import java.util.Comparator;
*/
public final class ElComparatorProperty<T> implements Comparator<T>, ElComparator<T> {
private static final long serialVersionUID = -2735738237263956073L;
private final ElPropertyValue elGetValue;
private final int nullOrder;
@@ -18,7 +18,6 @@ import io.ebeaninternal.api.SpiQuery;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -448,11 +447,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
}
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
@Override
public Expression idIn(List<?> idList) {
return new IdInExpression(idList);
public Expression idIn(Collection<?> idCollection) {
return new IdInExpression(idCollection);
}
/**
@@ -770,8 +770,8 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public ExpressionList<T> idIn(List<?> idList) {
add(expr.idIn(idList));
public ExpressionList<T> idIn(Collection<?> idCollection) {
add(expr.idIn(idCollection));
return this;
}
@@ -93,6 +93,11 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
sql.append(" ");
}
@Override
public String escapeLikeString(String value) {
return queryRequest.escapeLikeString(value);
}
/**
* Increments the parameter index and returns that value.
*/
@@ -10,7 +10,7 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
import java.util.Map;
/**
@@ -66,7 +66,7 @@ public interface DocQueryContext {
/**
* Write an Id in expression.
*/
void writeIds(List<?> idList) throws IOException;
void writeIds(Collection<?> idCollection) throws IOException;
/**
* Write an Id equals expression.
@@ -10,6 +10,8 @@ import io.ebean.Query;
import io.ebeaninternal.api.SpiExpressionList;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -95,7 +97,7 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
}
@Override
public ExpressionList<T> idIn(List<?> idValues) {
public ExpressionList<T> idIn(Collection<?> idValues) {
throw new PersistenceException(notAllowedMessage);
}
@@ -9,17 +9,18 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
import java.util.Iterator;
/**
* Slightly redundant as Query.setId() ultimately also does the same job.
*/
public class IdInExpression extends NonPrepareExpression {
private final List<?> idList;
private final Collection<?> idCollection;
public IdInExpression(List<?> idList) {
this.idList = idList;
public IdInExpression(Collection<?> idCollection) {
this.idCollection = idCollection;
}
@Override
@@ -33,7 +34,7 @@ public class IdInExpression extends NonPrepareExpression {
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeIds(idList);
context.writeIds(idCollection);
}
@Override
@@ -50,8 +51,8 @@ public class IdInExpression extends NonPrepareExpression {
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
for (Object anIdList : idList) {
idBinder.addIdInBindValue(request, anIdList);
for (Object id : idCollection) {
idBinder.addIdInBindValue(request, id);
}
}
@@ -63,10 +64,13 @@ public class IdInExpression extends NonPrepareExpression {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
request.append(descriptor.getIdBinder().getBindIdInSql(null));
String inClause = idBinder.getIdInValueExpr(idList.size());
request.append(inClause);
if (idCollection.size() == 0) {
request.append("1=0"); // append false for this stage
} else {
request.append(descriptor.getIdBinder().getBindIdInSql(null));
String inClause = idBinder.getIdInValueExpr(idCollection.size());
request.append(inClause);
}
}
@Override
@@ -75,10 +79,13 @@ public class IdInExpression extends NonPrepareExpression {
DefaultExpressionRequest r = (DefaultExpressionRequest) request;
BeanDescriptor<?> descriptor = r.getBeanDescriptor();
IdBinder idBinder = descriptor.getIdBinder();
request.append(descriptor.getIdBinderInLHSSql());
String inClause = idBinder.getIdInValueExpr(idList.size());
request.append(inClause);
if (idCollection.size() == 0) {
request.append("1=0"); // append false for this stage
} else {
request.append(descriptor.getIdBinderInLHSSql());
String inClause = idBinder.getIdInValueExpr(idCollection.size());
request.append(inClause);
}
}
/**
@@ -86,13 +93,13 @@ public class IdInExpression extends NonPrepareExpression {
*/
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(IdInExpression.class).add(idList.size());
builder.bind(idList.size());
builder.add(IdInExpression.class).add(idCollection.size());
builder.bind(idCollection.size());
}
@Override
public int queryBindHash() {
return idList.hashCode();
return idCollection.hashCode();
}
@Override
@@ -102,17 +109,19 @@ public class IdInExpression extends NonPrepareExpression {
}
IdInExpression that = (IdInExpression) other;
return this.idList.size() == that.idList.size();
return this.idCollection.size() == that.idCollection.size();
}
@Override
public boolean isSameByBind(SpiExpression other) {
IdInExpression that = (IdInExpression) other;
if (this.idList.size() != that.idList.size()) {
if (this.idCollection.size() != that.idCollection.size()) {
return false;
}
for (int i = 0; i < idList.size(); i++) {
if (!idList.get(i).equals(that.idList.get(i))) {
Iterator<?> it = that.idCollection.iterator();
for (Object id1 : idCollection) {
Object id2 = it.next();
if (!id1.equals(id2)) {
return false;
}
}
@@ -92,6 +92,9 @@ class InExpression extends AbstractExpression {
if (prop != null) {
request.append(prop.getAssocIdInExpr(propName));
String inClause = prop.getAssocIdInValueExpr(bindValues.length);
if (not) {
request.append(" not");
}
request.append(inClause);
} else {
@@ -568,7 +568,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public ExpressionList<T> idIn(List<?> idValues) {
public ExpressionList<T> idIn(Collection<?> idValues) {
return exprList.idIn(idValues);
}
@@ -34,8 +34,7 @@ class LikeExpression extends AbstractValueExpression {
String encryptKey = prop.getBeanProperty().getEncryptKey().getStringValue();
request.addBindEncryptKey(encryptKey);
}
String bindValue = getValue(strValue(), caseInsensitive, type);
String bindValue = getValue(strValue(), caseInsensitive, type, request);
request.addBindValue(bindValue);
}
@@ -92,13 +91,15 @@ class LikeExpression extends AbstractValueExpression {
return strValue().equals(that.strValue());
}
private static String getValue(String value, boolean caseInsensitive, LikeType type) {
private static String getValue(String value, boolean caseInsensitive, LikeType type, SpiExpressionRequest request) {
if (caseInsensitive) {
value = value.toLowerCase();
}
if (type == LikeType.RAW) {
return value;
}
value = request.escapeLikeString(value);
switch (type) {
case RAW:
return value;
case STARTS_WITH:
return value + "%";
case ENDS_WITH:
@@ -7,7 +7,8 @@ import java.sql.SQLException;
* Holds the first SQLException found when executing a JDBC batch.
*/
public class BatchedSqlException extends Exception {
private static final long serialVersionUID = -4374631080253580648L;
private SQLException cause;
BatchedSqlException(String message, SQLException cause) {
@@ -21,18 +21,19 @@ public final class DeleteMeta {
private final String sqlDraftNone;
private final BindableId id;
private final Bindable version;
private final Bindable tenantId;
private final String tableName;
private final boolean emptyStringAsNull;
public DeleteMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, BindableId id, Bindable version) {
DeleteMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, BindableId id, Bindable version, Bindable tenantId) {
this.emptyStringAsNull = emptyStringAsNull;
this.tableName = desc.getBaseTable();
this.id = id;
this.version = version;
this.tenantId = tenantId;
String tableName = desc.getBaseTable();
this.sqlNone = genSql(ConcurrencyMode.NONE, tableName);
@@ -48,7 +49,7 @@ public final class DeleteMeta {
}
}
public boolean isEmptyStringAsNull() {
boolean isEmptyStringAsNull() {
return emptyStringAsNull;
}
@@ -67,6 +68,9 @@ public final class DeleteMeta {
EntityBean bean = persist.getEntityBean();
id.dmlBind(bind, bean);
if (tenantId != null) {
tenantId.dmlBind(bind, bean);
}
switch (persist.getConcurrencyMode()) {
case VERSION:
@@ -102,21 +106,20 @@ public final class DeleteMeta {
private String genSql(ConcurrencyMode conMode, String table) {
// delete ... where bcol=? and bc1=? and bc2 is null and ...
GenerateDmlRequest request = new GenerateDmlRequest();
request.append("delete from ").append(table);
request.append(" where ");
request.setWhereIdMode();
id.dmlAppend(request);
if (tenantId != null) {
tenantId.dmlAppend(request);
}
if (ConcurrencyMode.VERSION.equals(conMode)) {
if (version == null) {
return null;
if (version != null) {
version.dmlAppend(request);
}
version.dmlAppend(request);
}
return request.toString();
@@ -39,7 +39,7 @@ public class MetaFactory {
private final boolean emptyStringAsNull;
public MetaFactory(DatabasePlatform dbPlatform) {
MetaFactory(DatabasePlatform dbPlatform) {
this.dbPlatform = dbPlatform;
this.emptyStringAsNull = dbPlatform.isTreatEmptyStringsAsNull();
@@ -54,7 +54,7 @@ public class MetaFactory {
/**
* Create the UpdateMeta for the given bean type.
*/
public UpdateMeta createUpdate(BeanDescriptor<?> desc) {
UpdateMeta createUpdate(BeanDescriptor<?> desc) {
List<Bindable> setList = new ArrayList<>();
@@ -63,30 +63,30 @@ public class MetaFactory {
assocOneFact.create(setList, desc, DmlMode.UPDATE);
BindableId id = idFact.createId(desc);
Bindable ver = versionFact.create(desc);
Bindable version = versionFact.create(desc);
Bindable tenantId = versionFact.createTenantId(desc);
BindableList setBindable = new BindableList(setList);
return new UpdateMeta(emptyStringAsNull, desc, setBindable, id, ver);
return new UpdateMeta(emptyStringAsNull, desc, setBindable, id, version, tenantId);
}
/**
* Create the DeleteMeta for the given bean type.
*/
public DeleteMeta createDelete(BeanDescriptor<?> desc) {
DeleteMeta createDelete(BeanDescriptor<?> desc) {
BindableId id = idFact.createId(desc);
Bindable version = versionFact.create(desc);
Bindable tenantId = versionFact.createTenantId(desc);
Bindable ver = versionFact.create(desc);
return new DeleteMeta(emptyStringAsNull, desc, id, ver);
return new DeleteMeta(emptyStringAsNull, desc, id, version, tenantId);
}
/**
* Create the InsertMeta for the given bean type.
*/
public InsertMeta createInsert(BeanDescriptor<?> desc) {
InsertMeta createInsert(BeanDescriptor<?> desc) {
BindableId id = idFact.createId(desc);
@@ -22,6 +22,7 @@ public final class UpdateMeta {
private final BindableList set;
private final BindableId id;
private final Bindable version;
private final Bindable tenantId;
private final String tableName;
@@ -30,12 +31,13 @@ public final class UpdateMeta {
private final boolean emptyStringAsNull;
public UpdateMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, BindableList set, BindableId id, Bindable version) {
UpdateMeta(boolean emptyStringAsNull, BeanDescriptor<?> desc, BindableList set, BindableId id, Bindable version, Bindable tenantId) {
this.emptyStringAsNull = emptyStringAsNull;
this.tableName = desc.getBaseTable();
this.set = set;
this.id = id;
this.version = version;
this.tenantId = tenantId;
String sqlNone = genSql(ConcurrencyMode.NONE, set, desc.getBaseTable());
String sqlVersion = genSql(ConcurrencyMode.VERSION, set, desc.getBaseTable());
@@ -47,7 +49,7 @@ public final class UpdateMeta {
/**
* Return true if empty strings should be treated as null.
*/
public boolean isEmptyStringAsNull() {
boolean isEmptyStringAsNull() {
return emptyStringAsNull;
}
@@ -68,6 +70,9 @@ public final class UpdateMeta {
updatePlan.bindSet(bind, bean);
id.dmlBind(bind, bean);
if (tenantId != null) {
tenantId.dmlBind(bind, bean);
}
switch (persist.getConcurrencyMode()) {
case VERSION:
@@ -82,7 +87,7 @@ public final class UpdateMeta {
/**
* get or generate the sql based on the concurrency mode.
*/
public SpiUpdatePlan getUpdatePlan(PersistRequestBean<?> request) {
SpiUpdatePlan getUpdatePlan(PersistRequestBean<?> request) {
if (request.isDynamicUpdateSql()) {
return getDynamicUpdatePlan(request);
@@ -135,8 +140,6 @@ public final class UpdateMeta {
private String genSql(ConcurrencyMode conMode, BindableList bindableList, String tableName) {
// update set col0=?, col1=?, col2=? where bcol=? and bc1=? and bc2=?
GenerateDmlRequest request = new GenerateDmlRequest();
request.append("update ").append(tableName).append(" set ");
@@ -153,12 +156,13 @@ public final class UpdateMeta {
request.setWhereIdMode();
id.dmlAppend(request);
if (tenantId != null) {
tenantId.dmlAppend(request);
}
if (ConcurrencyMode.VERSION.equals(conMode)) {
if (version == null) {
return null;
if (version != null) {
version.dmlAppend(request);
}
version.dmlAppend(request);
}
return request.toString();
@@ -18,10 +18,15 @@ public class FactoryVersion {
public Bindable create(BeanDescriptor<?> desc) {
BeanProperty versionProperty = desc.getVersionProperty();
if (versionProperty == null) {
return null;
}
return (versionProperty == null) ? null : new BindableProperty(versionProperty);
}
return new BindableProperty(versionProperty);
/**
* Create a Bindable for TenantId If multi-tenant with partitioning is on this bean type.
*/
public Bindable createTenantId(BeanDescriptor<?> desc) {
BeanProperty tenant = desc.getTenantProperty();
return (tenant == null) ? null : new BindableProperty(tenant);
}
}
@@ -232,7 +232,11 @@ public class CQueryEngine {
return readIterate;
} catch (SQLException e) {
throw cquery.createPersistenceException(e);
try {
throw cquery.createPersistenceException(e);
} finally {
request.rollbackTransIfRequired();
}
}
}
@@ -70,7 +70,11 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
public <T> int findCount(OrmQueryRequest<T> request) {
flushJdbcBatchOnQuery(request);
return queryEngine.findCount(request);
int result = queryEngine.findCount(request);
if (request.getQuery().isUseQueryCache()) {
request.putToQueryCache(result);
}
return result;
}
@Override
@@ -83,7 +87,12 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
@Override
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
return queryEngine.findSingleAttributeList(request);
List<A> result = queryEngine.findSingleAttributeList(request);
if (!result.isEmpty() && request.getQuery().isUseQueryCache()) {
// load the query result into the query cache
request.putToQueryCache(result);
}
return result;
}
@Override
@@ -2,16 +2,19 @@ package io.ebeaninternal.server.query;
import io.ebean.Version;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Comparator;
/**
* Compare Version beans in descending order with nulls last.
*/
class OrderVersionDesc implements Comparator<Version<?>> {
class OrderVersionDesc implements Comparator<Version<?>>, Serializable {
static final OrderVersionDesc INSTANCE = new OrderVersionDesc();
private static final long serialVersionUID = -3681686029998263310L;
@Override
public int compare(Version<?> o1, Version<?> o2) {
@@ -3,6 +3,8 @@ package io.ebeaninternal.server.query;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.HashSet;
@@ -15,6 +17,8 @@ import java.util.TreeSet;
*/
class SqlTreeAlias {
private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL);
private int counter;
private int manyWhereCounter;
@@ -178,9 +182,9 @@ class SqlTreeAlias {
private String parseRootAlias(String clause) {
if (rootTableAlias == null) {
return clause.replace("${}", "");
return TABLE_ALIAS_REPLACE.matcher(clause).replaceAll("");
} else {
return clause.replace("${}", rootTableAlias + ".");
return TABLE_ALIAS_REPLACE.matcher(clause).replaceAll(Matcher.quoteReplacement(rootTableAlias + "."));
}
}
@@ -135,6 +135,10 @@ class SqlTreeNodeBean implements SqlTreeNode {
pathMap = createPathMap(prefix, desc);
}
protected boolean isRoot() {
return false;
}
@Override
public ScalarType<?> getSingleAttributeScalarType() {
if (properties == null || properties.length == 0) {
@@ -316,6 +320,10 @@ class SqlTreeNodeBean implements SqlTreeNode {
aChildren.load(ctx, localBean, contextBean);
}
if (queryMode.equals(Mode.LAZYLOAD_MANY) && isRoot()) {
return contextBean;
}
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readId && !temporalVersions) {
@@ -25,6 +25,11 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean {
this.includeJoin = includeJoin;
}
@Override
protected boolean isRoot() {
return true;
}
/**
* Append the property columns to the buffer.
*/
@@ -9,6 +9,7 @@ import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Set properties for a UpdateQuery.
@@ -19,6 +20,8 @@ public class OrmUpdateProperties {
private static final NoneValue NONE_VALUE = new NoneValue();
private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL);
/**
* Bind value used in the set clause for update query.
* It may/may not have bind values etc.
@@ -188,8 +191,9 @@ public class OrmUpdateProperties {
if (setCount++ > 0) {
sb.append(", ");
}
// translate to db columns and remove table alias placeholders
sb.append(deployParser.parse(property).replace("${}", ""));
sb.append(TABLE_ALIAS_REPLACE.matcher(deployParser.parse(property)).replaceAll(""));
sb.append(entry.getValue().bindClause());
}
return sb.toString();
@@ -18,7 +18,7 @@ public class DJsonScalar {
this.typeManager = typeManager;
}
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
public void write(JsonGenerator gen, Object value) throws IOException {
if (value instanceof String) {
@@ -198,7 +198,7 @@ public class ReadJson {
* If there is a JsonReadBeanVisitor registered to the current path then
* call it's visit method with the bean and unmappedProperties.
*/
@SuppressWarnings(value = "unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
public void beanVisitor(Object bean, Map<String, Object> unmappedProperties) {
if (visitorMap != null) {
JsonReadBeanVisitor visitor = visitorMap.get(pathStack.peekWithNull());
@@ -646,6 +646,7 @@ public class JdbcTransaction implements SpiTransaction {
}
}
@Override
public PersistenceException translate(String message, SQLException cause) {
if (manager != null) {
return manager.translate(message, cause);
@@ -18,6 +18,7 @@ import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import io.ebeaninternal.util.JdbcClose;
/**
* Hook into external JTA transaction manager.
@@ -28,11 +29,6 @@ public class JtaTransactionManager implements ExternalTransactionManager {
private static final String EBEAN_TXN_RESOURCE = "EBEAN_TXN_RESOURCE";
/**
* The data source.
*/
private DataSource dataSource;
/**
* The Ebean transaction manager.
*/
@@ -59,10 +55,16 @@ public class JtaTransactionManager implements ExternalTransactionManager {
// the public API and hence the Object type and casting here
this.transactionManager = (TransactionManager) txnMgr;
this.dataSource = transactionManager.getDataSource();
this.serverName = transactionManager.getServerName();
}
/**
* Return the current dataSource taking into account multi-tenancy.
*/
private DataSource dataSource() {
return transactionManager.getDataSource();
}
private TransactionSynchronizationRegistry getSyncRegistry() {
try {
InitialContext ctx = new InitialContext();
@@ -121,7 +123,7 @@ public class JtaTransactionManager implements ExternalTransactionManager {
// "wrap" it in a Ebean specific JtaTransaction
String txnId = String.valueOf(System.currentTimeMillis());
JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager);
JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource(), transactionManager);
// create and register transaction listener
JtaTxnListener txnListener = createJtaTxnListener(newTrans);
@@ -232,6 +234,8 @@ public class JtaTransactionManager implements ExternalTransactionManager {
}
}
// No matter the completion status of the transaction, we release the connection we got from the pool.
JdbcClose.close(transaction.getInternalConnection());
}
}
@@ -70,15 +70,12 @@ public class TransactionMap {
* Set the transaction. This will now be the current transaction.
*/
public void set(SpiTransaction trans) {
if (transaction != null && transaction.isActive()) {
String m = "The existing transaction is still active?";
throw new PersistenceException(m);
throw new PersistenceException("The existing transaction is still active?");
}
transaction = trans;
}
/**
* Commit the transaction.
*/
@@ -21,6 +21,8 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Rob Bygrave: This is a copy of the google guava InetAddresses class
@@ -115,6 +117,10 @@ public final class ConvertInetAddresses {
private static final int IPV4_PART_COUNT = 4;
private static final int IPV6_PART_COUNT = 8;
public static final String DOUBLE_COLON = "::";
private static final Pattern IPSTRING_REPLACE = Pattern.compile(DOUBLE_COLON, Pattern.LITERAL);
private ConvertInetAddresses() {
}
@@ -186,7 +192,7 @@ public final class ConvertInetAddresses {
// handle IPv6 forms of IPv4 addresses
if (ipString.toUpperCase(Locale.US).startsWith("::FFFF:")) {
ipString = ipString.substring(7);
} else if (ipString.startsWith("::")) {
} else if (ipString.startsWith(DOUBLE_COLON)) {
ipString = ipString.substring(2);
isIpv6 = true;
}
@@ -260,13 +266,14 @@ public final class ConvertInetAddresses {
// Fill in any omitted colons
private static String padIpString(String ipString) {
if (ipString.contains("::")) {
if (ipString.contains(DOUBLE_COLON)) {
int count = numberOfColons(ipString);
StringBuilder buffer = new StringBuilder("::");
StringBuilder buffer = new StringBuilder(DOUBLE_COLON);
for (int i = 0; i + count < 7; i++) {
buffer.append(":");
}
ipString = ipString.replace("::", buffer);
ipString = IPSTRING_REPLACE.matcher(ipString).replaceAll(Matcher.quoteReplacement(buffer.toString()));
}
return ipString;
}
@@ -19,6 +19,7 @@ import java.util.UUID;
/**
* Type mapped for DB ARRAY type (Postgres only effectively).
*/
@SuppressWarnings("rawtypes")
public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implements ScalarTypeArray {
private static ScalarTypeArrayList UUID = new ScalarTypeArrayList("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
@@ -75,6 +76,7 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implemen
/**
* Return the DB column definition for DDL generation.
*/
@Override
public String getDbColumnDefn() {
return arrayType + "[]";
}
@@ -48,11 +48,13 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
}
}
@SuppressWarnings("rawtypes")
private ScalarTypeArrayListH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
super(arrayType, docPropertyType, converter);
}
@Override
@SuppressWarnings("rawtypes")
public void bind(DataBind bind, List value) throws SQLException {
if (value == null) {
bind.setNull(Types.ARRAY);
@@ -75,6 +75,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
/**
* Return the DB column definition for DDL generation.
*/
@Override
public String getDbColumnDefn() {
return arrayType + "[]";
}
@@ -61,6 +61,7 @@ public class ScalarTypeJsonList {
/**
* Base class for List handling.
*/
@SuppressWarnings("rawtypes")
private abstract static class Base extends ScalarTypeJsonCollection<List> {
public Base(int dbType, DocPropertyType docType) {
@@ -135,6 +136,7 @@ public class ScalarTypeJsonList {
this.pgType = pgType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, List value) throws SQLException {
@@ -21,6 +21,7 @@ import java.util.Map;
/**
* Type which maps Map<String,Object> to various DB types (Clob, Varchar, Blob) in JSON format.
*/
@SuppressWarnings("rawtypes")
public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
private static final ScalarTypeJsonMap CLOB = new ScalarTypeJsonMap.Clob();
@@ -17,6 +17,7 @@ public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
this.postgresType = postgresType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, Map value) throws SQLException {
@@ -67,6 +67,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Sets wrapping the ObjectMapper Set as a ModifyAwareSet.
*/
@SuppressWarnings("rawtypes")
private static class OmSet extends Base<Set> {
public OmSet(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
@@ -84,6 +85,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Lists wrapping the ObjectMapper List as a ModifyAwareList.
*/
@SuppressWarnings("rawtypes")
private static class OmList extends Base<List> {
public OmList(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
@@ -101,6 +103,7 @@ public class ScalarTypeJsonObjectMapper {
/**
* Type for Map wrapping the ObjectMapper Map as a ModifyAwareMap.
*/
@SuppressWarnings("rawtypes")
private static class OmMap extends Base<Map> {
public OmMap(ObjectMapper objectMapper, Type type, int dbType, String pgType) {
@@ -64,6 +64,7 @@ public class ScalarTypeJsonSet {
/**
* Base class for List handling.
*/
@SuppressWarnings("rawtypes")
private abstract static class Base extends ScalarTypeJsonCollection<Set> {
public Base(int dbType, DocPropertyType docPropertyType) {
@@ -142,6 +143,7 @@ public class ScalarTypeJsonSet {
this.pgType = pgType;
}
@SuppressWarnings("rawtypes")
@Override
public void bind(DataBind bind, Set value) throws SQLException {
@@ -229,7 +229,7 @@ public class DocPropertyOptions {
if (docMapping.store()) {
store = true;
}
if (docMapping.boost() != 1) {
if (Float.compare(docMapping.boost(), 1.0F) != 0) {
boost = docMapping.boost();
}
if (!"".equals(docMapping.nullValue())) {
+4 -3
View File
@@ -1,5 +1,6 @@
package io.ebean;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import org.tests.model.basic.Country;
@@ -15,7 +16,7 @@ public class BaseTestCase {
static {
logger.debug("... preStart");
if (!AgentLoader.loadAgentFromClasspath("ebean-agent", "debug=1;packages=com.avaje.tests,org.avaje.test")) {
if (!AgentLoader.loadAgentFromClasspath("ebean-agent", "debug=1;packages=org.tests,org.avaje.test,io.ebean")) {
logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded");
}
}
@@ -39,10 +40,10 @@ public class BaseTestCase {
*/
protected String trimSql(String sql, int columns) {
for (int i = 0; i <= columns; i++) {
sql = sql.replace(" c" + i + ",", ",");
sql = StringHelper.replaceString(sql, " c" + i + ",", ",");
}
for (int i = 0; i <= columns; i++) {
sql = sql.replace(" c" + i + " ", " ");
sql = StringHelper.replaceString(sql, " c" + i + " ", " ");
}
return sql;
}
@@ -8,7 +8,7 @@ import org.mockito.Mockito;
import javax.sql.DataSource;
public class EbeanServerFactory_MultiTenancy_Test {
public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase {
/**
* Tests using multi tenancy per database
@@ -20,7 +20,6 @@ public class EbeanServerFactory_ServerConfigStart_Test {
config.setName("h2");
config.loadFromProperties();
config.setName("h2other");
config.setH2ProductionMode(true);
config.setDdlGenerate(false);
config.setDdlRun(false);
config.setDefaultServer(false);

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