mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
60
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6c5073e47 | ||
|
|
2a58b954e9 | ||
|
|
9772623880 | ||
|
|
27b6183aad | ||
|
|
55e19618f8 | ||
|
|
5c60ba4d7f | ||
|
|
b9cc584086 | ||
|
|
bf5a8c2fad | ||
|
|
66138e5ea2 | ||
|
|
75fb89ef76 | ||
|
|
a2cb468222 | ||
|
|
166bcd7c45 | ||
|
|
95aed6af54 | ||
|
|
7a697c12af | ||
|
|
23278ce30b | ||
|
|
36a5610e25 | ||
|
|
08263c4588 | ||
|
|
1e88a52208 | ||
|
|
e770a42175 | ||
|
|
35b467c04f | ||
|
|
2001539755 | ||
|
|
e49c4bfe5a | ||
|
|
15be31fd5f | ||
|
|
4777ec46be | ||
|
|
80ab731aec | ||
|
|
080bafe18f | ||
|
|
e913f88f52 | ||
|
|
e94c5484a0 | ||
|
|
4af00c51d3 | ||
|
|
23d1256dbf | ||
|
|
ed0ef46d2e | ||
|
|
1860ded735 | ||
|
|
d432854b82 | ||
|
|
93582c8ea3 | ||
|
|
520d35b1d6 | ||
|
|
8ca3599cbf | ||
|
|
283ae74219 | ||
|
|
cebd3f92a4 | ||
|
|
4b2481d3ea | ||
|
|
f1f2a416d3 | ||
|
|
74dd97a55f | ||
|
|
3f04f7f363 | ||
|
|
800f854a12 | ||
|
|
bef9e6d54f | ||
|
|
0e4c0ae6c3 | ||
|
|
a0ea9887df | ||
|
|
0413c22e6e | ||
|
|
989ae44a6d | ||
|
|
100d314e63 | ||
|
|
dbf4e99187 | ||
|
|
7b8a85106c | ||
|
|
58c5f01e2b | ||
|
|
bc74d35651 | ||
|
|
a1f95bf25e | ||
|
|
c454e1f8a7 | ||
|
|
5a3669e1db | ||
|
|
7a2e0b3695 | ||
|
|
ce6d6269cd | ||
|
|
7d800b7080 | ||
|
|
136154e247 |
+2
-1
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+5
-2
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
-2
@@ -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())) {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user