mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46f3b74b38 | ||
|
|
df51ccd2c4 | ||
|
|
730d43c008 | ||
|
|
81c2c804a6 | ||
|
|
533be356f2 | ||
|
|
589191f3f4 | ||
|
|
0e65efea57 | ||
|
|
be66872249 | ||
|
|
85a0354d42 | ||
|
|
0b8613fd4c | ||
|
|
e734c0010c | ||
|
|
e08333ef26 | ||
|
|
4a3eabbd6b | ||
|
|
ae68d41519 | ||
|
|
722692d934 | ||
|
|
21a3f322e1 | ||
|
|
0d175557b0 | ||
|
|
57ccd19fe6 | ||
|
|
9674711516 | ||
|
|
9155716752 | ||
|
|
d7d8c3e651 | ||
|
|
16f6f2ee7f | ||
|
|
fea6dfd62b | ||
|
|
464ed4322e | ||
|
|
c3f556f0dc | ||
|
|
ba6810891e | ||
|
|
c530883e5e | ||
|
|
06542b031e | ||
|
|
4b5365e708 | ||
|
|
1d471fee92 | ||
|
|
3825dea00a | ||
|
|
3fd130ac4c | ||
|
|
196645e7a2 | ||
|
|
f5459920e9 | ||
|
|
ee6452cfb0 | ||
|
|
ad7e18561b | ||
|
|
c640524bfc | ||
|
|
fea840c859 | ||
|
|
bb7df71391 | ||
|
|
cb6f0335b1 | ||
|
|
762899ef10 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.42.2</version>
|
||||
<version>11.44.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.42.2</tag>
|
||||
<tag>ebean-11.44.1</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -118,7 +118,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>4.11</version>
|
||||
<version>4.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -130,7 +130,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>4.5.2</version>
|
||||
<version>4.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -142,7 +142,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>11.19.1</version>
|
||||
<version>11.20.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -220,6 +220,13 @@
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nuodb.jdbc</groupId>
|
||||
<artifactId>nuodb-jdbc</artifactId>
|
||||
<version>20.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
@@ -230,7 +237,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean.test</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<version>2.10.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -285,6 +292,13 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.composite</groupId>
|
||||
<artifactId>avaje-composite-testing</artifactId>
|
||||
@@ -316,7 +330,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>11.42.1</version>
|
||||
<version>11.44.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -1237,4 +1237,18 @@ public class DB {
|
||||
return getDefault().json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the base tables for the given bean types.
|
||||
*/
|
||||
public static void truncate(Class<?>... types) {
|
||||
getDefault().truncate(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate the given tables.
|
||||
*/
|
||||
public static void truncate(String... tables) {
|
||||
getDefault().truncate(tables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1580,4 +1580,15 @@ public interface Database {
|
||||
* </p>
|
||||
*/
|
||||
<T> Set<String> validateQuery(Query<T> query);
|
||||
|
||||
/**
|
||||
* Truncate all the given tables.
|
||||
*/
|
||||
void truncate(String... tables);
|
||||
|
||||
/**
|
||||
* Truncate the base tables for the given bean types.
|
||||
*/
|
||||
void truncate(Class<?>... tables);
|
||||
|
||||
}
|
||||
|
||||
@@ -536,4 +536,12 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Add the expressions to the given expression list.
|
||||
*
|
||||
* @param where The expression list to add the expressions to
|
||||
* @param expressions The expressions that are parsed
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
<T> void where(ExpressionList<T> where, String expressions, Object[] params);
|
||||
}
|
||||
|
||||
@@ -489,7 +489,26 @@ public interface ExpressionList<T> {
|
||||
* Add some filter predicate expressions to the many property.
|
||||
*/
|
||||
@Nonnull
|
||||
ExpressionList<T> filterMany(String prop);
|
||||
ExpressionList<T> filterMany(String manyProperty);
|
||||
|
||||
/**
|
||||
* Add filter expressions to the many property.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .eq("name", "Rob")
|
||||
* .filterMany("orders", "status = ?", Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param manyProperty The many property
|
||||
* @param expressions Filter expressions with and, or and ? or ?1 type bind parameters
|
||||
* @param params Bind parameters used in the expressions
|
||||
*/
|
||||
Query<T> filterMany(String manyProperty, String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
@@ -663,6 +682,14 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Add the expressions to this expression list.
|
||||
*
|
||||
* @param expressions The expressions that are parsed and added to this expression list
|
||||
* @param params Bind parameters to match ? or ?1 bind positions.
|
||||
*/
|
||||
ExpressionList<T> where(String expressions, Object... params);
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
* <pre>{@code
|
||||
@@ -831,9 +858,9 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> inRange(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
ExpressionList<T> between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
@@ -1327,7 +1354,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -1335,7 +1362,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param values The values which is typically a list or set of id values.
|
||||
*/
|
||||
ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
|
||||
|
||||
@@ -148,6 +148,8 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
@@ -188,6 +190,17 @@ public class FetchConfig implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public FetchConfig cache() {
|
||||
this.cache = true;
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
@@ -247,6 +260,13 @@ public class FetchConfig implements Serializable {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -255,6 +275,7 @@ public class FetchConfig implements Serializable {
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
if (cache != that.cache) return false;
|
||||
return queryAll == that.queryAll;
|
||||
}
|
||||
|
||||
@@ -263,6 +284,7 @@ public class FetchConfig implements Serializable {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
@@ -111,4 +113,11 @@ public interface FetchGroup<T> {
|
||||
return XServiceProvider.fetchGroupOf(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a query to be used by query beans for constructing FetchGroup.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType) {
|
||||
return XServiceProvider.fetchGroupQueryFor(beanType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,12 +67,26 @@ public interface FetchGroupBuilder<T> {
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using a query join.
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchQuery(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including specified properties using L2 cache.
|
||||
* Cache misses fallback to fetchQuery().
|
||||
*/
|
||||
@Nonnull
|
||||
FetchGroupBuilder<T> fetchCache(String path, String properties);
|
||||
|
||||
/**
|
||||
* Fetch the path including all its properties lazily.
|
||||
*/
|
||||
|
||||
@@ -501,6 +501,14 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties using L2 bean cache.
|
||||
*
|
||||
* @param path The path of the beans we are fetching from L2 cache.
|
||||
* @param fetchProperties The properties that should be loaded.
|
||||
*/
|
||||
Query<T> fetchCache(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties lazily (via batch lazy loading).
|
||||
* <p>
|
||||
@@ -587,6 +595,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path eagerly using L2 cache.
|
||||
*/
|
||||
Query<T> fetchCache(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path lazily (via batch lazy loading).
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Thrown at SERIALIZABLE isolation level for non-recoverable concurrent conflict.
|
||||
*/
|
||||
public class SerializableConflictException extends OptimisticLockException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Create with a message and cause.
|
||||
*/
|
||||
public SerializableConflictException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebean.service.SpiFetchGroupService;
|
||||
import io.ebean.service.SpiProfileLocationFactory;
|
||||
import io.ebean.service.SpiRawSqlService;
|
||||
@@ -71,4 +72,11 @@ class XServiceProvider {
|
||||
static <T> FetchGroupBuilder<T> fetchGroupOf(Class<T> cls) {
|
||||
return fetchGroupService.of(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FetchGroup Query for building fetch groups via query beans.
|
||||
*/
|
||||
static <T> SpiFetchGroupQuery<T> fetchGroupQueryFor(Class<T> cls) {
|
||||
return fetchGroupService.queryFor(cls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* A call origin for query execution profiling to collect graph use (for query tuning).
|
||||
*/
|
||||
public interface CallOrigin {
|
||||
|
||||
/**
|
||||
* Return the top element. Typically the top stack element with class and line.
|
||||
*/
|
||||
String getTopElement();
|
||||
|
||||
/**
|
||||
* Return the full description of the call origin.
|
||||
*/
|
||||
String getFullDescription();
|
||||
|
||||
/**
|
||||
* Compute and return an origin key based on the query hash.
|
||||
*/
|
||||
String getOriginKey(int queryHash);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package io.ebean.bean;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.ebean.util.EncodeB64.enc;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
@@ -17,15 +19,15 @@ import java.util.Arrays;
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
public final class CallStack implements Serializable, CallOrigin {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private static final String NEWLINE = "\n";
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
private final int hc;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
|
||||
@@ -37,12 +39,17 @@ public final class CallStack implements Serializable {
|
||||
|
||||
private int computeHashCode() {
|
||||
int hc = 0;
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
hc = 92821 * hc + aCallStack.hashCode();
|
||||
for (StackTraceElement element : callStack) {
|
||||
hc = 92821 * hc + element.hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hc;
|
||||
@@ -63,73 +70,29 @@ public final class CallStack implements Serializable {
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
public String getTopElement() {
|
||||
return callStack[0].toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack lines appended with the given newLine string.
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
@Override
|
||||
public String getFullDescription() {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (StackTraceElement aCallStack : callStack) {
|
||||
sb.append(aCallStack.toString()).append(newLine);
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
sb.append(callStack[i].toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginKey(int queryHash) {
|
||||
return enc(queryHash) + "." + zeroHash + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,13 +95,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private final byte[] flags;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
private boolean loadedFromCache;
|
||||
private Object[] origValues;
|
||||
|
||||
private Exception[] loadErrors;
|
||||
|
||||
private int lazyLoadProperty = -1;
|
||||
|
||||
private Object ownerId;
|
||||
private int sortOrder;
|
||||
|
||||
@@ -116,6 +113,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Constructor only for use by serialization frameworks.
|
||||
*/
|
||||
public EntityBeanIntercept() {
|
||||
this.owner = null;
|
||||
this.flags = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'owning' entity bean.
|
||||
*/
|
||||
@@ -303,6 +308,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true when the bean has been loaded from L2 bean cache.
|
||||
* The effect of this is that we should skip the cache if there
|
||||
* is subsequent lazy loading (bean cache partially populated).
|
||||
*/
|
||||
public void setLoadedFromCache(boolean loadedFromCache) {
|
||||
this.loadedFromCache = loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean was loaded from L2 bean cache.
|
||||
*/
|
||||
public boolean isLoadedFromCache() {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean should be treated as readOnly. If a setter method
|
||||
* is called when it is readOnly an Exception is thrown.
|
||||
@@ -772,7 +793,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
|
||||
public boolean[] getLoaded() {
|
||||
boolean[] ret= new boolean[flags.length];
|
||||
boolean[] ret = new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
private final CallOrigin callOrigin;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
@@ -24,11 +24,11 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
public ObjectGraphOrigin(int queryHash, CallOrigin callOrigin, String beanType) {
|
||||
this.callOrigin = callOrigin;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
this.key = callOrigin.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,22 +49,22 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
public CallOrigin getCallOrigin() {
|
||||
return callOrigin;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
public String getTopElement() {
|
||||
return callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
|
||||
return "key[" + key + "] type[" + beanType + "] " + callOrigin.getTopElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * callStack.hashCode();
|
||||
int hc = 92821 * callOrigin.hashCode();
|
||||
hc = 92821 * hc + beanType.hashCode();
|
||||
hc = 92821 * hc + queryHash;
|
||||
return hc;
|
||||
@@ -82,6 +82,6 @@ public final class ObjectGraphOrigin implements Serializable {
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
&& e.callOrigin.equals(callOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2929,6 +2929,7 @@ public class ServerConfig {
|
||||
}
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
|
||||
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
|
||||
|
||||
@@ -18,5 +18,10 @@ public enum DataErrorType {
|
||||
/**
|
||||
* Data integrity error like an invalid foreign key.
|
||||
*/
|
||||
DataIntegrity
|
||||
DataIntegrity,
|
||||
|
||||
/**
|
||||
* Non recoverable concurrency conflict.
|
||||
*/
|
||||
SerializableConflict
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected Platform platform = Platform.GENERIC;
|
||||
|
||||
protected String truncateTable = "truncate table %s";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
|
||||
protected String tableAliasPlaceHolder = "${ta}";
|
||||
@@ -577,7 +579,7 @@ public class DatabasePlatform {
|
||||
/**
|
||||
* Normally not needed - overridden in CockroachPlatform.
|
||||
*/
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -708,6 +710,13 @@ public class DatabasePlatform {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a statement to truncate a table.
|
||||
*/
|
||||
public String truncateStatement(String table) {
|
||||
return String.format(truncateTable, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the DB schema if it does not exist.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean.config.dbplatform;
|
||||
import io.ebean.AcquireLockException;
|
||||
import io.ebean.DataIntegrityException;
|
||||
import io.ebean.DuplicateKeyException;
|
||||
import io.ebean.SerializableConflictException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
@@ -14,12 +15,12 @@ import java.util.Map;
|
||||
*/
|
||||
public class SqlCodeTranslator implements SqlExceptionTranslator {
|
||||
|
||||
private final Map<String,DataErrorType> map;
|
||||
private final Map<String, DataErrorType> map;
|
||||
|
||||
/**
|
||||
* Create given the map of SQLState codes to error types.
|
||||
*/
|
||||
public SqlCodeTranslator(Map<String,DataErrorType> map) {
|
||||
public SqlCodeTranslator(Map<String, DataErrorType> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@@ -46,6 +47,8 @@ public class SqlCodeTranslator implements SqlExceptionTranslator {
|
||||
return new DuplicateKeyException(message, e);
|
||||
case DataIntegrity:
|
||||
return new DataIntegrityException(message, e);
|
||||
case SerializableConflict:
|
||||
return new SerializableConflictException(message, e);
|
||||
}
|
||||
}
|
||||
// return a generic exception
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class SqlErrorCodes {
|
||||
|
||||
private final Map<String,DataErrorType> map = new HashMap<>();
|
||||
private final Map<String, DataErrorType> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Map the codes to AcquireLockException.
|
||||
@@ -31,6 +31,13 @@ public class SqlErrorCodes {
|
||||
return add(DataErrorType.DuplicateKey, codes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the codes to SerializableConflictException.
|
||||
*/
|
||||
public SqlErrorCodes addSerializableConflict(String... codes) {
|
||||
return add(DataErrorType.SerializableConflict, codes);
|
||||
}
|
||||
|
||||
private SqlErrorCodes add(DataErrorType type, String... codes) {
|
||||
for (String code : codes) {
|
||||
map.put(code, type);
|
||||
|
||||
@@ -21,7 +21,7 @@ public class CockroachPlatform extends PostgresPlatform {
|
||||
* Needs a commit after create index such that alter table add foreign key ... succeeds.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDdlCommitOnCreateIndex() {
|
||||
public boolean isDdlAutoCommit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.platform = Platform.DB2;
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
@@ -26,7 +26,6 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
.addAcquireLock("50200","HYT00")
|
||||
|
||||
@@ -18,7 +18,6 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.historySupport = new HanaHistorySupport();
|
||||
this.basicSqlLimiter = new HanaBasicSqlLimiter();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.platform = Platform.HSQLDB;
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
|
||||
this.truncateTable = "delete from %s";
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
@@ -31,7 +31,6 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.config.dbplatform.DbViewHistorySupport;
|
||||
|
||||
/**
|
||||
* Runtime support for @History with NuoDB.
|
||||
*/
|
||||
public class NuoDbHistorySupport extends DbViewHistorySupport {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.config.dbplatform.SqlErrorCodes;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* NuoDb specific platform.
|
||||
*/
|
||||
public class NuoDbPlatform extends DatabasePlatform {
|
||||
|
||||
public NuoDbPlatform() {
|
||||
super();
|
||||
this.platform = Platform.NUODB;
|
||||
this.idInExpandedForm = true;
|
||||
this.supportsResultSetConcurrencyModeUpdatable = false;
|
||||
this.supportsDeleteTableAlias = true;
|
||||
this.columnAliasPrefix = null;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.historySupport = new NuoDbHistorySupport();
|
||||
//this.dbEncrypt = ...
|
||||
dbIdentity.setIdType(IdType.IDENTITY);
|
||||
dbIdentity.setSupportsIdentity(true);
|
||||
dbIdentity.setSupportsSequence(true);
|
||||
dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
|
||||
// No referential integrity exception to map
|
||||
this.exceptionTranslator =
|
||||
new SqlErrorCodes()
|
||||
//.addAcquireLock("")
|
||||
.addDuplicateKey("23000")
|
||||
.addSerializableConflict("40002")
|
||||
.build();
|
||||
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
return new NuoDbSequence(be, ds, seqName, stepSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
default:
|
||||
return sql + " for update";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebean.config.dbplatform.nuodb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.config.dbplatform.SequenceStepIdGenerator;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
public class NuoDbSequence extends SequenceStepIdGenerator {
|
||||
|
||||
private final String nextSql;
|
||||
|
||||
/**
|
||||
* Construct where batchSize is the sequence step size.
|
||||
*/
|
||||
public NuoDbSequence(BackgroundExecutor be, DataSource ds, String seqName, int stepSize) {
|
||||
super(be, ds, seqName, stepSize);
|
||||
this.nextSql = "select next value for " + seqName + " from dual";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql(int batchSize) {
|
||||
return nextSql;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.basicSqlLimiter = new BasicSqlAnsiLimiter();
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
dbIdentity.setSupportsSequence(true);
|
||||
dbIdentity.setSupportsIdentity(true);
|
||||
@@ -48,6 +48,7 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
//.addAcquireLock("")
|
||||
.addDuplicateKey("1")
|
||||
.addDataIntegrity("2291")
|
||||
.addSerializableConflict("72000")
|
||||
.build();
|
||||
|
||||
this.openQuote = "\"";
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
this.nativeUuidType = true;
|
||||
this.columnAliasPrefix = null;
|
||||
|
||||
this.truncateTable = "truncate table %s cascade";
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
|
||||
@@ -52,6 +52,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
.addAcquireLock("55P03")
|
||||
.addDuplicateKey("23505")
|
||||
.addDataIntegrity("23000","23502","23503","23514")
|
||||
.addSerializableConflict("40001")
|
||||
.build();
|
||||
|
||||
this.openQuote = "\"";
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()");
|
||||
|
||||
this.truncateTable = "delete from %s";
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
this.likeClauseRaw = "like ?";
|
||||
this.likeClauseEscaped = "like ?";
|
||||
|
||||
@@ -24,6 +24,11 @@ public interface BeanQueryRequest<T> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return true if an Id IN expression should have the bind parameters padded.
|
||||
*/
|
||||
boolean isPadInExpression();
|
||||
|
||||
/**
|
||||
* Return true if multi-value binding using Array or Table Values is supported.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebean.service;
|
||||
|
||||
import io.ebean.FetchGroup;
|
||||
import io.ebean.Query;
|
||||
|
||||
/**
|
||||
* Extension of Query to build FetchGroup via query beans.
|
||||
*/
|
||||
public interface SpiFetchGroupQuery<T> extends Query<T> {
|
||||
|
||||
/**
|
||||
* Build the fetch group with select and fetch clauses.
|
||||
*/
|
||||
FetchGroup<T> buildFetchGroup();
|
||||
}
|
||||
@@ -23,4 +23,10 @@ public interface SpiFetchGroupService {
|
||||
* @return The FetchGroupBuilder to add additional select and fetch clauses
|
||||
*/
|
||||
<T> FetchGroupBuilder<T> of(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Return a new FetchGroupQuery for building FetchGroup via query beans.
|
||||
*/
|
||||
<T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.ebean.util;
|
||||
|
||||
/**
|
||||
* Integer to base64 encoder.
|
||||
*/
|
||||
public final class EncodeB64 {
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -17,8 +15,6 @@ import java.util.Set;
|
||||
*/
|
||||
public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoadBeanRequest.class);
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
private final LoadBeanBuffer loadBuffer;
|
||||
@@ -27,11 +23,14 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
private boolean loadedFromCache;
|
||||
|
||||
/**
|
||||
* Construct for lazy load request.
|
||||
*/
|
||||
public LoadBeanRequest(LoadBeanBuffer LoadBuffer, String lazyLoadProperty, boolean loadCache) {
|
||||
this(LoadBuffer, null, true, lazyLoadProperty, loadCache);
|
||||
public LoadBeanRequest(LoadBeanBuffer LoadBuffer, EntityBeanIntercept ebi, boolean loadCache) {
|
||||
this(LoadBuffer, null, true, ebi.getLazyLoadProperty(), loadCache);
|
||||
this.loadedFromCache = ebi.isLoadedFromCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,10 +55,16 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
return loadBuffer.getBeanDescriptor().getBeanType();
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
/**
|
||||
* Return true if the beans invoking lazy loading were previously loaded from cache.
|
||||
*/
|
||||
public boolean isLoadedFromCache() {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
private boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "path:" + loadBuffer.getFullPath() + " batch:" + batch.size();
|
||||
@@ -75,17 +80,10 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanBuffer getLoadContext() {
|
||||
private LoadBeanBuffer getLoadContext() {
|
||||
return loadBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return getLoadContext().getBatchSize();
|
||||
}
|
||||
@@ -93,30 +91,14 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the list of Id values for the beans in the lazy load buffer.
|
||||
*/
|
||||
public List<Object> getIdList(int batchSize) {
|
||||
public List<Object> getIdList() {
|
||||
|
||||
List<Object> idList = new ArrayList<>(batchSize);
|
||||
List<Object> idList = new ArrayList<>();
|
||||
|
||||
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
|
||||
for (EntityBeanIntercept ebi : batch) {
|
||||
EntityBean bean = ebi.getOwner();
|
||||
idList.add(desc.getId(bean));
|
||||
idList.add(desc.getId(ebi.getOwner()));
|
||||
}
|
||||
|
||||
|
||||
if (!desc.isMultiValueIdSupported() && !idList.isEmpty()) {
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
// for performance make up the Id's to the batch size
|
||||
// so we get the same query (for Ebean and the db)
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
// just add the first Id again
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idList;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.api;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.server.core.BindPadding;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
@@ -65,13 +66,6 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadManyBuffer getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if lazy loading should only load the id values.
|
||||
* <p>
|
||||
@@ -80,14 +74,14 @@ public class LoadManyRequest extends LoadRequest {
|
||||
* used.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isOnlyIds() {
|
||||
private boolean isOnlyIds() {
|
||||
return onlyIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should load the Collection ids into the cache.
|
||||
*/
|
||||
public boolean isLoadCache() {
|
||||
private boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
@@ -98,22 +92,16 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadContext.getBatchSize();
|
||||
}
|
||||
|
||||
private List<Object> getParentIdList(int batchSize) {
|
||||
private List<Object> getParentIdList() {
|
||||
|
||||
ArrayList<Object> idList = new ArrayList<>(batchSize);
|
||||
List<Object> idList = new ArrayList<>();
|
||||
|
||||
BeanPropertyAssocMany<?> many = getMany();
|
||||
for (BeanCollection<?> bc : batch) {
|
||||
idList.add(many.getParentId(bc.getOwnerBean()));
|
||||
}
|
||||
if (!many.getTargetDescriptor().isMultiValueIdSupported()) {
|
||||
int extraIds = batchSize - batch.size();
|
||||
if (extraIds > 0) {
|
||||
Object firstId = idList.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
idList.add(firstId);
|
||||
}
|
||||
}
|
||||
if (many.getTargetDescriptor().isPadInExpression()) {
|
||||
BindPadding.padIds(idList);
|
||||
}
|
||||
|
||||
return idList;
|
||||
@@ -123,7 +111,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadContext.getBeanProperty();
|
||||
}
|
||||
|
||||
public SpiQuery<?> createQuery(SpiEbeanServer server, int batchSize) {
|
||||
public SpiQuery<?> createQuery(SpiEbeanServer server) {
|
||||
|
||||
BeanPropertyAssocMany<?> many = getMany();
|
||||
|
||||
@@ -142,10 +130,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
}
|
||||
|
||||
query.setLazyLoadForParents(many);
|
||||
|
||||
List<Object> idList = getParentIdList(batchSize);
|
||||
many.addWhereParentIdIn(query, idList, loadContext.isUseDocStore());
|
||||
|
||||
many.addWhereParentIdIn(query, getParentIdList(), loadContext.isUseDocStore());
|
||||
query.setPersistenceContext(loadContext.getPersistenceContext());
|
||||
|
||||
String mode = isLazy() ? "+lazy" : "+query";
|
||||
|
||||
@@ -11,7 +11,7 @@ import io.ebean.Transaction;
|
||||
import io.ebean.TxScope;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -81,7 +81,7 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader,
|
||||
* graph costing.
|
||||
* </p>
|
||||
*/
|
||||
CallStack createCallStack();
|
||||
CallOrigin createCallOrigin();
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope to use defined at query or server level.
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.ebean.OrderBy;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
@@ -289,6 +289,11 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
*/
|
||||
boolean selectAllForLazyLoadProperty();
|
||||
|
||||
/**
|
||||
* Set the on a secondary query given the label, relativePath and profile location of the parent query.
|
||||
*/
|
||||
void setProfilePath(String label, String relativePath, ProfileLocation profileLocation);
|
||||
|
||||
/**
|
||||
* Set the query mode.
|
||||
*/
|
||||
@@ -558,7 +563,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
* because the queryPlanHash is used to identify the query point.
|
||||
* </p>
|
||||
*/
|
||||
ObjectGraphNode setOrigin(CallStack callStack);
|
||||
ObjectGraphNode setOrigin(CallOrigin callOrigin);
|
||||
|
||||
/**
|
||||
* Set the profile point of the bean or collection that is lazy loading.
|
||||
|
||||
@@ -44,7 +44,7 @@ public class DdlGenerator {
|
||||
private final boolean extraDdl;
|
||||
private final boolean createOnly;
|
||||
private final boolean jaxbPresent;
|
||||
private final boolean ddlCommitOnCreateIndex;
|
||||
private final boolean ddlAutoCommit;
|
||||
private final String dbSchema;
|
||||
private final ScriptTransform scriptTransform;
|
||||
|
||||
@@ -63,10 +63,10 @@ public class DdlGenerator {
|
||||
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
|
||||
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
|
||||
this.runDdl = false;
|
||||
this.ddlCommitOnCreateIndex = false;
|
||||
this.ddlAutoCommit = false;
|
||||
} else {
|
||||
this.runDdl = serverConfig.isDdlRun();
|
||||
this.ddlCommitOnCreateIndex = server.getDatabasePlatform().isDdlCommitOnCreateIndex();
|
||||
this.ddlAutoCommit = server.getDatabasePlatform().isDdlAutoCommit();
|
||||
}
|
||||
this.scriptTransform = createScriptTransform(serverConfig.getMigrationConfig());
|
||||
this.baseDir = initBaseDir();
|
||||
@@ -160,13 +160,11 @@ public class DdlGenerator {
|
||||
|
||||
DdlRunner runner = new DdlRunner(expectErrors, scriptName);
|
||||
try {
|
||||
if (expectErrors) {
|
||||
if (expectErrors || ddlAutoCommit) {
|
||||
connection.setAutoCommit(true);
|
||||
} else if (ddlCommitOnCreateIndex) {
|
||||
runner.setCommitOnCreateIndex();
|
||||
}
|
||||
int count = runner.runAll(scriptTransform.transform(content), connection);
|
||||
if (expectErrors) {
|
||||
if (expectErrors || ddlAutoCommit) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
connection.commit();
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebean.config.dbplatform.hana.HanaPlatform;
|
||||
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
|
||||
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
|
||||
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
|
||||
import io.ebean.config.dbplatform.oracle.OraclePlatform;
|
||||
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
|
||||
import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
|
||||
@@ -804,6 +805,8 @@ public class DefaultDbMigration implements DbMigration {
|
||||
return new SQLitePlatform();
|
||||
case HANA:
|
||||
return new HanaPlatform();
|
||||
case NUODB:
|
||||
return new NuoDbPlatform();
|
||||
case COCKROACH:
|
||||
return new CockroachPlatform();
|
||||
case CLICKHOUSE:
|
||||
|
||||
@@ -10,7 +10,6 @@ public class CockroachDdl extends PlatformDdl {
|
||||
|
||||
public CockroachDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new PostgresHistoryDdl();
|
||||
this.dropTableCascade = " cascade";
|
||||
this.columnSetType = "type ";
|
||||
this.alterTableIfExists = "if exists ";
|
||||
|
||||
+8
-11
@@ -29,11 +29,11 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
protected String viewSuffix;
|
||||
protected String historySuffix;
|
||||
|
||||
|
||||
protected String currentTimestamp = "now(6)";
|
||||
protected String sysPeriodType = "datetime(6)";
|
||||
protected String now = "now(6)";
|
||||
protected String sysPeriodEndValue = "now(6)";
|
||||
|
||||
public DbTriggerBasedHistoryDdl() {
|
||||
DbTriggerBasedHistoryDdl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,7 +164,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
protected void addSysPeriodColumns(DdlBuffer apply, String baseTableName, String whenCreatedColumn) throws IOException {
|
||||
|
||||
apply.append("alter table ").append(baseTableName).append(" add column ")
|
||||
.append(sysPeriodStart).append(" ").append(sysPeriodType).append(" default ").append(currentTimestamp).endOfStatement();
|
||||
.append(sysPeriodStart).append(" ").append(sysPeriodType).append(" default ").append(now).endOfStatement();
|
||||
apply.append("alter table ").append(baseTableName).append(" add column ")
|
||||
.append(sysPeriodEnd).append(" ").append(sysPeriodType).endOfStatement();
|
||||
|
||||
@@ -246,13 +246,12 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
|
||||
appendColumnNames(buffer, columns, "");
|
||||
buffer.append(") values (OLD.").append(sysPeriodStart).append(", ").append(currentTimestamp).append(",");
|
||||
buffer.append(") values (OLD.").append(sysPeriodStart).append(", ").append(sysPeriodEndValue).append(",");
|
||||
appendColumnNames(buffer, columns, "OLD.");
|
||||
buffer.append(");").newLine();
|
||||
}
|
||||
|
||||
protected void appendColumnNames(DdlBuffer buffer, List<String> columns, String columnPrefix) throws IOException {
|
||||
|
||||
void appendColumnNames(DdlBuffer buffer, List<String> columns, String columnPrefix) throws IOException {
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (i > 0) {
|
||||
buffer.append(", ");
|
||||
@@ -265,8 +264,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
/**
|
||||
* Append a single column to the buffer if it is not null.
|
||||
*/
|
||||
protected void appendColumnName(DdlBuffer buffer, String prefix, String columnName) throws IOException {
|
||||
|
||||
void appendColumnName(DdlBuffer buffer, String prefix, String columnName) throws IOException {
|
||||
if (columnName != null) {
|
||||
buffer.append(prefix).append(columnName);
|
||||
}
|
||||
@@ -280,8 +278,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
* the column.
|
||||
* </p>
|
||||
*/
|
||||
protected List<String> columnNamesForApply(MTable table) {
|
||||
|
||||
List<String> columnNamesForApply(MTable table) {
|
||||
return table.allHistoryColumns(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
private static final String TRIGGER_CLASS = H2HistoryTrigger.class.getName();
|
||||
|
||||
public H2HistoryDdl() {
|
||||
H2HistoryDdl() {
|
||||
this.sysPeriodType = "timestamp";
|
||||
this.currentTimestamp = "now()";
|
||||
this.now = "now()";
|
||||
this.sysPeriodEndValue = "now()";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-3
@@ -11,13 +11,11 @@ import java.io.IOException;
|
||||
*/
|
||||
public class MySqlHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
|
||||
public MySqlHistoryDdl() {
|
||||
MySqlHistoryDdl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
|
||||
|
||||
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
|
||||
buffer.append("drop trigger ").append(deleteTriggerName(baseTable)).endOfStatement();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.annotation.ConstraintMode;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
|
||||
public class NuoDbDdl extends PlatformDdl {
|
||||
|
||||
public NuoDbDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.historyDdl = new NuoDbHistoryDdl();
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
this.dropConstraintIfExists = "drop constraint";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendForeignKeyOnDelete(StringBuilder buffer, ConstraintMode mode) {
|
||||
if (mode == ConstraintMode.RESTRICT) {
|
||||
// do nothing
|
||||
} else if (mode == ConstraintMode.SET_NULL) {
|
||||
// do nothing
|
||||
} else {
|
||||
super.appendForeignKeyOnDelete(buffer, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
|
||||
import io.ebeaninternal.dbmigration.model.MTable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NuoDB history support using DB triggers to maintain a history table.
|
||||
*/
|
||||
public class NuoDbHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
NuoDbHistoryDdl() {
|
||||
this.now = "now()";
|
||||
this.sysPeriodEndValue = "NEW.sys_period_start";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
|
||||
|
||||
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
|
||||
buffer.append("drop trigger ").append(deleteTriggerName(baseTable)).endOfStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
|
||||
|
||||
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
|
||||
|
||||
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
|
||||
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
|
||||
|
||||
recreateHistoryView(update);
|
||||
|
||||
DdlBuffer buffer = update.historyTriggerBuffer();
|
||||
String baseTable = update.getBaseTable();
|
||||
|
||||
dropTriggers(buffer, baseTable);
|
||||
addBeforeUpdate(updateTriggerName(baseTable), update);
|
||||
addBeforeDelete(deleteTriggerName(baseTable), update);
|
||||
}
|
||||
|
||||
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) throws IOException {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
addTriggerStart(triggerName, update, apply, " before update for each row as ");
|
||||
apply.append(" NEW.sys_period_start = greatest(current_timestamp, date_add(OLD.sys_period_start, interval 1 microsecond))").endOfStatement();
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
addEndTrigger(apply);
|
||||
}
|
||||
|
||||
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) throws IOException {
|
||||
|
||||
DdlBuffer apply = update.historyTriggerBuffer();
|
||||
addTriggerStart(triggerName, update, apply, " before delete for each row as");
|
||||
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
|
||||
addEndTrigger(apply);
|
||||
}
|
||||
|
||||
private void addTriggerStart(String triggerName, DbTriggerUpdate update, DdlBuffer apply, String s) throws IOException {
|
||||
apply
|
||||
.append("delimiter $$").newLine()
|
||||
.append("create or replace trigger ").append(triggerName).append(" for ").append(update.getBaseTable())
|
||||
.append(s).newLine();
|
||||
}
|
||||
|
||||
private void addEndTrigger(DdlBuffer apply) throws IOException {
|
||||
apply.append("end_trigger")
|
||||
.endOfStatement()
|
||||
.append("$$").newLine()
|
||||
.newLine();
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -12,9 +12,9 @@ import java.util.List;
|
||||
*/
|
||||
public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
|
||||
public PostgresHistoryDdl() {
|
||||
this.currentTimestamp = "current_timestamp";
|
||||
PostgresHistoryDdl() {
|
||||
this.now = "current_timestamp";
|
||||
this.sysPeriodEndValue = "current_timestamp";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +36,7 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
protected void addSysPeriodColumns(DdlBuffer apply, String baseTableName, String whenCreatedColumn) throws IOException {
|
||||
apply
|
||||
.append("alter table ").append(baseTableName)
|
||||
.append(" add column ").append(sysPeriod).append(" tstzrange not null default tstzrange(").append(currentTimestamp).append(", null)")
|
||||
.append(" add column ").append(sysPeriod).append(" tstzrange not null default tstzrange(").append(now).append(", null)")
|
||||
.endOfStatement();
|
||||
|
||||
if (whenCreatedColumn != null) {
|
||||
|
||||
@@ -149,7 +149,7 @@ public class AutoTuneDiffCollection {
|
||||
origin.setKey(point.getKey());
|
||||
origin.setBeanType(point.getBeanType());
|
||||
origin.setDetail(entry.getDetail().toString());
|
||||
origin.setCallStack(point.getCallStack().description("\n"));
|
||||
origin.setCallStack(point.getCallOrigin().getFullDescription());
|
||||
origin.setOriginal(query);
|
||||
|
||||
if (updateTuning) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.autotune.service;
|
||||
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.AutoTuneConfig;
|
||||
import io.ebean.config.AutoTuneMode;
|
||||
@@ -97,7 +97,7 @@ public class BaseQueryTuner {
|
||||
|
||||
if (!useTuning(query)) {
|
||||
if (profiling) {
|
||||
profiling(query, server.createCallStack());
|
||||
profiling(query, server.createCallOrigin());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -110,8 +110,8 @@ public class BaseQueryTuner {
|
||||
}
|
||||
|
||||
// create a query point to identify the query
|
||||
CallStack stack = server.createCallStack();
|
||||
ObjectGraphNode origin = query.setOrigin(stack);
|
||||
CallOrigin callOrigin = server.createCallOrigin();
|
||||
ObjectGraphNode origin = query.setOrigin(callOrigin);
|
||||
|
||||
if (profiling) {
|
||||
if (profilingListener.isProfileRequest(origin, query)) {
|
||||
@@ -154,10 +154,10 @@ public class BaseQueryTuner {
|
||||
}
|
||||
}
|
||||
|
||||
private void profiling(SpiQuery<?> query, CallStack stack) {
|
||||
private void profiling(SpiQuery<?> query, CallOrigin call) {
|
||||
|
||||
// create a query point to identify the query
|
||||
ObjectGraphNode origin = query.setOrigin(stack);
|
||||
ObjectGraphNode origin = query.setOrigin(call);
|
||||
if (profilingListener.isProfileRequest(origin, query)) {
|
||||
// collect more profiling based on profiling rate etc
|
||||
query.setProfilingListener(profilingListener);
|
||||
|
||||
@@ -13,6 +13,8 @@ public class CachedBeanDataToBean {
|
||||
public static void load(BeanDescriptor<?> desc, EntityBean bean, CachedBeanData cacheBeanData, PersistenceContext context) {
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
// any future lazy loading skips L2 bean cache
|
||||
ebi.setLoadedFromCache(true);
|
||||
|
||||
BeanProperty idProperty = desc.getIdProperty();
|
||||
if (desc.getInheritInfo() != null) {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Supports padding bind parameters for IN expressions.
|
||||
* <p>
|
||||
* We do this in order to get better hit ratio on DB query plans.
|
||||
* </p>
|
||||
*/
|
||||
public final class BindPadding {
|
||||
|
||||
/**
|
||||
* Pad out the Ids into common bucket sizes.
|
||||
*
|
||||
* @param idCollection The collection of Ids values being bound.
|
||||
*/
|
||||
public static void padIds(List<Object> idCollection) {
|
||||
|
||||
int extraIds = padding(idCollection.size());
|
||||
if (extraIds > 0) {
|
||||
// for performance make up the Id's to the batch size
|
||||
// so we get the same query (for Ebean and the db)
|
||||
Object firstId = idCollection.get(0);
|
||||
for (int i = 0; i < extraIds; i++) {
|
||||
// just add the first Id again
|
||||
idCollection.add(firstId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra padding on binding id's in order to get better hit ratio on DB prepared statements / query plans.
|
||||
*/
|
||||
static int padding(int size) {
|
||||
if (size == 1) {
|
||||
return 0;
|
||||
}
|
||||
if (size <= 5) {
|
||||
return 5 - size;
|
||||
}
|
||||
if (size <= 10) {
|
||||
return 10 - size;
|
||||
}
|
||||
if (size <= 20) {
|
||||
return 20 - size;
|
||||
}
|
||||
if (size <= 40) {
|
||||
return 40 - size;
|
||||
}
|
||||
if (size <= 50) {
|
||||
return 50 - size;
|
||||
}
|
||||
return size <= 100 ? 100 - size : 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.CallOrigin;
|
||||
|
||||
/**
|
||||
* Creates CallOrigin based on the stack trace.
|
||||
*/
|
||||
public interface CallOriginFactory {
|
||||
|
||||
/**
|
||||
* Create and return the CallStack given the stack trace elements.
|
||||
*/
|
||||
CallOrigin createCallOrigin();
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.CallStack;
|
||||
|
||||
/**
|
||||
* Creates CallStack based on the stack trace.
|
||||
*/
|
||||
public interface CallStackFactory {
|
||||
|
||||
/**
|
||||
* Create and return the CallStack given the stack trace elements.
|
||||
*/
|
||||
CallStack createCallStack();
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebean.config.dbplatform.hana.HanaPlatform;
|
||||
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
|
||||
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
|
||||
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
|
||||
import io.ebean.config.dbplatform.oracle.OraclePlatform;
|
||||
import io.ebean.config.dbplatform.postgres.Postgres8Platform;
|
||||
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
|
||||
@@ -108,6 +109,9 @@ public class DatabasePlatformFactory {
|
||||
if (dbName.equals("clickhouse")) {
|
||||
return new ClickHousePlatform();
|
||||
}
|
||||
if (dbName.equals("nuodb")) {
|
||||
return new NuoDbPlatform();
|
||||
}
|
||||
if (dbName.equals("sqlite")) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
@@ -158,6 +162,8 @@ public class DatabasePlatformFactory {
|
||||
return new HsqldbPlatform();
|
||||
} else if (dbProductName.contains("postgres")) {
|
||||
return readPostgres(connection);
|
||||
} else if (dbProductName.contains("nuo")) {
|
||||
return new NuoDbPlatform();
|
||||
} else if (dbProductName.contains("sqlite")) {
|
||||
return new SQLitePlatform();
|
||||
} else if (dbProductName.contains("db2")) {
|
||||
@@ -177,7 +183,7 @@ public class DatabasePlatformFactory {
|
||||
/**
|
||||
* Use a select version() query as it could be Postgres or CockroachDB.
|
||||
*/
|
||||
private static PostgresPlatform readPostgres(Connection connection) {
|
||||
private static DatabasePlatform readPostgres(Connection connection) {
|
||||
// Postgres driver uses a hardcoded product name so use version() query
|
||||
PreparedStatement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
@@ -25,7 +26,7 @@ import java.util.List;
|
||||
/**
|
||||
* Helper to handle lazy loading and refreshing of beans.
|
||||
*/
|
||||
public class DefaultBeanLoader {
|
||||
class DefaultBeanLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultBeanLoader.class);
|
||||
|
||||
@@ -33,63 +34,19 @@ public class DefaultBeanLoader {
|
||||
|
||||
private final boolean onIterateUseExtraTxn;
|
||||
|
||||
protected DefaultBeanLoader(DefaultServer server) {
|
||||
DefaultBeanLoader(DefaultServer server) {
|
||||
this.server = server;
|
||||
this.onIterateUseExtraTxn = server.getDatabasePlatform().useExtraTransactionOnIterateSecondaryQueries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a batch size that might be less than the requestedBatchSize.
|
||||
* <p>
|
||||
* This means we can have large and variable requestedBatchSizes.
|
||||
* </p>
|
||||
* <p>
|
||||
* We want to restrict the number of different batch sizes as we want to
|
||||
* re-use the query plan cache and get DB statement re-use.
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchSize) {
|
||||
void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
if (batchSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
}
|
||||
if (batchSize <= 5) {
|
||||
// anything less than 5 becomes 5
|
||||
return 5;
|
||||
}
|
||||
if (batchSize <= 10) {
|
||||
return 10;
|
||||
}
|
||||
if (batchSize <= 20) {
|
||||
return 20;
|
||||
}
|
||||
if (batchSize <= 50) {
|
||||
return 50;
|
||||
}
|
||||
if (batchSize <= 100) {
|
||||
return 100;
|
||||
}
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
List<BeanCollection<?>> batch = loadRequest.getBatch();
|
||||
|
||||
int batchSize = getBatchSize(batch.size());
|
||||
|
||||
SpiQuery<?> query = loadRequest.createQuery(server, batchSize);
|
||||
SpiQuery<?> query = loadRequest.createQuery(server);
|
||||
executeQuery(loadRequest, query);
|
||||
|
||||
loadRequest.postLoad();
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
EntityBean parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
@@ -97,8 +54,8 @@ public class DefaultBeanLoader {
|
||||
loadManyInternal(parentBean, propertyName, null, false, onlyIds);
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, false);
|
||||
void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
loadManyInternal(parentBean, propertyName, null, true, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, boolean onlyIds) {
|
||||
@@ -147,8 +104,7 @@ public class DefaultBeanLoader {
|
||||
query.setLoadDescription("+lazy", null);
|
||||
}
|
||||
|
||||
String idProperty = parentDesc.getIdBinder().getIdProperty();
|
||||
query.select(idProperty);
|
||||
query.select(parentDesc.getIdBinder().getIdProperty());
|
||||
|
||||
if (onlyIds) {
|
||||
query.fetch(many.getName(), many.getTargetIdProperty());
|
||||
@@ -185,16 +141,14 @@ public class DefaultBeanLoader {
|
||||
/**
|
||||
* Load a batch of beans for +query or +lazy loading.
|
||||
*/
|
||||
public void loadBean(LoadBeanRequest loadRequest) {
|
||||
void loadBean(LoadBeanRequest loadRequest) {
|
||||
|
||||
List<EntityBeanIntercept> batch = loadRequest.getBatch();
|
||||
if (batch.isEmpty()) {
|
||||
throw new RuntimeException("Nothing in batch?");
|
||||
}
|
||||
|
||||
int batchSize = getBatchSize(batch.size());
|
||||
|
||||
List<Object> idList = loadRequest.getIdList(batchSize);
|
||||
List<Object> idList = loadRequest.getIdList();
|
||||
if (idList.isEmpty()) {
|
||||
// everything was loaded from cache
|
||||
return;
|
||||
@@ -202,6 +156,9 @@ public class DefaultBeanLoader {
|
||||
|
||||
SpiQuery<?> query = server.createQuery(loadRequest.getBeanType());
|
||||
loadRequest.configureQuery(query, idList);
|
||||
if (loadRequest.isLoadedFromCache()) {
|
||||
query.setBeanCacheMode(CacheMode.PUT);
|
||||
}
|
||||
|
||||
List<?> list = executeQuery(loadRequest, query);
|
||||
loadRequest.postLoad(list);
|
||||
@@ -228,7 +185,7 @@ public class DefaultBeanLoader {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
|
||||
}
|
||||
|
||||
@@ -315,6 +272,5 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
|
||||
desc.resetManyProperties(dbBean);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.CallStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -7,7 +8,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* Default CallStackFactory where the Hash function for StackTraceElement includes the line number.
|
||||
*/
|
||||
public class DefaultCallStackFactory implements CallStackFactory {
|
||||
public class DefaultCallOriginFactory implements CallOriginFactory {
|
||||
|
||||
private static final int IGNORE_LEADING_ELEMENTS = 5;
|
||||
|
||||
@@ -15,12 +16,12 @@ public class DefaultCallStackFactory implements CallStackFactory {
|
||||
|
||||
private final int maxCallStack;
|
||||
|
||||
DefaultCallStackFactory(int maxCallStack) {
|
||||
DefaultCallOriginFactory(int maxCallStack) {
|
||||
this.maxCallStack = maxCallStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallStack createCallStack() {
|
||||
public CallOrigin createCallOrigin() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
|
||||
// ignore the first 6 as they are always avaje stack elements
|
||||
@@ -58,7 +59,7 @@ public class DefaultCallStackFactory implements CallStackFactory {
|
||||
return element.getMethodName().startsWith("_ebean_");
|
||||
}
|
||||
|
||||
private CallStack createCallStack(StackTraceElement[] finalTrace) {
|
||||
private CallOrigin createCallStack(StackTraceElement[] finalTrace) {
|
||||
return new CallStack(finalTrace, finalTrace[0].hashCode(), pathHash(finalTrace));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import io.ebean.ValuePair;
|
||||
import io.ebean.Version;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
@@ -124,8 +124,10 @@ import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -162,7 +164,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
*/
|
||||
private final ClockService clockService;
|
||||
|
||||
private final CallStackFactory callStackFactory;
|
||||
private final CallOriginFactory callStackFactory;
|
||||
|
||||
/**
|
||||
* Handles the save, delete, updateSql CallableSql.
|
||||
@@ -310,12 +312,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
/**
|
||||
* Create the CallStackFactory depending if AutoTune is being used.
|
||||
*/
|
||||
private CallStackFactory initCallStackFactory(ServerConfig serverConfig) {
|
||||
private CallOriginFactory initCallStackFactory(ServerConfig serverConfig) {
|
||||
if (!serverConfig.getAutoTuneConfig().isActive()) {
|
||||
// use a common CallStack for performance as we don't care with no AutoTune
|
||||
return new NoopCallStackFactory();
|
||||
return new NoopCallOriginFactory();
|
||||
}
|
||||
return new DefaultCallStackFactory(serverConfig.getMaxCallStack());
|
||||
return new DefaultCallOriginFactory(serverConfig.getMaxCallStack());
|
||||
}
|
||||
|
||||
private void configureServerPlugins() {
|
||||
@@ -568,37 +570,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
@Override
|
||||
public void refreshMany(Object parentBean, String propertyName) {
|
||||
|
||||
beanLoader.refreshMany(checkEntityBean(parentBean), propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
beanLoader.loadMany(loadRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
beanLoader.loadMany(bc, onlyIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(Object bean) {
|
||||
|
||||
beanLoader.refresh(checkEntityBean(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(LoadBeanRequest loadRequest) {
|
||||
|
||||
beanLoader.loadBean(loadRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
|
||||
beanLoader.loadBean(ebi);
|
||||
}
|
||||
|
||||
@@ -639,6 +635,36 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
externalModification(evt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate(Class<?>... types) {
|
||||
List<String> tableNames = new ArrayList<>();
|
||||
for (Class<?> type : types) {
|
||||
tableNames.add(getBeanDescriptor(type).getBaseTable());
|
||||
}
|
||||
truncate(tableNames.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate(String... tables) {
|
||||
try (Connection connection = getDataSource().getConnection()) {
|
||||
for (String table : tables) {
|
||||
executeSql(connection, databasePlatform.truncateStatement(table));
|
||||
}
|
||||
connection.commit();
|
||||
} catch(SQLException e) {
|
||||
throw new PersistenceException("Error executing truncate", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeSql(Connection connection, String sql) throws SQLException {
|
||||
if (sql != null) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
transactionManager.log().sql().debug(sql);
|
||||
stmt.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
@@ -1103,7 +1129,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
// if determine cost and no origin for AutoTune
|
||||
if (query.getParentNode() == null) {
|
||||
query.setOrigin(createCallStack());
|
||||
query.setOrigin(createCallOrigin());
|
||||
}
|
||||
|
||||
return new OrmQueryRequest<>(this, queryEngine, query, (SpiTransaction) t);
|
||||
@@ -2277,8 +2303,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public CallStack createCallStack() {
|
||||
return callStackFactory.createCallStack();
|
||||
public CallOrigin createCallOrigin() {
|
||||
return callStackFactory.createCallOrigin();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ class DefaultSlowQueryListener implements SlowQueryListener {
|
||||
String firstStack = "";
|
||||
ObjectGraphNode node = event.getOriginNode();
|
||||
if (node != null) {
|
||||
firstStack = node.getOriginQueryPoint().getFirstStackElement();
|
||||
firstStack = node.getOriginQueryPoint().getTopElement();
|
||||
}
|
||||
log.warn("Slow query warning - millis:{} rows:{} caller[{}] sql[{}]", event.getTimeMillis(), event.getRowCount(), firstStack, event.getSql());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.CallStack;
|
||||
|
||||
/**
|
||||
* A CallOriginFactory we can use when we don't use AutoTune.
|
||||
*/
|
||||
class NoopCallOriginFactory implements CallOriginFactory {
|
||||
|
||||
private final CallOrigin COMMON = new CallStack(Thread.currentThread().getStackTrace(), 0, 0);
|
||||
|
||||
@Override
|
||||
public CallOrigin createCallOrigin() {
|
||||
return COMMON;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.CallStack;
|
||||
|
||||
/**
|
||||
* A CallStackFactory we can use when we don't use AutoTune.
|
||||
*/
|
||||
class NoopCallStackFactory implements CallStackFactory {
|
||||
|
||||
private final CallStack COMMON = new CallStack(Thread.currentThread().getStackTrace(), 0, 0);
|
||||
|
||||
@Override
|
||||
public CallStack createCallStack() {
|
||||
return COMMON;
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.persistenceContext = query.getPersistenceContext();
|
||||
}
|
||||
|
||||
public PersistenceException translate(String bindLog, String sql, SQLException e) {
|
||||
@@ -115,6 +116,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPadInExpression() {
|
||||
return beanDescriptor.isPadInExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiValueIdSupported() {
|
||||
return beanDescriptor.isMultiValueIdSupported();
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.HanaColumnStoreDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.HsqldbDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.MySqlDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.NuoDbDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.Oracle10Ddl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.platform.PostgresDdl;
|
||||
@@ -33,6 +34,8 @@ public class PlatformDdlBuilder {
|
||||
return new MySqlDdl(platform);
|
||||
case HSQLDB:
|
||||
return new HsqldbDdl(platform);
|
||||
case NUODB:
|
||||
return new NuoDbDdl(platform);
|
||||
case ORACLE:
|
||||
return new Oracle10Ddl(platform);
|
||||
case SQLITE:
|
||||
|
||||
@@ -21,7 +21,9 @@ class AssocOneHelpRefInherit extends AssocOneHelp {
|
||||
@Override
|
||||
void loadIgnore(DbReadContext ctx) {
|
||||
property.targetIdBinder.loadIgnore(ctx);
|
||||
ctx.getDataReader().incrementPos(1);
|
||||
if (inherit.hasChildren()) {
|
||||
ctx.getDataReader().incrementPos(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,6 +112,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
*/
|
||||
@@ -1833,6 +1835,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return multiValueSupported && isSimpleId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Id IN expression should have bind parameters padded.
|
||||
*/
|
||||
public boolean isPadInExpression() {
|
||||
return !multiValueSupported && isSimpleId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql for binding an id. This is the columns with table alias that
|
||||
* make up the id.
|
||||
@@ -2307,6 +2316,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return idBinder.convertSetId(idValue, bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id value to the bean (without type conversion).
|
||||
*/
|
||||
public void setId(Object idValue, EntityBean bean) {
|
||||
idProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty(String propName) {
|
||||
return findProperty(propName);
|
||||
@@ -3210,7 +3226,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
|
||||
boolean hasIdValue(EntityBean bean) {
|
||||
return (idProperty != null && !DmlUtil.isNullOrZero(idProperty.getValue(bean)));
|
||||
return (idProperty != null && !isNullOrZero(idProperty.getValue(bean)));
|
||||
}
|
||||
|
||||
boolean hasVersionProperty(EntityBeanIntercept ebi) {
|
||||
|
||||
@@ -675,25 +675,30 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
*/
|
||||
EntityBean loadBeanDirect(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
|
||||
|
||||
id = desc.convertId(id);
|
||||
EntityBean bean = null;
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
} else {
|
||||
bean = (EntityBean)desc.contextGet(context, id);
|
||||
}
|
||||
|
||||
if (bean == null) {
|
||||
bean = desc.createEntityBean();
|
||||
desc.setId(id, bean);
|
||||
desc.contextPut(context, id, bean);
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
// Not using loadContext here so no batch lazy loading for these beans
|
||||
ebi.setBeanLoader(desc.getEbeanServer());
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
ebi.setPersistenceContext(context);
|
||||
}
|
||||
|
||||
EntityBean bean = desc.createEntityBean();
|
||||
id = desc.convertSetId(id, bean);
|
||||
CachedBeanDataToBean.load(desc, bean, data, context);
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
|
||||
// Not using a loadContext for beans coming out of L2 cache
|
||||
// so that means no batch lazy loading for these beans
|
||||
ebi.setBeanLoader(desc.getEbeanServer());
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
ebi.setReadOnly(true);
|
||||
}
|
||||
ebi.setPersistenceContext(context);
|
||||
desc.contextPut(context, id, bean);
|
||||
|
||||
if (desc.isReadAuditing()) {
|
||||
desc.readAuditBean("l2", "", bean);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
|
||||
|
||||
class BeanDescriptorJsonHelp<T> {
|
||||
|
||||
private final BeanDescriptor<T> desc;
|
||||
@@ -158,7 +160,7 @@ class BeanDescriptorJsonHelp<T> {
|
||||
}
|
||||
Object contextBean = null;
|
||||
Object id = desc.beanId(bean);
|
||||
if (id != null) {
|
||||
if (!isNullOrZero(id)) {
|
||||
// check if the bean has already been loaded
|
||||
contextBean = readJson.persistenceContextPutIfAbsent(id, bean, desc);
|
||||
}
|
||||
|
||||
@@ -24,11 +24,9 @@ public class IdBinderFactory {
|
||||
* Create the IdConvertSet for the given type of Id properties.
|
||||
*/
|
||||
public IdBinder createIdBinder(BeanProperty id) {
|
||||
|
||||
if (id == null) {
|
||||
// for report type beans that don't need an id
|
||||
return EMPTY;
|
||||
|
||||
}
|
||||
if (id.isEmbedded()) {
|
||||
return new IdBinderEmbedded(idInExpandedForm, (BeanPropertyAssocOne<?>) id);
|
||||
|
||||
@@ -313,10 +313,17 @@ public class DeployCreateProperties {
|
||||
|
||||
Type[] typeArgs = ptype.getActualTypeArguments();
|
||||
if (typeArgs.length == 1) {
|
||||
// probably a Set or List
|
||||
// expecting set or list
|
||||
if (typeArgs[0] instanceof Class<?>) {
|
||||
return (Class<?>) typeArgs[0];
|
||||
}
|
||||
if (typeArgs[0] instanceof WildcardType) {
|
||||
final Type[] upperBounds = ((WildcardType) typeArgs[0]).getUpperBounds();
|
||||
if (upperBounds.length == 1 && upperBounds[0] instanceof Class<?>) {
|
||||
// kotlin generated wildcard type
|
||||
return (Class<?>) upperBounds[0];
|
||||
}
|
||||
}
|
||||
// throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
import io.ebeaninternal.api.SpiExpressionFactory;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.grammer.EqlParser;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -151,6 +152,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
|
||||
return new BitwiseExpression(propertyName, BitwiseOp.AND, flags, "=", match);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void where(ExpressionList<T> list, String expressions, Object[] params) {
|
||||
EqlParser.parseWhere(expressions, list, this, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
|
||||
@@ -470,8 +470,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> filterMany(String prop) {
|
||||
return query.filterMany(prop);
|
||||
public ExpressionList<T> filterMany(String manyProperty) {
|
||||
return query.filterMany(manyProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> filterMany(String manyProperty, String expressions, Object... params) {
|
||||
query.filterMany(manyProperty).where(expressions, params);
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -745,6 +751,12 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> where(String expressions, Object... params) {
|
||||
expr.where(this, expressions, params);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> bitwiseAny(String propertyName, long flags) {
|
||||
add(expr.bitwiseAny(propertyName, flags));
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.server.core.BindPadding;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.id.IdBinder;
|
||||
|
||||
@@ -46,6 +47,10 @@ public class IdInExpression extends NonPrepareExpression {
|
||||
@Override
|
||||
public void prepareExpression(BeanQueryRequest<?> request) {
|
||||
multiValueIdSupported = request.isMultiValueIdSupported();
|
||||
if (!multiValueIdSupported && !idCollection.isEmpty() && request.isPadInExpression()) {
|
||||
// pad out the ids for better hit ratio on DB query plans
|
||||
BindPadding.padIds(idCollection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -326,11 +326,21 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.exampleLike(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> where(String expressions, Object... params) {
|
||||
throw new IllegalStateException("where not allowed on Junction expression list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> filterMany(String prop) {
|
||||
throw new IllegalStateException("filterMany not allowed on Junction expression list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> filterMany(String manyProperty, String expressions, Object... params) {
|
||||
throw new IllegalStateException("filterMany not allowed on Junction expression list");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> usingTransaction(Transaction transaction) {
|
||||
return exprList.usingTransaction(transaction);
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.LikeType;
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLBaseListener;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLLexer;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLParser;
|
||||
import io.ebeaninternal.server.util.ArrayStack;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class EqlAdapter<T> extends EQLBaseListener {
|
||||
|
||||
private static final OperatorMapping operatorMapping = new OperatorMapping();
|
||||
class EqlAdapter<T> extends EqlWhereListener<T> {
|
||||
|
||||
private static final String DISTINCT = "distinct";
|
||||
|
||||
@@ -29,27 +19,33 @@ class EqlAdapter<T> extends EQLBaseListener {
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final EqlAdapterHelper helper;
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private ArrayStack<ExpressionList<T>> textStack;
|
||||
|
||||
private ArrayStack<ExpressionList<T>> whereStack;
|
||||
|
||||
private boolean textMode;
|
||||
|
||||
private List<Object> inValues;
|
||||
|
||||
private String inPropertyName;
|
||||
|
||||
public EqlAdapter(SpiQuery<T> query) {
|
||||
EqlAdapter(SpiQuery<T> query) {
|
||||
this.query = query;
|
||||
this.helper = new EqlAdapterHelper(this);
|
||||
this.expressionFactory = query.getExpressionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
ExpressionFactory expressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object namedParam(String parameterName) {
|
||||
return query.createNamedParameter(parameterName);
|
||||
}
|
||||
|
||||
@Override
|
||||
Object positionParam(String paramPosition) {
|
||||
return query.createNamedParameter(paramPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current expression list that expressions should be added to.
|
||||
*/
|
||||
protected ExpressionList<T> peekExprList() {
|
||||
@Override
|
||||
ExpressionList<T> peekExprList() {
|
||||
|
||||
if (textMode) {
|
||||
// return the current text expression list
|
||||
@@ -74,28 +70,6 @@ class EqlAdapter<T> extends EQLBaseListener {
|
||||
return textStack.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the expression list onto the appropriate stack.
|
||||
*/
|
||||
private void pushExprList(ExpressionList<T> list) {
|
||||
if (textMode) {
|
||||
textStack.push(list);
|
||||
} else {
|
||||
whereStack.push(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End a list of expressions added by 'OR'.
|
||||
*/
|
||||
private void popJunction() {
|
||||
if (textMode) {
|
||||
textStack.pop();
|
||||
} else {
|
||||
whereStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSelect_clause(EQLParser.Select_clauseContext ctx) {
|
||||
|
||||
@@ -199,233 +173,4 @@ class EqlAdapter<T> extends EQLBaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
private String getLeftHandSidePath(ParserRuleContext ctx) {
|
||||
TerminalNode pathToken = ctx.getToken(EQLLexer.PATH_VARIABLE, 0);
|
||||
return pathToken.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInrange_expression(EQLParser.Inrange_expressionContext ctx) {
|
||||
checkChildren(ctx, 5);
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.INRANGE) {
|
||||
throw new IllegalStateException("Expecting INRANGE operator but got " + op);
|
||||
}
|
||||
helper.addInRange(path, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterBetween_expression(EQLParser.Between_expressionContext ctx) {
|
||||
|
||||
checkChildren(ctx, 5);
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.BETWEEN) {
|
||||
throw new IllegalStateException("Expecting BETWEEN operator but got " + op);
|
||||
}
|
||||
helper.addBetween(path, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterPropertyBetween_expression(EQLParser.PropertyBetween_expressionContext ctx) {
|
||||
checkChildren(ctx, 5);
|
||||
String rawValue = child(ctx, 0);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.BETWEEN) {
|
||||
throw new IllegalStateException("Expecting BETWEEN operator but got " + op);
|
||||
}
|
||||
helper.addBetweenProperty(rawValue, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIn_expression(EQLParser.In_expressionContext ctx) {
|
||||
this.inValues = new ArrayList<>();
|
||||
this.inPropertyName = getLeftHandSidePath(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIn_value(EQLParser.In_valueContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
String text = child(ctx, i);
|
||||
if (isValue(text)) {
|
||||
inValues.add(helper.bind(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String child(ParserRuleContext ctx, int position) {
|
||||
ParseTree child = ctx.getChild(position);
|
||||
return child.getText();
|
||||
}
|
||||
|
||||
private boolean isValue(String text) {
|
||||
return text.length() != 1 || (!text.equals("(") && !text.equals(")") && !text.equals(","));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitIn_expression(EQLParser.In_expressionContext ctx) {
|
||||
helper.addIn(inPropertyName, inValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNull_expression(EQLParser.IsNull_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNotNull_expression(EQLParser.IsNotNull_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNotNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsEmpty_expression(EQLParser.IsEmpty_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isEmpty(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNotEmpty_expression(EQLParser.IsNotEmpty_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNotEmpty(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterLike_expression(EQLParser.Like_expressionContext ctx) {
|
||||
addExpression(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterComparison_expression(EQLParser.Comparison_expressionContext ctx) {
|
||||
addExpression(ctx);
|
||||
}
|
||||
|
||||
private void addExpression(ParserRuleContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
if (childCount < 3) {
|
||||
throw new IllegalStateException("expecting 3 children for comparison? " + ctx);
|
||||
}
|
||||
String operator = child(ctx, 1);
|
||||
EqlOperator op = operatorMapping.get(operator);
|
||||
if (op == null) {
|
||||
throw new IllegalStateException("No operator found for " + operator);
|
||||
}
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
String rhs = child(ctx, 2);
|
||||
if (path.equals(rhs)) {
|
||||
// the 'value operator path' form
|
||||
// invert the operator and use LHS as RHS
|
||||
op = invert(op);
|
||||
rhs = child(ctx, 0);
|
||||
}
|
||||
|
||||
// RHS is Path, Literal or Named input parameter
|
||||
helper.addExpression(path, op, rhs);
|
||||
}
|
||||
|
||||
private EqlOperator invert(EqlOperator op) {
|
||||
switch (op) {
|
||||
// no change
|
||||
case EQ:
|
||||
return EqlOperator.EQ;
|
||||
case IEQ:
|
||||
return EqlOperator.IEQ;
|
||||
case INE:
|
||||
return EqlOperator.INE;
|
||||
case NE:
|
||||
return EqlOperator.NE;
|
||||
// invert
|
||||
case LT:
|
||||
return EqlOperator.GT;
|
||||
case LTE:
|
||||
return EqlOperator.GTE;
|
||||
case GT:
|
||||
return EqlOperator.LT;
|
||||
case GTE:
|
||||
return EqlOperator.LTE;
|
||||
default:
|
||||
throw new IllegalStateException("Can not invert operator " + op);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enterConditional_term(EQLParser.Conditional_termContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
if (childCount > 1) {
|
||||
pushExprList(peekExprList().and());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_term(EQLParser.Conditional_termContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterConditional_expression(EQLParser.Conditional_expressionContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
pushExprList(peekExprList().or());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_expression(EQLParser.Conditional_expressionContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterConditional_factor(EQLParser.Conditional_factorContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
pushExprList(peekExprList().not());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_factor(EQLParser.Conditional_factorContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
private EqlOperator getOperator(ParserRuleContext ctx) {
|
||||
String operator = child(ctx, 1);
|
||||
EqlOperator op = operatorMapping.get(operator);
|
||||
if (op == null) {
|
||||
throw new IllegalStateException("No operator found for " + operator);
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for the minimum number of children.
|
||||
*/
|
||||
private void checkChildren(ParserRuleContext ctx, int min) {
|
||||
if (ctx.getChildCount() < min) {
|
||||
throw new IllegalStateException("expecting " + min + " children for comparison but got " + ctx.getChildCount());
|
||||
}
|
||||
}
|
||||
|
||||
public Object namedParam(String parameterName) {
|
||||
return query.createNamedParameter(parameterName);
|
||||
}
|
||||
|
||||
public Expression like(boolean caseInsensitive, LikeType likeType, String property, Object bindValue) {
|
||||
return query.getExpressionFactory().like(property, bindValue, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
public Expression ieq(String property, Object bindValue) {
|
||||
return query.getExpressionFactory().ieqObject(property, bindValue);
|
||||
}
|
||||
|
||||
public Expression ine(String property, Object bindValue) {
|
||||
return query.getExpressionFactory().ineObject(property, bindValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.LikeType;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
class EqlAdapterHelper {
|
||||
|
||||
private final EqlAdapter<?> owner;
|
||||
|
||||
public EqlAdapterHelper(EqlAdapter<?> owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
enum ValueType {
|
||||
NAMED_PARAM,
|
||||
STRING,
|
||||
BOOL,
|
||||
NUMBER
|
||||
}
|
||||
|
||||
private ValueType getValueType(String valueAsText) {
|
||||
|
||||
char firstChar = Character.toLowerCase(valueAsText.charAt(0));
|
||||
switch (firstChar) {
|
||||
case ':':
|
||||
return ValueType.NAMED_PARAM;
|
||||
case 't':
|
||||
return ValueType.BOOL;
|
||||
case 'f':
|
||||
return ValueType.BOOL;
|
||||
case '\'':
|
||||
return ValueType.STRING;
|
||||
default:
|
||||
if (Character.isDigit(firstChar)) {
|
||||
return ValueType.NUMBER;
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected first character in value [" + valueAsText + "]");
|
||||
}
|
||||
}
|
||||
|
||||
protected void addBetweenProperty(String rawValue, String lowProperty, String highProperty) {
|
||||
peekExprList().betweenProperties(lowProperty, highProperty, bind(rawValue));
|
||||
}
|
||||
|
||||
protected void addBetween(String path, String value1, String value2) {
|
||||
peekExprList().between(path, bind(value1), bind(value2));
|
||||
}
|
||||
|
||||
protected void addInRange(String path, String value1, String value2) {
|
||||
peekExprList().inRange(path, bind(value1), bind(value2));
|
||||
}
|
||||
|
||||
protected void addIn(String path, List<Object> inValues) {
|
||||
peekExprList().in(path, inValues);
|
||||
}
|
||||
|
||||
protected void addExpression(String path, EqlOperator op, String value) {
|
||||
|
||||
switch (op) {
|
||||
case EQ:
|
||||
peekExprList().eq(path, bind(value));
|
||||
break;
|
||||
case IEQ:
|
||||
peekExprList().add(owner.ieq(path, bind(value)));
|
||||
break;
|
||||
case NE:
|
||||
peekExprList().ne(path, bind(value));
|
||||
break;
|
||||
case INE:
|
||||
peekExprList().add(owner.ine(path, bind(value)));
|
||||
break;
|
||||
case GT:
|
||||
peekExprList().gt(path, bind(value));
|
||||
break;
|
||||
case LT:
|
||||
peekExprList().lt(path, bind(value));
|
||||
break;
|
||||
case GTE:
|
||||
peekExprList().ge(path, bind(value));
|
||||
break;
|
||||
case LTE:
|
||||
peekExprList().le(path, bind(value));
|
||||
break;
|
||||
case LIKE:
|
||||
addLike(false, LikeType.RAW, path, bind(value));
|
||||
break;
|
||||
case CONTAINS:
|
||||
addLike(false, LikeType.CONTAINS, path, bind(value));
|
||||
break;
|
||||
case STARTS_WITH:
|
||||
addLike(false, LikeType.STARTS_WITH, path, bind(value));
|
||||
break;
|
||||
case ENDS_WITH:
|
||||
addLike(false, LikeType.ENDS_WITH, path, bind(value));
|
||||
break;
|
||||
case ILIKE:
|
||||
addLike(true, LikeType.RAW, path, bind(value));
|
||||
break;
|
||||
case ICONTAINS:
|
||||
addLike(true, LikeType.CONTAINS, path, bind(value));
|
||||
break;
|
||||
case ISTARTS_WITH:
|
||||
addLike(true, LikeType.STARTS_WITH, path, bind(value));
|
||||
break;
|
||||
case IENDS_WITH:
|
||||
addLike(true, LikeType.ENDS_WITH, path, bind(value));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unhandled operator " + op);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addLike(boolean caseInsensitive, LikeType likeType, String path, Object bindValue) {
|
||||
peekExprList().add(owner.like(caseInsensitive, likeType, path, bindValue));
|
||||
}
|
||||
|
||||
protected Object bind(String value) {
|
||||
ValueType valueType = getValueType(value);
|
||||
return getBindValue(valueType, value);
|
||||
}
|
||||
|
||||
private ExpressionList<?> peekExprList() {
|
||||
return owner.peekExprList();
|
||||
}
|
||||
|
||||
private Object getBindValue(ValueType valueType, String value) {
|
||||
switch (valueType) {
|
||||
case BOOL:
|
||||
return Boolean.parseBoolean(value);
|
||||
case NUMBER:
|
||||
return new BigDecimal(value);
|
||||
case STRING:
|
||||
return unquote(value);
|
||||
case NAMED_PARAM:
|
||||
return owner.namedParam(value.substring(1));
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled valueType " + valueType);
|
||||
}
|
||||
}
|
||||
|
||||
private String unquote(String value) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ enum EqlOperator {
|
||||
LTE,
|
||||
GT,
|
||||
GTE,
|
||||
EQORNULL,
|
||||
LTORNULL,
|
||||
GTORNULL,
|
||||
CONTAINS,
|
||||
STARTS_WITH,
|
||||
ENDS_WITH,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLLexer;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLParser;
|
||||
@@ -22,20 +24,21 @@ public class EqlParser {
|
||||
*/
|
||||
public static <T> void parse(String raw, SpiQuery<T> query) {
|
||||
|
||||
EQLLexer lexer = new EQLLexer(CharStreams.fromString(raw));
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
EQLParser parser = new EQLParser(tokens);
|
||||
EQLParser parser = new EQLParser(new CommonTokenStream(new EQLLexer(CharStreams.fromString(raw))));
|
||||
parser.addErrorListener(errorListener);
|
||||
EQLParser.Select_statementContext context = parser.select_statement();
|
||||
|
||||
EqlAdapter<T> adapter = new EqlAdapter<>(query);
|
||||
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
walker.walk(adapter, context);
|
||||
|
||||
new ParseTreeWalker().walk(new EqlAdapter<>(query), parser.select_statement());
|
||||
query.simplifyExpressions();
|
||||
}
|
||||
|
||||
public static <T> void parseWhere(String raw, ExpressionList<T> where, ExpressionFactory expr, Object[] params) {
|
||||
|
||||
EQLParser parser = new EQLParser(new CommonTokenStream(new EQLLexer(CharStreams.fromString(raw))));
|
||||
parser.addErrorListener(errorListener);
|
||||
|
||||
new ParseTreeWalker().walk(new EqlWhereAdapter<>(where, expr, params), parser.conditional_expression());
|
||||
}
|
||||
|
||||
static class ErrorListener extends BaseErrorListener {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
enum EqlValueType {
|
||||
POS_PARAM,
|
||||
NAMED_PARAM,
|
||||
STRING,
|
||||
BOOL,
|
||||
NUMBER
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebeaninternal.server.util.ArrayStack;
|
||||
|
||||
class EqlWhereAdapter<T> extends EqlWhereListener<T> {
|
||||
|
||||
private final ExpressionList<T> where;
|
||||
private final ExpressionFactory expr;
|
||||
private final Object[] params;
|
||||
|
||||
private int paramIndex;
|
||||
|
||||
EqlWhereAdapter(ExpressionList<T> where, ExpressionFactory expr, Object[] params) {
|
||||
this.where = where;
|
||||
this.expr = expr;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
ExpressionList<T> peekExprList() {
|
||||
if (whereStack == null) {
|
||||
whereStack = new ArrayStack<>();
|
||||
whereStack.push(where);
|
||||
}
|
||||
return whereStack.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
ExpressionFactory expressionFactory() {
|
||||
return expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object positionParam(String paramPosition) {
|
||||
if ("?".equals(paramPosition)) {
|
||||
return params[paramIndex++];
|
||||
}
|
||||
final int pos = Integer.parseInt(paramPosition.substring(1));
|
||||
return params[pos -1];
|
||||
}
|
||||
|
||||
@Override
|
||||
Object namedParam(String substring) {
|
||||
throw new RuntimeException("Not supported");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
package io.ebeaninternal.server.grammer;
|
||||
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.LikeType;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLBaseListener;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLLexer;
|
||||
import io.ebeaninternal.server.grammer.antlr.EQLParser;
|
||||
import io.ebeaninternal.server.util.ArrayStack;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class EqlWhereListener<T> extends EQLBaseListener {
|
||||
|
||||
private static final OperatorMapping operatorMapping = new OperatorMapping();
|
||||
|
||||
ArrayStack<ExpressionList<T>> textStack;
|
||||
|
||||
ArrayStack<ExpressionList<T>> whereStack;
|
||||
|
||||
boolean textMode;
|
||||
|
||||
private boolean inWithEmpty;
|
||||
|
||||
private List<Object> inValues;
|
||||
|
||||
private String inPropertyName;
|
||||
|
||||
/**
|
||||
* Return the current expression list that expressions should be added to.
|
||||
*/
|
||||
abstract ExpressionList<T> peekExprList();
|
||||
|
||||
abstract ExpressionFactory expressionFactory();
|
||||
|
||||
abstract Object namedParam(String paramName);
|
||||
|
||||
abstract Object positionParam(String paramPosition);
|
||||
|
||||
/**
|
||||
* Push the expression list onto the appropriate stack.
|
||||
*/
|
||||
private void pushExprList(ExpressionList<T> list) {
|
||||
if (textMode) {
|
||||
textStack.push(list);
|
||||
} else {
|
||||
whereStack.push(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End a list of expressions added by 'OR'.
|
||||
*/
|
||||
private void popJunction() {
|
||||
if (textMode) {
|
||||
textStack.pop();
|
||||
} else {
|
||||
whereStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private String getLeftHandSidePath(ParserRuleContext ctx) {
|
||||
TerminalNode pathToken = ctx.getToken(EQLLexer.PATH_VARIABLE, 0);
|
||||
return pathToken.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInrange_expression(EQLParser.Inrange_expressionContext ctx) {
|
||||
checkChildren(ctx, 5);
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.INRANGE) {
|
||||
throw new IllegalStateException("Expecting INRANGE operator but got " + op);
|
||||
}
|
||||
addInRange(path, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterBetween_expression(EQLParser.Between_expressionContext ctx) {
|
||||
|
||||
checkChildren(ctx, 5);
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.BETWEEN) {
|
||||
throw new IllegalStateException("Expecting BETWEEN operator but got " + op);
|
||||
}
|
||||
addBetween(path, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterPropertyBetween_expression(EQLParser.PropertyBetween_expressionContext ctx) {
|
||||
checkChildren(ctx, 5);
|
||||
String rawValue = child(ctx, 0);
|
||||
EqlOperator op = getOperator(ctx);
|
||||
if (op != EqlOperator.BETWEEN) {
|
||||
throw new IllegalStateException("Expecting BETWEEN operator but got " + op);
|
||||
}
|
||||
addBetweenProperty(rawValue, child(ctx, 2), child(ctx, 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx) {
|
||||
this.inWithEmpty = true;
|
||||
this.inValues = new ArrayList<>();
|
||||
this.inPropertyName = getLeftHandSidePath(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIn_expression(EQLParser.In_expressionContext ctx) {
|
||||
this.inValues = new ArrayList<>();
|
||||
this.inPropertyName = getLeftHandSidePath(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIn_value(EQLParser.In_valueContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
String text = child(ctx, i);
|
||||
if (text.startsWith("?")) {
|
||||
inValues = toList(getBindValue(EqlValueType.POS_PARAM, text));
|
||||
} else {
|
||||
if (inWithEmpty) {
|
||||
throw new IllegalArgumentException("Sorry, can only use inOrEmpty with positioned parameters");
|
||||
}
|
||||
if (isValue(text)) {
|
||||
inValues.add(bind(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Object> toList(Object value) {
|
||||
if (value == null) return null;
|
||||
if (value instanceof List) {
|
||||
return (List<Object>)value;
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
return new ArrayList<>((Set)value);
|
||||
}
|
||||
throw new IllegalArgumentException("Expected List of Set but got " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitIn_expression(EQLParser.In_expressionContext ctx) {
|
||||
peekExprList().in(inPropertyName, inValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx) {
|
||||
inWithEmpty = false;
|
||||
peekExprList().inOrEmpty(inPropertyName, inValues);
|
||||
}
|
||||
|
||||
String child(ParserRuleContext ctx, int position) {
|
||||
ParseTree child = ctx.getChild(position);
|
||||
return child.getText();
|
||||
}
|
||||
|
||||
private boolean isValue(String text) {
|
||||
return text.length() != 1 || (!text.equals("(") && !text.equals(")") && !text.equals(","));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNull_expression(EQLParser.IsNull_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNotNull_expression(EQLParser.IsNotNull_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNotNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsEmpty_expression(EQLParser.IsEmpty_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isEmpty(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterIsNotEmpty_expression(EQLParser.IsNotEmpty_expressionContext ctx) {
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
peekExprList().isNotEmpty(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterLike_expression(EQLParser.Like_expressionContext ctx) {
|
||||
addExpression(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterComparison_expression(EQLParser.Comparison_expressionContext ctx) {
|
||||
addExpression(ctx);
|
||||
}
|
||||
|
||||
private void addExpression(ParserRuleContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
if (childCount < 3) {
|
||||
throw new IllegalStateException("expecting 3 children for comparison? " + ctx);
|
||||
}
|
||||
String operator = child(ctx, 1);
|
||||
EqlOperator op = operatorMapping.get(operator);
|
||||
if (op == null) {
|
||||
throw new IllegalStateException("No operator found for " + operator);
|
||||
}
|
||||
String path = getLeftHandSidePath(ctx);
|
||||
String rhs = child(ctx, 2);
|
||||
if (path.equals(rhs)) {
|
||||
// the 'value operator path' form
|
||||
// invert the operator and use LHS as RHS
|
||||
op = invert(op);
|
||||
rhs = child(ctx, 0);
|
||||
}
|
||||
|
||||
// RHS is Path, Literal or Named input parameter
|
||||
addExpression(path, op, rhs);
|
||||
}
|
||||
|
||||
private EqlOperator invert(EqlOperator op) {
|
||||
switch (op) {
|
||||
// no change
|
||||
case EQ:
|
||||
return EqlOperator.EQ;
|
||||
case IEQ:
|
||||
return EqlOperator.IEQ;
|
||||
case INE:
|
||||
return EqlOperator.INE;
|
||||
case NE:
|
||||
return EqlOperator.NE;
|
||||
// invert
|
||||
case LT:
|
||||
return EqlOperator.GT;
|
||||
case LTE:
|
||||
return EqlOperator.GTE;
|
||||
case GT:
|
||||
return EqlOperator.LT;
|
||||
case GTE:
|
||||
return EqlOperator.LTE;
|
||||
case EQORNULL:
|
||||
return EqlOperator.EQORNULL;
|
||||
case GTORNULL:
|
||||
return EqlOperator.LTORNULL;
|
||||
case LTORNULL:
|
||||
return EqlOperator.GTORNULL;
|
||||
default:
|
||||
throw new IllegalStateException("Can not invert operator " + op);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterConditional_term(EQLParser.Conditional_termContext ctx) {
|
||||
int childCount = ctx.getChildCount();
|
||||
if (childCount > 1) {
|
||||
pushExprList(peekExprList().and());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_term(EQLParser.Conditional_termContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterConditional_expression(EQLParser.Conditional_expressionContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
pushExprList(peekExprList().or());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_expression(EQLParser.Conditional_expressionContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterConditional_factor(EQLParser.Conditional_factorContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
pushExprList(peekExprList().not());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitConditional_factor(EQLParser.Conditional_factorContext ctx) {
|
||||
if (ctx.getChildCount() > 1) {
|
||||
popJunction();
|
||||
}
|
||||
}
|
||||
|
||||
private EqlOperator getOperator(ParserRuleContext ctx) {
|
||||
String operator = child(ctx, 1);
|
||||
EqlOperator op = operatorMapping.get(operator);
|
||||
if (op == null) {
|
||||
throw new IllegalStateException("No operator found for " + operator);
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for the minimum number of children.
|
||||
*/
|
||||
void checkChildren(ParserRuleContext ctx, int min) {
|
||||
if (ctx.getChildCount() < min) {
|
||||
throw new IllegalStateException("expecting " + min + " children for comparison but got " + ctx.getChildCount());
|
||||
}
|
||||
}
|
||||
|
||||
private Expression like(boolean caseInsensitive, LikeType likeType, String property, Object bindValue) {
|
||||
return expressionFactory().like(property, bindValue, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
private Expression ieq(String property, Object bindValue) {
|
||||
return expressionFactory().ieqObject(property, bindValue);
|
||||
}
|
||||
|
||||
private Expression ine(String property, Object bindValue) {
|
||||
return expressionFactory().ineObject(property, bindValue);
|
||||
}
|
||||
|
||||
private EqlValueType getValueType(String valueAsText) {
|
||||
|
||||
char firstChar = Character.toLowerCase(valueAsText.charAt(0));
|
||||
switch (firstChar) {
|
||||
case '?':
|
||||
return EqlValueType.POS_PARAM;
|
||||
case ':':
|
||||
return EqlValueType.NAMED_PARAM;
|
||||
case 't':
|
||||
return EqlValueType.BOOL;
|
||||
case 'f':
|
||||
return EqlValueType.BOOL;
|
||||
case '\'':
|
||||
return EqlValueType.STRING;
|
||||
default:
|
||||
if (Character.isDigit(firstChar)) {
|
||||
return EqlValueType.NUMBER;
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected first character in value [" + valueAsText + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private void addBetweenProperty(String rawValue, String lowProperty, String highProperty) {
|
||||
peekExprList().betweenProperties(lowProperty, highProperty, bind(rawValue));
|
||||
}
|
||||
|
||||
private void addBetween(String path, String value1, String value2) {
|
||||
peekExprList().between(path, bind(value1), bind(value2));
|
||||
}
|
||||
|
||||
private void addInRange(String path, String value1, String value2) {
|
||||
peekExprList().inRange(path, bind(value1), bind(value2));
|
||||
}
|
||||
|
||||
private void addExpression(String path, EqlOperator op, String value) {
|
||||
switch (op) {
|
||||
case EQ:
|
||||
peekExprList().eq(path, bind(value));
|
||||
break;
|
||||
case IEQ:
|
||||
peekExprList().add(ieq(path, bind(value)));
|
||||
break;
|
||||
case NE:
|
||||
peekExprList().ne(path, bind(value));
|
||||
break;
|
||||
case INE:
|
||||
peekExprList().add(ine(path, bind(value)));
|
||||
break;
|
||||
case GT:
|
||||
peekExprList().gt(path, bind(value));
|
||||
break;
|
||||
case LT:
|
||||
peekExprList().lt(path, bind(value));
|
||||
break;
|
||||
case GTE:
|
||||
peekExprList().ge(path, bind(value));
|
||||
break;
|
||||
case LTE:
|
||||
peekExprList().le(path, bind(value));
|
||||
break;
|
||||
case LIKE:
|
||||
addLike(false, LikeType.RAW, path, bind(value));
|
||||
break;
|
||||
case CONTAINS:
|
||||
addLike(false, LikeType.CONTAINS, path, bind(value));
|
||||
break;
|
||||
case STARTS_WITH:
|
||||
addLike(false, LikeType.STARTS_WITH, path, bind(value));
|
||||
break;
|
||||
case ENDS_WITH:
|
||||
addLike(false, LikeType.ENDS_WITH, path, bind(value));
|
||||
break;
|
||||
case ILIKE:
|
||||
addLike(true, LikeType.RAW, path, bind(value));
|
||||
break;
|
||||
case ICONTAINS:
|
||||
addLike(true, LikeType.CONTAINS, path, bind(value));
|
||||
break;
|
||||
case ISTARTS_WITH:
|
||||
addLike(true, LikeType.STARTS_WITH, path, bind(value));
|
||||
break;
|
||||
case IENDS_WITH:
|
||||
addLike(true, LikeType.ENDS_WITH, path, bind(value));
|
||||
break;
|
||||
case EQORNULL:
|
||||
peekExprList().eqOrNull(path, bind(value));
|
||||
break;
|
||||
case GTORNULL:
|
||||
peekExprList().gtOrNull(path, bind(value));
|
||||
break;
|
||||
case LTORNULL:
|
||||
peekExprList().ltOrNull(path, bind(value));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unhandled operator " + op);
|
||||
}
|
||||
}
|
||||
|
||||
private void addLike(boolean caseInsensitive, LikeType likeType, String path, Object bindValue) {
|
||||
peekExprList().add(like(caseInsensitive, likeType, path, bindValue));
|
||||
}
|
||||
|
||||
private Object bind(String value) {
|
||||
return getBindValue(getValueType(value), value);
|
||||
}
|
||||
|
||||
private Object getBindValue(EqlValueType valueType, String value) {
|
||||
switch (valueType) {
|
||||
case BOOL:
|
||||
return Boolean.parseBoolean(value);
|
||||
case NUMBER:
|
||||
return new BigDecimal(value);
|
||||
case STRING:
|
||||
return unquote(value);
|
||||
case POS_PARAM:
|
||||
return positionParam(value);
|
||||
case NAMED_PARAM:
|
||||
return namedParam(value.substring(1));
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled valueType " + valueType);
|
||||
}
|
||||
}
|
||||
|
||||
private String unquote(String value) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import java.util.Map;
|
||||
|
||||
class OperatorMapping {
|
||||
|
||||
final Map<String, EqlOperator> map = new HashMap<>();
|
||||
private final Map<String, EqlOperator> map = new HashMap<>();
|
||||
|
||||
public OperatorMapping() {
|
||||
OperatorMapping() {
|
||||
map.put("eq", EqlOperator.EQ);
|
||||
map.put("=", EqlOperator.EQ);
|
||||
map.put("ieq", EqlOperator.IEQ);
|
||||
@@ -42,7 +42,11 @@ class OperatorMapping {
|
||||
map.put("ilike", EqlOperator.ILIKE);
|
||||
|
||||
map.put("inrange", EqlOperator.INRANGE);
|
||||
map.put("inRange", EqlOperator.INRANGE);
|
||||
map.put("between", EqlOperator.BETWEEN);
|
||||
map.put("eqOrNull", EqlOperator.EQORNULL);
|
||||
map.put("gtOrNull", EqlOperator.GTORNULL);
|
||||
map.put("ltOrNull", EqlOperator.LTORNULL);
|
||||
}
|
||||
|
||||
public EqlOperator get(String key) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -58,17 +58,22 @@ T__56=57
|
||||
T__57=58
|
||||
T__58=59
|
||||
T__59=60
|
||||
INPUT_VARIABLE=61
|
||||
PATH_VARIABLE=62
|
||||
QUOTED_PATH_VARIABLE=63
|
||||
PROP_FORMULA=64
|
||||
BOOLEAN_LITERAL=65
|
||||
NUMBER_LITERAL=66
|
||||
DOUBLE=67
|
||||
INT=68
|
||||
ZERO=69
|
||||
STRING_LITERAL=70
|
||||
WS=71
|
||||
T__60=61
|
||||
T__61=62
|
||||
T__62=63
|
||||
T__63=64
|
||||
T__64=65
|
||||
INPUT_VARIABLE=66
|
||||
PATH_VARIABLE=67
|
||||
QUOTED_PATH_VARIABLE=68
|
||||
PROP_FORMULA=69
|
||||
BOOLEAN_LITERAL=70
|
||||
NUMBER_LITERAL=71
|
||||
DOUBLE=72
|
||||
INT=73
|
||||
ZERO=74
|
||||
STRING_LITERAL=75
|
||||
WS=76
|
||||
'('=1
|
||||
')'=2
|
||||
'select'=3
|
||||
@@ -91,42 +96,47 @@ WS=71
|
||||
'or'=20
|
||||
'and'=21
|
||||
'not'=22
|
||||
'in'=23
|
||||
'between'=24
|
||||
'inrange'=25
|
||||
'inOrEmpty'=23
|
||||
'in'=24
|
||||
'between'=25
|
||||
'to'=26
|
||||
'is'=27
|
||||
'null'=28
|
||||
'isNull'=29
|
||||
'isNotNull'=30
|
||||
'notNull'=31
|
||||
'empty'=32
|
||||
'isEmpty'=33
|
||||
'isNotEmpty'=34
|
||||
'notEmpty'=35
|
||||
'like'=36
|
||||
'ilike'=37
|
||||
'contains'=38
|
||||
'icontains'=39
|
||||
'startsWith'=40
|
||||
'istartsWith'=41
|
||||
'endsWith'=42
|
||||
'iendsWith'=43
|
||||
'='=44
|
||||
'eq'=45
|
||||
'>'=46
|
||||
'gt'=47
|
||||
'>='=48
|
||||
'ge'=49
|
||||
'gte'=50
|
||||
'<'=51
|
||||
'lt'=52
|
||||
'<='=53
|
||||
'le'=54
|
||||
'lte'=55
|
||||
'<>'=56
|
||||
'!='=57
|
||||
'ne'=58
|
||||
'ieq'=59
|
||||
'ine'=60
|
||||
'0'=69
|
||||
'inrange'=27
|
||||
'inRange'=28
|
||||
'is'=29
|
||||
'null'=30
|
||||
'isNull'=31
|
||||
'isNotNull'=32
|
||||
'notNull'=33
|
||||
'empty'=34
|
||||
'isEmpty'=35
|
||||
'isNotEmpty'=36
|
||||
'notEmpty'=37
|
||||
'like'=38
|
||||
'ilike'=39
|
||||
'contains'=40
|
||||
'icontains'=41
|
||||
'startsWith'=42
|
||||
'istartsWith'=43
|
||||
'endsWith'=44
|
||||
'iendsWith'=45
|
||||
'='=46
|
||||
'eq'=47
|
||||
'>'=48
|
||||
'gt'=49
|
||||
'>='=50
|
||||
'ge'=51
|
||||
'gte'=52
|
||||
'<'=53
|
||||
'lt'=54
|
||||
'<='=55
|
||||
'le'=56
|
||||
'lte'=57
|
||||
'<>'=58
|
||||
'!='=59
|
||||
'ne'=60
|
||||
'ieq'=61
|
||||
'ine'=62
|
||||
'eqOrNull'=63
|
||||
'gtOrNull'=64
|
||||
'ltOrNull'=65
|
||||
'0'=74
|
||||
|
||||
@@ -347,6 +347,18 @@ public class EQLBaseListener implements EQLListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitAny_expression(EQLParser.Any_expressionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@@ -395,6 +407,18 @@ public class EQLBaseListener implements EQLListener {
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitInrange_expression(EQLParser.Inrange_expressionContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void enterInrange_op(EQLParser.Inrange_opContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation does nothing.</p>
|
||||
*/
|
||||
@Override public void exitInrange_op(EQLParser.Inrange_opContext ctx) { }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,9 +28,9 @@ public class EQLLexer extends Lexer {
|
||||
T__38=39, T__39=40, T__40=41, T__41=42, T__42=43, T__43=44, T__44=45,
|
||||
T__45=46, T__46=47, T__47=48, T__48=49, T__49=50, T__50=51, T__51=52,
|
||||
T__52=53, T__53=54, T__54=55, T__55=56, T__56=57, T__57=58, T__58=59,
|
||||
T__59=60, INPUT_VARIABLE=61, PATH_VARIABLE=62, QUOTED_PATH_VARIABLE=63,
|
||||
PROP_FORMULA=64, BOOLEAN_LITERAL=65, NUMBER_LITERAL=66, DOUBLE=67, INT=68,
|
||||
ZERO=69, STRING_LITERAL=70, WS=71;
|
||||
T__59=60, T__60=61, T__61=62, T__62=63, T__63=64, T__64=65, INPUT_VARIABLE=66,
|
||||
PATH_VARIABLE=67, QUOTED_PATH_VARIABLE=68, PROP_FORMULA=69, BOOLEAN_LITERAL=70,
|
||||
NUMBER_LITERAL=71, DOUBLE=72, INT=73, ZERO=74, STRING_LITERAL=75, WS=76;
|
||||
public static String[] channelNames = {
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
|
||||
};
|
||||
@@ -48,9 +48,10 @@ public class EQLLexer extends Lexer {
|
||||
"T__33", "T__34", "T__35", "T__36", "T__37", "T__38", "T__39", "T__40",
|
||||
"T__41", "T__42", "T__43", "T__44", "T__45", "T__46", "T__47", "T__48",
|
||||
"T__49", "T__50", "T__51", "T__52", "T__53", "T__54", "T__55", "T__56",
|
||||
"T__57", "T__58", "T__59", "INPUT_VARIABLE", "PATH_VARIABLE", "QUOTED_PATH_VARIABLE",
|
||||
"PROP_FORMULA", "BOOLEAN_LITERAL", "NUMBER_LITERAL", "DOUBLE", "INT",
|
||||
"ZERO", "STRING_LITERAL", "WS"
|
||||
"T__57", "T__58", "T__59", "T__60", "T__61", "T__62", "T__63", "T__64",
|
||||
"INPUT_VARIABLE", "PATH_VARIABLE", "QUOTED_PATH_VARIABLE", "PROP_FORMULA",
|
||||
"BOOLEAN_LITERAL", "NUMBER_LITERAL", "DOUBLE", "INT", "ZERO", "STRING_LITERAL",
|
||||
"WS"
|
||||
};
|
||||
}
|
||||
public static final String[] ruleNames = makeRuleNames();
|
||||
@@ -60,12 +61,14 @@ public class EQLLexer extends Lexer {
|
||||
null, "'('", "')'", "'select'", "'distinct'", "'where'", "'order'", "'by'",
|
||||
"','", "'nulls'", "'first'", "'last'", "'asc'", "'desc'", "'limit'",
|
||||
"'offset'", "'fetch'", "'+'", "'query'", "'lazy'", "'or'", "'and'", "'not'",
|
||||
"'in'", "'between'", "'inrange'", "'to'", "'is'", "'null'", "'isNull'",
|
||||
"'isNotNull'", "'notNull'", "'empty'", "'isEmpty'", "'isNotEmpty'", "'notEmpty'",
|
||||
"'like'", "'ilike'", "'contains'", "'icontains'", "'startsWith'", "'istartsWith'",
|
||||
"'endsWith'", "'iendsWith'", "'='", "'eq'", "'>'", "'gt'", "'>='", "'ge'",
|
||||
"'gte'", "'<'", "'lt'", "'<='", "'le'", "'lte'", "'<>'", "'!='", "'ne'",
|
||||
"'ieq'", "'ine'", null, null, null, null, null, null, null, null, "'0'"
|
||||
"'inOrEmpty'", "'in'", "'between'", "'to'", "'inrange'", "'inRange'",
|
||||
"'is'", "'null'", "'isNull'", "'isNotNull'", "'notNull'", "'empty'",
|
||||
"'isEmpty'", "'isNotEmpty'", "'notEmpty'", "'like'", "'ilike'", "'contains'",
|
||||
"'icontains'", "'startsWith'", "'istartsWith'", "'endsWith'", "'iendsWith'",
|
||||
"'='", "'eq'", "'>'", "'gt'", "'>='", "'ge'", "'gte'", "'<'", "'lt'",
|
||||
"'<='", "'le'", "'lte'", "'<>'", "'!='", "'ne'", "'ieq'", "'ine'", "'eqOrNull'",
|
||||
"'gtOrNull'", "'ltOrNull'", null, null, null, null, null, null, null,
|
||||
null, "'0'"
|
||||
};
|
||||
}
|
||||
private static final String[] _LITERAL_NAMES = makeLiteralNames();
|
||||
@@ -76,9 +79,9 @@ public class EQLLexer extends Lexer {
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, "INPUT_VARIABLE", "PATH_VARIABLE", "QUOTED_PATH_VARIABLE", "PROP_FORMULA",
|
||||
"BOOLEAN_LITERAL", "NUMBER_LITERAL", "DOUBLE", "INT", "ZERO", "STRING_LITERAL",
|
||||
"WS"
|
||||
null, null, null, null, null, null, "INPUT_VARIABLE", "PATH_VARIABLE",
|
||||
"QUOTED_PATH_VARIABLE", "PROP_FORMULA", "BOOLEAN_LITERAL", "NUMBER_LITERAL",
|
||||
"DOUBLE", "INT", "ZERO", "STRING_LITERAL", "WS"
|
||||
};
|
||||
}
|
||||
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
|
||||
@@ -140,7 +143,7 @@ public class EQLLexer extends Lexer {
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
public static final String _serializedATN =
|
||||
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2I\u0249\b\1\4\2\t"+
|
||||
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2N\u0289\b\1\4\2\t"+
|
||||
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
|
||||
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
|
||||
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
|
||||
@@ -148,188 +151,211 @@ public class EQLLexer extends Lexer {
|
||||
"\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+
|
||||
",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+
|
||||
"\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+
|
||||
"\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\3\2"+
|
||||
"\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3"+
|
||||
"\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\t"+
|
||||
"\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f"+
|
||||
"\3\f\3\f\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17"+
|
||||
"\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21"+
|
||||
"\3\21\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24"+
|
||||
"\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\30\3\30\3\30"+
|
||||
"\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32"+
|
||||
"\3\32\3\32\3\33\3\33\3\33\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36"+
|
||||
"\3\36\3\36\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37"+
|
||||
"\3\37\3\37\3 \3 \3 \3 \3 \3 \3 \3 \3!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3"+
|
||||
"\"\3\"\3\"\3\"\3#\3#\3#\3#\3#\3#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\3$\3"+
|
||||
"$\3$\3%\3%\3%\3%\3%\3&\3&\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\3\'\3\'\3\'"+
|
||||
"\3\'\3(\3(\3(\3(\3(\3(\3(\3(\3(\3(\3)\3)\3)\3)\3)\3)\3)\3)\3)\3)\3)\3"+
|
||||
"*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3+\3+\3,\3,\3"+
|
||||
",\3,\3,\3,\3,\3,\3,\3,\3-\3-\3.\3.\3.\3/\3/\3\60\3\60\3\60\3\61\3\61\3"+
|
||||
"\61\3\62\3\62\3\62\3\63\3\63\3\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3"+
|
||||
"\66\3\66\3\67\3\67\3\67\38\38\38\38\39\39\39\3:\3:\3:\3;\3;\3;\3<\3<\3"+
|
||||
"<\3<\3=\3=\3=\3=\3>\3>\3>\7>\u01d4\n>\f>\16>\u01d7\13>\3?\3?\7?\u01db"+
|
||||
"\n?\f?\16?\u01de\13?\3@\3@\3@\3@\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3"+
|
||||
"A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3A\3"+
|
||||
"A\3A\3A\3A\3A\3A\3A\5A\u020e\nA\3B\3B\3B\3B\3B\3B\3B\3B\3B\5B\u0219\n"+
|
||||
"B\3C\5C\u021c\nC\3C\3C\5C\u0220\nC\3C\3C\5C\u0224\nC\3D\6D\u0227\nD\r"+
|
||||
"D\16D\u0228\3D\3D\7D\u022d\nD\fD\16D\u0230\13D\3E\3E\7E\u0234\nE\fE\16"+
|
||||
"E\u0237\13E\3F\3F\3G\3G\3G\3G\7G\u023f\nG\fG\16G\u0242\13G\3G\3G\3H\3"+
|
||||
"H\3H\3H\2\2I\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16"+
|
||||
"\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+
|
||||
"\tI\4J\tJ\4K\tK\4L\tL\4M\tM\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3"+
|
||||
"\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7"+
|
||||
"\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13"+
|
||||
"\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\16\3\16\3\16"+
|
||||
"\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\20"+
|
||||
"\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\23\3\23\3\23\3\23\3\23"+
|
||||
"\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\27"+
|
||||
"\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\31"+
|
||||
"\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\34"+
|
||||
"\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35"+
|
||||
"\3\35\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \3 \3 \3!"+
|
||||
"\3!\3!\3!\3!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#\3#\3"+
|
||||
"#\3#\3#\3$\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3%\3&\3"+
|
||||
"&\3&\3&\3&\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3(\3(\3)\3)\3)"+
|
||||
"\3)\3)\3)\3)\3)\3)\3*\3*\3*\3*\3*\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+"+
|
||||
"\3+\3+\3+\3+\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3-\3-\3-\3-\3-\3-\3-"+
|
||||
"\3-\3-\3.\3.\3.\3.\3.\3.\3.\3.\3.\3.\3/\3/\3\60\3\60\3\60\3\61\3\61\3"+
|
||||
"\62\3\62\3\62\3\63\3\63\3\63\3\64\3\64\3\64\3\65\3\65\3\65\3\65\3\66\3"+
|
||||
"\66\3\67\3\67\3\67\38\38\38\39\39\39\3:\3:\3:\3:\3;\3;\3;\3<\3<\3<\3="+
|
||||
"\3=\3=\3>\3>\3>\3>\3?\3?\3?\3?\3@\3@\3@\3@\3@\3@\3@\3@\3@\3A\3A\3A\3A"+
|
||||
"\3A\3A\3A\3A\3A\3B\3B\3B\3B\3B\3B\3B\3B\3B\3C\3C\3C\7C\u020b\nC\fC\16"+
|
||||
"C\u020e\13C\3C\3C\7C\u0212\nC\fC\16C\u0215\13C\5C\u0217\nC\3D\3D\7D\u021b"+
|
||||
"\nD\fD\16D\u021e\13D\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3"+
|
||||
"F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3F\3"+
|
||||
"F\3F\3F\3F\3F\3F\3F\5F\u024e\nF\3G\3G\3G\3G\3G\3G\3G\3G\3G\5G\u0259\n"+
|
||||
"G\3H\5H\u025c\nH\3H\3H\5H\u0260\nH\3H\3H\5H\u0264\nH\3I\6I\u0267\nI\r"+
|
||||
"I\16I\u0268\3I\3I\7I\u026d\nI\fI\16I\u0270\13I\3J\3J\7J\u0274\nJ\fJ\16"+
|
||||
"J\u0277\13J\3K\3K\3L\3L\3L\3L\7L\u027f\nL\fL\16L\u0282\13L\3L\3L\3M\3"+
|
||||
"M\3M\3M\2\2N\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16"+
|
||||
"\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34"+
|
||||
"\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g"+
|
||||
"\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089F"+
|
||||
"\u008bG\u008dH\u008fI\3\2\t\5\2C\\aac|\6\2\62;C\\aac|\7\2\60\60\62;C\\"+
|
||||
"aac|\3\2\62;\3\2\63;\3\2))\5\2\13\f\17\17\"\"\2\u0258\2\3\3\2\2\2\2\5"+
|
||||
"\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2"+
|
||||
"\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33"+
|
||||
"\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2"+
|
||||
"\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2"+
|
||||
"\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2"+
|
||||
"\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K"+
|
||||
"\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2"+
|
||||
"\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2"+
|
||||
"\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q"+
|
||||
"\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2"+
|
||||
"\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087"+
|
||||
"\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2"+
|
||||
"\2\3\u0091\3\2\2\2\5\u0093\3\2\2\2\7\u0095\3\2\2\2\t\u009c\3\2\2\2\13"+
|
||||
"\u00a5\3\2\2\2\r\u00ab\3\2\2\2\17\u00b1\3\2\2\2\21\u00b4\3\2\2\2\23\u00b6"+
|
||||
"\3\2\2\2\25\u00bc\3\2\2\2\27\u00c2\3\2\2\2\31\u00c7\3\2\2\2\33\u00cb\3"+
|
||||
"\2\2\2\35\u00d0\3\2\2\2\37\u00d6\3\2\2\2!\u00dd\3\2\2\2#\u00e3\3\2\2\2"+
|
||||
"%\u00e5\3\2\2\2\'\u00eb\3\2\2\2)\u00f0\3\2\2\2+\u00f3\3\2\2\2-\u00f7\3"+
|
||||
"\2\2\2/\u00fb\3\2\2\2\61\u00fe\3\2\2\2\63\u0106\3\2\2\2\65\u010e\3\2\2"+
|
||||
"\2\67\u0111\3\2\2\29\u0114\3\2\2\2;\u0119\3\2\2\2=\u0120\3\2\2\2?\u012a"+
|
||||
"\3\2\2\2A\u0132\3\2\2\2C\u0138\3\2\2\2E\u0140\3\2\2\2G\u014b\3\2\2\2I"+
|
||||
"\u0154\3\2\2\2K\u0159\3\2\2\2M\u015f\3\2\2\2O\u0168\3\2\2\2Q\u0172\3\2"+
|
||||
"\2\2S\u017d\3\2\2\2U\u0189\3\2\2\2W\u0192\3\2\2\2Y\u019c\3\2\2\2[\u019e"+
|
||||
"\3\2\2\2]\u01a1\3\2\2\2_\u01a3\3\2\2\2a\u01a6\3\2\2\2c\u01a9\3\2\2\2e"+
|
||||
"\u01ac\3\2\2\2g\u01b0\3\2\2\2i\u01b2\3\2\2\2k\u01b5\3\2\2\2m\u01b8\3\2"+
|
||||
"\2\2o\u01bb\3\2\2\2q\u01bf\3\2\2\2s\u01c2\3\2\2\2u\u01c5\3\2\2\2w\u01c8"+
|
||||
"\3\2\2\2y\u01cc\3\2\2\2{\u01d0\3\2\2\2}\u01d8\3\2\2\2\177\u01df\3\2\2"+
|
||||
"\2\u0081\u020d\3\2\2\2\u0083\u0218\3\2\2\2\u0085\u0223\3\2\2\2\u0087\u0226"+
|
||||
"\3\2\2\2\u0089\u0231\3\2\2\2\u008b\u0238\3\2\2\2\u008d\u023a\3\2\2\2\u008f"+
|
||||
"\u0245\3\2\2\2\u0091\u0092\7*\2\2\u0092\4\3\2\2\2\u0093\u0094\7+\2\2\u0094"+
|
||||
"\6\3\2\2\2\u0095\u0096\7u\2\2\u0096\u0097\7g\2\2\u0097\u0098\7n\2\2\u0098"+
|
||||
"\u0099\7g\2\2\u0099\u009a\7e\2\2\u009a\u009b\7v\2\2\u009b\b\3\2\2\2\u009c"+
|
||||
"\u009d\7f\2\2\u009d\u009e\7k\2\2\u009e\u009f\7u\2\2\u009f\u00a0\7v\2\2"+
|
||||
"\u00a0\u00a1\7k\2\2\u00a1\u00a2\7p\2\2\u00a2\u00a3\7e\2\2\u00a3\u00a4"+
|
||||
"\7v\2\2\u00a4\n\3\2\2\2\u00a5\u00a6\7y\2\2\u00a6\u00a7\7j\2\2\u00a7\u00a8"+
|
||||
"\7g\2\2\u00a8\u00a9\7t\2\2\u00a9\u00aa\7g\2\2\u00aa\f\3\2\2\2\u00ab\u00ac"+
|
||||
"\7q\2\2\u00ac\u00ad\7t\2\2\u00ad\u00ae\7f\2\2\u00ae\u00af\7g\2\2\u00af"+
|
||||
"\u00b0\7t\2\2\u00b0\16\3\2\2\2\u00b1\u00b2\7d\2\2\u00b2\u00b3\7{\2\2\u00b3"+
|
||||
"\20\3\2\2\2\u00b4\u00b5\7.\2\2\u00b5\22\3\2\2\2\u00b6\u00b7\7p\2\2\u00b7"+
|
||||
"\u00b8\7w\2\2\u00b8\u00b9\7n\2\2\u00b9\u00ba\7n\2\2\u00ba\u00bb\7u\2\2"+
|
||||
"\u00bb\24\3\2\2\2\u00bc\u00bd\7h\2\2\u00bd\u00be\7k\2\2\u00be\u00bf\7"+
|
||||
"t\2\2\u00bf\u00c0\7u\2\2\u00c0\u00c1\7v\2\2\u00c1\26\3\2\2\2\u00c2\u00c3"+
|
||||
"\7n\2\2\u00c3\u00c4\7c\2\2\u00c4\u00c5\7u\2\2\u00c5\u00c6\7v\2\2\u00c6"+
|
||||
"\30\3\2\2\2\u00c7\u00c8\7c\2\2\u00c8\u00c9\7u\2\2\u00c9\u00ca\7e\2\2\u00ca"+
|
||||
"\32\3\2\2\2\u00cb\u00cc\7f\2\2\u00cc\u00cd\7g\2\2\u00cd\u00ce\7u\2\2\u00ce"+
|
||||
"\u00cf\7e\2\2\u00cf\34\3\2\2\2\u00d0\u00d1\7n\2\2\u00d1\u00d2\7k\2\2\u00d2"+
|
||||
"\u00d3\7o\2\2\u00d3\u00d4\7k\2\2\u00d4\u00d5\7v\2\2\u00d5\36\3\2\2\2\u00d6"+
|
||||
"\u00d7\7q\2\2\u00d7\u00d8\7h\2\2\u00d8\u00d9\7h\2\2\u00d9\u00da\7u\2\2"+
|
||||
"\u00da\u00db\7g\2\2\u00db\u00dc\7v\2\2\u00dc \3\2\2\2\u00dd\u00de\7h\2"+
|
||||
"\2\u00de\u00df\7g\2\2\u00df\u00e0\7v\2\2\u00e0\u00e1\7e\2\2\u00e1\u00e2"+
|
||||
"\7j\2\2\u00e2\"\3\2\2\2\u00e3\u00e4\7-\2\2\u00e4$\3\2\2\2\u00e5\u00e6"+
|
||||
"\7s\2\2\u00e6\u00e7\7w\2\2\u00e7\u00e8\7g\2\2\u00e8\u00e9\7t\2\2\u00e9"+
|
||||
"\u00ea\7{\2\2\u00ea&\3\2\2\2\u00eb\u00ec\7n\2\2\u00ec\u00ed\7c\2\2\u00ed"+
|
||||
"\u00ee\7|\2\2\u00ee\u00ef\7{\2\2\u00ef(\3\2\2\2\u00f0\u00f1\7q\2\2\u00f1"+
|
||||
"\u00f2\7t\2\2\u00f2*\3\2\2\2\u00f3\u00f4\7c\2\2\u00f4\u00f5\7p\2\2\u00f5"+
|
||||
"\u00f6\7f\2\2\u00f6,\3\2\2\2\u00f7\u00f8\7p\2\2\u00f8\u00f9\7q\2\2\u00f9"+
|
||||
"\u00fa\7v\2\2\u00fa.\3\2\2\2\u00fb\u00fc\7k\2\2\u00fc\u00fd\7p\2\2\u00fd"+
|
||||
"\60\3\2\2\2\u00fe\u00ff\7d\2\2\u00ff\u0100\7g\2\2\u0100\u0101\7v\2\2\u0101"+
|
||||
"\u0102\7y\2\2\u0102\u0103\7g\2\2\u0103\u0104\7g\2\2\u0104\u0105\7p\2\2"+
|
||||
"\u0105\62\3\2\2\2\u0106\u0107\7k\2\2\u0107\u0108\7p\2\2\u0108\u0109\7"+
|
||||
"t\2\2\u0109\u010a\7c\2\2\u010a\u010b\7p\2\2\u010b\u010c\7i\2\2\u010c\u010d"+
|
||||
"\7g\2\2\u010d\64\3\2\2\2\u010e\u010f\7v\2\2\u010f\u0110\7q\2\2\u0110\66"+
|
||||
"\3\2\2\2\u0111\u0112\7k\2\2\u0112\u0113\7u\2\2\u01138\3\2\2\2\u0114\u0115"+
|
||||
"\7p\2\2\u0115\u0116\7w\2\2\u0116\u0117\7n\2\2\u0117\u0118\7n\2\2\u0118"+
|
||||
":\3\2\2\2\u0119\u011a\7k\2\2\u011a\u011b\7u\2\2\u011b\u011c\7P\2\2\u011c"+
|
||||
"\u011d\7w\2\2\u011d\u011e\7n\2\2\u011e\u011f\7n\2\2\u011f<\3\2\2\2\u0120"+
|
||||
"\u0121\7k\2\2\u0121\u0122\7u\2\2\u0122\u0123\7P\2\2\u0123\u0124\7q\2\2"+
|
||||
"\u0124\u0125\7v\2\2\u0125\u0126\7P\2\2\u0126\u0127\7w\2\2\u0127\u0128"+
|
||||
"\7n\2\2\u0128\u0129\7n\2\2\u0129>\3\2\2\2\u012a\u012b\7p\2\2\u012b\u012c"+
|
||||
"\7q\2\2\u012c\u012d\7v\2\2\u012d\u012e\7P\2\2\u012e\u012f\7w\2\2\u012f"+
|
||||
"\u0130\7n\2\2\u0130\u0131\7n\2\2\u0131@\3\2\2\2\u0132\u0133\7g\2\2\u0133"+
|
||||
"\u0134\7o\2\2\u0134\u0135\7r\2\2\u0135\u0136\7v\2\2\u0136\u0137\7{\2\2"+
|
||||
"\u0137B\3\2\2\2\u0138\u0139\7k\2\2\u0139\u013a\7u\2\2\u013a\u013b\7G\2"+
|
||||
"\2\u013b\u013c\7o\2\2\u013c\u013d\7r\2\2\u013d\u013e\7v\2\2\u013e\u013f"+
|
||||
"\7{\2\2\u013fD\3\2\2\2\u0140\u0141\7k\2\2\u0141\u0142\7u\2\2\u0142\u0143"+
|
||||
"\7P\2\2\u0143\u0144\7q\2\2\u0144\u0145\7v\2\2\u0145\u0146\7G\2\2\u0146"+
|
||||
"\u0147\7o\2\2\u0147\u0148\7r\2\2\u0148\u0149\7v\2\2\u0149\u014a\7{\2\2"+
|
||||
"\u014aF\3\2\2\2\u014b\u014c\7p\2\2\u014c\u014d\7q\2\2\u014d\u014e\7v\2"+
|
||||
"\2\u014e\u014f\7G\2\2\u014f\u0150\7o\2\2\u0150\u0151\7r\2\2\u0151\u0152"+
|
||||
"\7v\2\2\u0152\u0153\7{\2\2\u0153H\3\2\2\2\u0154\u0155\7n\2\2\u0155\u0156"+
|
||||
"\7k\2\2\u0156\u0157\7m\2\2\u0157\u0158\7g\2\2\u0158J\3\2\2\2\u0159\u015a"+
|
||||
"\7k\2\2\u015a\u015b\7n\2\2\u015b\u015c\7k\2\2\u015c\u015d\7m\2\2\u015d"+
|
||||
"\u015e\7g\2\2\u015eL\3\2\2\2\u015f\u0160\7e\2\2\u0160\u0161\7q\2\2\u0161"+
|
||||
"\u0162\7p\2\2\u0162\u0163\7v\2\2\u0163\u0164\7c\2\2\u0164\u0165\7k\2\2"+
|
||||
"\u0165\u0166\7p\2\2\u0166\u0167\7u\2\2\u0167N\3\2\2\2\u0168\u0169\7k\2"+
|
||||
"\2\u0169\u016a\7e\2\2\u016a\u016b\7q\2\2\u016b\u016c\7p\2\2\u016c\u016d"+
|
||||
"\7v\2\2\u016d\u016e\7c\2\2\u016e\u016f\7k\2\2\u016f\u0170\7p\2\2\u0170"+
|
||||
"\u0171\7u\2\2\u0171P\3\2\2\2\u0172\u0173\7u\2\2\u0173\u0174\7v\2\2\u0174"+
|
||||
"\u0175\7c\2\2\u0175\u0176\7t\2\2\u0176\u0177\7v\2\2\u0177\u0178\7u\2\2"+
|
||||
"\u0178\u0179\7Y\2\2\u0179\u017a\7k\2\2\u017a\u017b\7v\2\2\u017b\u017c"+
|
||||
"\7j\2\2\u017cR\3\2\2\2\u017d\u017e\7k\2\2\u017e\u017f\7u\2\2\u017f\u0180"+
|
||||
"\7v\2\2\u0180\u0181\7c\2\2\u0181\u0182\7t\2\2\u0182\u0183\7v\2\2\u0183"+
|
||||
"\u0184\7u\2\2\u0184\u0185\7Y\2\2\u0185\u0186\7k\2\2\u0186\u0187\7v\2\2"+
|
||||
"\u0187\u0188\7j\2\2\u0188T\3\2\2\2\u0189\u018a\7g\2\2\u018a\u018b\7p\2"+
|
||||
"\2\u018b\u018c\7f\2\2\u018c\u018d\7u\2\2\u018d\u018e\7Y\2\2\u018e\u018f"+
|
||||
"\7k\2\2\u018f\u0190\7v\2\2\u0190\u0191\7j\2\2\u0191V\3\2\2\2\u0192\u0193"+
|
||||
"\7k\2\2\u0193\u0194\7g\2\2\u0194\u0195\7p\2\2\u0195\u0196\7f\2\2\u0196"+
|
||||
"\u0197\7u\2\2\u0197\u0198\7Y\2\2\u0198\u0199\7k\2\2\u0199\u019a\7v\2\2"+
|
||||
"\u019a\u019b\7j\2\2\u019bX\3\2\2\2\u019c\u019d\7?\2\2\u019dZ\3\2\2\2\u019e"+
|
||||
"\u019f\7g\2\2\u019f\u01a0\7s\2\2\u01a0\\\3\2\2\2\u01a1\u01a2\7@\2\2\u01a2"+
|
||||
"^\3\2\2\2\u01a3\u01a4\7i\2\2\u01a4\u01a5\7v\2\2\u01a5`\3\2\2\2\u01a6\u01a7"+
|
||||
"\7@\2\2\u01a7\u01a8\7?\2\2\u01a8b\3\2\2\2\u01a9\u01aa\7i\2\2\u01aa\u01ab"+
|
||||
"\7g\2\2\u01abd\3\2\2\2\u01ac\u01ad\7i\2\2\u01ad\u01ae\7v\2\2\u01ae\u01af"+
|
||||
"\7g\2\2\u01aff\3\2\2\2\u01b0\u01b1\7>\2\2\u01b1h\3\2\2\2\u01b2\u01b3\7"+
|
||||
"n\2\2\u01b3\u01b4\7v\2\2\u01b4j\3\2\2\2\u01b5\u01b6\7>\2\2\u01b6\u01b7"+
|
||||
"\7?\2\2\u01b7l\3\2\2\2\u01b8\u01b9\7n\2\2\u01b9\u01ba\7g\2\2\u01ban\3"+
|
||||
"\2\2\2\u01bb\u01bc\7n\2\2\u01bc\u01bd\7v\2\2\u01bd\u01be\7g\2\2\u01be"+
|
||||
"p\3\2\2\2\u01bf\u01c0\7>\2\2\u01c0\u01c1\7@\2\2\u01c1r\3\2\2\2\u01c2\u01c3"+
|
||||
"\7#\2\2\u01c3\u01c4\7?\2\2\u01c4t\3\2\2\2\u01c5\u01c6\7p\2\2\u01c6\u01c7"+
|
||||
"\7g\2\2\u01c7v\3\2\2\2\u01c8\u01c9\7k\2\2\u01c9\u01ca\7g\2\2\u01ca\u01cb"+
|
||||
"\7s\2\2\u01cbx\3\2\2\2\u01cc\u01cd\7k\2\2\u01cd\u01ce\7p\2\2\u01ce\u01cf"+
|
||||
"\7g\2\2\u01cfz\3\2\2\2\u01d0\u01d1\7<\2\2\u01d1\u01d5\t\2\2\2\u01d2\u01d4"+
|
||||
"\t\3\2\2\u01d3\u01d2\3\2\2\2\u01d4\u01d7\3\2\2\2\u01d5\u01d3\3\2\2\2\u01d5"+
|
||||
"\u01d6\3\2\2\2\u01d6|\3\2\2\2\u01d7\u01d5\3\2\2\2\u01d8\u01dc\t\2\2\2"+
|
||||
"\u01d9\u01db\t\4\2\2\u01da\u01d9\3\2\2\2\u01db\u01de\3\2\2\2\u01dc\u01da"+
|
||||
"\3\2\2\2\u01dc\u01dd\3\2\2\2\u01dd~\3\2\2\2\u01de\u01dc\3\2\2\2\u01df"+
|
||||
"\u01e0\7b\2\2\u01e0\u01e1\5}?\2\u01e1\u01e2\7b\2\2\u01e2\u0080\3\2\2\2"+
|
||||
"\u01e3\u01e4\7u\2\2\u01e4\u01e5\7w\2\2\u01e5\u01e6\7o\2\2\u01e6\u01e7"+
|
||||
"\7*\2\2\u01e7\u01e8\3\2\2\2\u01e8\u01e9\5}?\2\u01e9\u01ea\7+\2\2\u01ea"+
|
||||
"\u020e\3\2\2\2\u01eb\u01ec\7o\2\2\u01ec\u01ed\7c\2\2\u01ed\u01ee\7z\2"+
|
||||
"\2\u01ee\u01ef\7*\2\2\u01ef\u01f0\3\2\2\2\u01f0\u01f1\5}?\2\u01f1\u01f2"+
|
||||
"\7+\2\2\u01f2\u020e\3\2\2\2\u01f3\u01f4\7o\2\2\u01f4\u01f5\7k\2\2\u01f5"+
|
||||
"\u01f6\7p\2\2\u01f6\u01f7\7*\2\2\u01f7\u01f8\3\2\2\2\u01f8\u01f9\5}?\2"+
|
||||
"\u01f9\u01fa\7+\2\2\u01fa\u020e\3\2\2\2\u01fb\u01fc\7c\2\2\u01fc\u01fd"+
|
||||
"\7x\2\2\u01fd\u01fe\7i\2\2\u01fe\u01ff\7*\2\2\u01ff\u0200\3\2\2\2\u0200"+
|
||||
"\u0201\5}?\2\u0201\u0202\7+\2\2\u0202\u020e\3\2\2\2\u0203\u0204\7e\2\2"+
|
||||
"\u0204\u0205\7q\2\2\u0205\u0206\7w\2\2\u0206\u0207\7p\2\2\u0207\u0208"+
|
||||
"\7v\2\2\u0208\u0209\7*\2\2\u0209\u020a\3\2\2\2\u020a\u020b\5}?\2\u020b"+
|
||||
"\u020c\7+\2\2\u020c\u020e\3\2\2\2\u020d\u01e3\3\2\2\2\u020d\u01eb\3\2"+
|
||||
"\2\2\u020d\u01f3\3\2\2\2\u020d\u01fb\3\2\2\2\u020d\u0203\3\2\2\2\u020e"+
|
||||
"\u0082\3\2\2\2\u020f\u0210\7v\2\2\u0210\u0211\7t\2\2\u0211\u0212\7w\2"+
|
||||
"\2\u0212\u0219\7g\2\2\u0213\u0214\7h\2\2\u0214\u0215\7c\2\2\u0215\u0216"+
|
||||
"\7n\2\2\u0216\u0217\7u\2\2\u0217\u0219\7g\2\2\u0218\u020f\3\2\2\2\u0218"+
|
||||
"\u0213\3\2\2\2\u0219\u0084\3\2\2\2\u021a\u021c\7/\2\2\u021b\u021a\3\2"+
|
||||
"\2\2\u021b\u021c\3\2\2\2\u021c\u021d\3\2\2\2\u021d\u0224\5\u0087D\2\u021e"+
|
||||
"\u0220\7/\2\2\u021f\u021e\3\2\2\2\u021f\u0220\3\2\2\2\u0220\u0221\3\2"+
|
||||
"\2\2\u0221\u0224\5\u0089E\2\u0222\u0224\5\u008bF\2\u0223\u021b\3\2\2\2"+
|
||||
"\u0223\u021f\3\2\2\2\u0223\u0222\3\2\2\2\u0224\u0086\3\2\2\2\u0225\u0227"+
|
||||
"\t\5\2\2\u0226\u0225\3\2\2\2\u0227\u0228\3\2\2\2\u0228\u0226\3\2\2\2\u0228"+
|
||||
"\u0229\3\2\2\2\u0229\u022a\3\2\2\2\u022a\u022e\7\60\2\2\u022b\u022d\t"+
|
||||
"\5\2\2\u022c\u022b\3\2\2\2\u022d\u0230\3\2\2\2\u022e\u022c\3\2\2\2\u022e"+
|
||||
"\u022f\3\2\2\2\u022f\u0088\3\2\2\2\u0230\u022e\3\2\2\2\u0231\u0235\t\6"+
|
||||
"\2\2\u0232\u0234\t\5\2\2\u0233\u0232\3\2\2\2\u0234\u0237\3\2\2\2\u0235"+
|
||||
"\u0233\3\2\2\2\u0235\u0236\3\2\2\2\u0236\u008a\3\2\2\2\u0237\u0235\3\2"+
|
||||
"\2\2\u0238\u0239\7\62\2\2\u0239\u008c\3\2\2\2\u023a\u0240\7)\2\2\u023b"+
|
||||
"\u023f\n\7\2\2\u023c\u023d\7)\2\2\u023d\u023f\7)\2\2\u023e\u023b\3\2\2"+
|
||||
"\2\u023e\u023c\3\2\2\2\u023f\u0242\3\2\2\2\u0240\u023e\3\2\2\2\u0240\u0241"+
|
||||
"\3\2\2\2\u0241\u0243\3\2\2\2\u0242\u0240\3\2\2\2\u0243\u0244\7)\2\2\u0244"+
|
||||
"\u008e\3\2\2\2\u0245\u0246\t\b\2\2\u0246\u0247\3\2\2\2\u0247\u0248\bH"+
|
||||
"\2\2\u0248\u0090\3\2\2\2\17\2\u01d5\u01dc\u020d\u0218\u021b\u021f\u0223"+
|
||||
"\u0228\u022e\u0235\u023e\u0240\3\b\2\2";
|
||||
"\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\3\2\t\5\2C\\"+
|
||||
"aac|\6\2\62;C\\aac|\7\2\60\60\62;C\\aac|\3\2\62;\3\2\63;\3\2))\5\2\13"+
|
||||
"\f\17\17\"\"\2\u029a\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2"+
|
||||
"\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3"+
|
||||
"\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2"+
|
||||
"\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2"+
|
||||
"\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2"+
|
||||
"\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2"+
|
||||
"\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q"+
|
||||
"\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2"+
|
||||
"\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2"+
|
||||
"\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w"+
|
||||
"\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2"+
|
||||
"\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b"+
|
||||
"\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2"+
|
||||
"\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099\3\2\2\2\3\u009b\3\2\2\2\5\u009d"+
|
||||
"\3\2\2\2\7\u009f\3\2\2\2\t\u00a6\3\2\2\2\13\u00af\3\2\2\2\r\u00b5\3\2"+
|
||||
"\2\2\17\u00bb\3\2\2\2\21\u00be\3\2\2\2\23\u00c0\3\2\2\2\25\u00c6\3\2\2"+
|
||||
"\2\27\u00cc\3\2\2\2\31\u00d1\3\2\2\2\33\u00d5\3\2\2\2\35\u00da\3\2\2\2"+
|
||||
"\37\u00e0\3\2\2\2!\u00e7\3\2\2\2#\u00ed\3\2\2\2%\u00ef\3\2\2\2\'\u00f5"+
|
||||
"\3\2\2\2)\u00fa\3\2\2\2+\u00fd\3\2\2\2-\u0101\3\2\2\2/\u0105\3\2\2\2\61"+
|
||||
"\u010f\3\2\2\2\63\u0112\3\2\2\2\65\u011a\3\2\2\2\67\u011d\3\2\2\29\u0125"+
|
||||
"\3\2\2\2;\u012d\3\2\2\2=\u0130\3\2\2\2?\u0135\3\2\2\2A\u013c\3\2\2\2C"+
|
||||
"\u0146\3\2\2\2E\u014e\3\2\2\2G\u0154\3\2\2\2I\u015c\3\2\2\2K\u0167\3\2"+
|
||||
"\2\2M\u0170\3\2\2\2O\u0175\3\2\2\2Q\u017b\3\2\2\2S\u0184\3\2\2\2U\u018e"+
|
||||
"\3\2\2\2W\u0199\3\2\2\2Y\u01a5\3\2\2\2[\u01ae\3\2\2\2]\u01b8\3\2\2\2_"+
|
||||
"\u01ba\3\2\2\2a\u01bd\3\2\2\2c\u01bf\3\2\2\2e\u01c2\3\2\2\2g\u01c5\3\2"+
|
||||
"\2\2i\u01c8\3\2\2\2k\u01cc\3\2\2\2m\u01ce\3\2\2\2o\u01d1\3\2\2\2q\u01d4"+
|
||||
"\3\2\2\2s\u01d7\3\2\2\2u\u01db\3\2\2\2w\u01de\3\2\2\2y\u01e1\3\2\2\2{"+
|
||||
"\u01e4\3\2\2\2}\u01e8\3\2\2\2\177\u01ec\3\2\2\2\u0081\u01f5\3\2\2\2\u0083"+
|
||||
"\u01fe\3\2\2\2\u0085\u0216\3\2\2\2\u0087\u0218\3\2\2\2\u0089\u021f\3\2"+
|
||||
"\2\2\u008b\u024d\3\2\2\2\u008d\u0258\3\2\2\2\u008f\u0263\3\2\2\2\u0091"+
|
||||
"\u0266\3\2\2\2\u0093\u0271\3\2\2\2\u0095\u0278\3\2\2\2\u0097\u027a\3\2"+
|
||||
"\2\2\u0099\u0285\3\2\2\2\u009b\u009c\7*\2\2\u009c\4\3\2\2\2\u009d\u009e"+
|
||||
"\7+\2\2\u009e\6\3\2\2\2\u009f\u00a0\7u\2\2\u00a0\u00a1\7g\2\2\u00a1\u00a2"+
|
||||
"\7n\2\2\u00a2\u00a3\7g\2\2\u00a3\u00a4\7e\2\2\u00a4\u00a5\7v\2\2\u00a5"+
|
||||
"\b\3\2\2\2\u00a6\u00a7\7f\2\2\u00a7\u00a8\7k\2\2\u00a8\u00a9\7u\2\2\u00a9"+
|
||||
"\u00aa\7v\2\2\u00aa\u00ab\7k\2\2\u00ab\u00ac\7p\2\2\u00ac\u00ad\7e\2\2"+
|
||||
"\u00ad\u00ae\7v\2\2\u00ae\n\3\2\2\2\u00af\u00b0\7y\2\2\u00b0\u00b1\7j"+
|
||||
"\2\2\u00b1\u00b2\7g\2\2\u00b2\u00b3\7t\2\2\u00b3\u00b4\7g\2\2\u00b4\f"+
|
||||
"\3\2\2\2\u00b5\u00b6\7q\2\2\u00b6\u00b7\7t\2\2\u00b7\u00b8\7f\2\2\u00b8"+
|
||||
"\u00b9\7g\2\2\u00b9\u00ba\7t\2\2\u00ba\16\3\2\2\2\u00bb\u00bc\7d\2\2\u00bc"+
|
||||
"\u00bd\7{\2\2\u00bd\20\3\2\2\2\u00be\u00bf\7.\2\2\u00bf\22\3\2\2\2\u00c0"+
|
||||
"\u00c1\7p\2\2\u00c1\u00c2\7w\2\2\u00c2\u00c3\7n\2\2\u00c3\u00c4\7n\2\2"+
|
||||
"\u00c4\u00c5\7u\2\2\u00c5\24\3\2\2\2\u00c6\u00c7\7h\2\2\u00c7\u00c8\7"+
|
||||
"k\2\2\u00c8\u00c9\7t\2\2\u00c9\u00ca\7u\2\2\u00ca\u00cb\7v\2\2\u00cb\26"+
|
||||
"\3\2\2\2\u00cc\u00cd\7n\2\2\u00cd\u00ce\7c\2\2\u00ce\u00cf\7u\2\2\u00cf"+
|
||||
"\u00d0\7v\2\2\u00d0\30\3\2\2\2\u00d1\u00d2\7c\2\2\u00d2\u00d3\7u\2\2\u00d3"+
|
||||
"\u00d4\7e\2\2\u00d4\32\3\2\2\2\u00d5\u00d6\7f\2\2\u00d6\u00d7\7g\2\2\u00d7"+
|
||||
"\u00d8\7u\2\2\u00d8\u00d9\7e\2\2\u00d9\34\3\2\2\2\u00da\u00db\7n\2\2\u00db"+
|
||||
"\u00dc\7k\2\2\u00dc\u00dd\7o\2\2\u00dd\u00de\7k\2\2\u00de\u00df\7v\2\2"+
|
||||
"\u00df\36\3\2\2\2\u00e0\u00e1\7q\2\2\u00e1\u00e2\7h\2\2\u00e2\u00e3\7"+
|
||||
"h\2\2\u00e3\u00e4\7u\2\2\u00e4\u00e5\7g\2\2\u00e5\u00e6\7v\2\2\u00e6 "+
|
||||
"\3\2\2\2\u00e7\u00e8\7h\2\2\u00e8\u00e9\7g\2\2\u00e9\u00ea\7v\2\2\u00ea"+
|
||||
"\u00eb\7e\2\2\u00eb\u00ec\7j\2\2\u00ec\"\3\2\2\2\u00ed\u00ee\7-\2\2\u00ee"+
|
||||
"$\3\2\2\2\u00ef\u00f0\7s\2\2\u00f0\u00f1\7w\2\2\u00f1\u00f2\7g\2\2\u00f2"+
|
||||
"\u00f3\7t\2\2\u00f3\u00f4\7{\2\2\u00f4&\3\2\2\2\u00f5\u00f6\7n\2\2\u00f6"+
|
||||
"\u00f7\7c\2\2\u00f7\u00f8\7|\2\2\u00f8\u00f9\7{\2\2\u00f9(\3\2\2\2\u00fa"+
|
||||
"\u00fb\7q\2\2\u00fb\u00fc\7t\2\2\u00fc*\3\2\2\2\u00fd\u00fe\7c\2\2\u00fe"+
|
||||
"\u00ff\7p\2\2\u00ff\u0100\7f\2\2\u0100,\3\2\2\2\u0101\u0102\7p\2\2\u0102"+
|
||||
"\u0103\7q\2\2\u0103\u0104\7v\2\2\u0104.\3\2\2\2\u0105\u0106\7k\2\2\u0106"+
|
||||
"\u0107\7p\2\2\u0107\u0108\7Q\2\2\u0108\u0109\7t\2\2\u0109\u010a\7G\2\2"+
|
||||
"\u010a\u010b\7o\2\2\u010b\u010c\7r\2\2\u010c\u010d\7v\2\2\u010d\u010e"+
|
||||
"\7{\2\2\u010e\60\3\2\2\2\u010f\u0110\7k\2\2\u0110\u0111\7p\2\2\u0111\62"+
|
||||
"\3\2\2\2\u0112\u0113\7d\2\2\u0113\u0114\7g\2\2\u0114\u0115\7v\2\2\u0115"+
|
||||
"\u0116\7y\2\2\u0116\u0117\7g\2\2\u0117\u0118\7g\2\2\u0118\u0119\7p\2\2"+
|
||||
"\u0119\64\3\2\2\2\u011a\u011b\7v\2\2\u011b\u011c\7q\2\2\u011c\66\3\2\2"+
|
||||
"\2\u011d\u011e\7k\2\2\u011e\u011f\7p\2\2\u011f\u0120\7t\2\2\u0120\u0121"+
|
||||
"\7c\2\2\u0121\u0122\7p\2\2\u0122\u0123\7i\2\2\u0123\u0124\7g\2\2\u0124"+
|
||||
"8\3\2\2\2\u0125\u0126\7k\2\2\u0126\u0127\7p\2\2\u0127\u0128\7T\2\2\u0128"+
|
||||
"\u0129\7c\2\2\u0129\u012a\7p\2\2\u012a\u012b\7i\2\2\u012b\u012c\7g\2\2"+
|
||||
"\u012c:\3\2\2\2\u012d\u012e\7k\2\2\u012e\u012f\7u\2\2\u012f<\3\2\2\2\u0130"+
|
||||
"\u0131\7p\2\2\u0131\u0132\7w\2\2\u0132\u0133\7n\2\2\u0133\u0134\7n\2\2"+
|
||||
"\u0134>\3\2\2\2\u0135\u0136\7k\2\2\u0136\u0137\7u\2\2\u0137\u0138\7P\2"+
|
||||
"\2\u0138\u0139\7w\2\2\u0139\u013a\7n\2\2\u013a\u013b\7n\2\2\u013b@\3\2"+
|
||||
"\2\2\u013c\u013d\7k\2\2\u013d\u013e\7u\2\2\u013e\u013f\7P\2\2\u013f\u0140"+
|
||||
"\7q\2\2\u0140\u0141\7v\2\2\u0141\u0142\7P\2\2\u0142\u0143\7w\2\2\u0143"+
|
||||
"\u0144\7n\2\2\u0144\u0145\7n\2\2\u0145B\3\2\2\2\u0146\u0147\7p\2\2\u0147"+
|
||||
"\u0148\7q\2\2\u0148\u0149\7v\2\2\u0149\u014a\7P\2\2\u014a\u014b\7w\2\2"+
|
||||
"\u014b\u014c\7n\2\2\u014c\u014d\7n\2\2\u014dD\3\2\2\2\u014e\u014f\7g\2"+
|
||||
"\2\u014f\u0150\7o\2\2\u0150\u0151\7r\2\2\u0151\u0152\7v\2\2\u0152\u0153"+
|
||||
"\7{\2\2\u0153F\3\2\2\2\u0154\u0155\7k\2\2\u0155\u0156\7u\2\2\u0156\u0157"+
|
||||
"\7G\2\2\u0157\u0158\7o\2\2\u0158\u0159\7r\2\2\u0159\u015a\7v\2\2\u015a"+
|
||||
"\u015b\7{\2\2\u015bH\3\2\2\2\u015c\u015d\7k\2\2\u015d\u015e\7u\2\2\u015e"+
|
||||
"\u015f\7P\2\2\u015f\u0160\7q\2\2\u0160\u0161\7v\2\2\u0161\u0162\7G\2\2"+
|
||||
"\u0162\u0163\7o\2\2\u0163\u0164\7r\2\2\u0164\u0165\7v\2\2\u0165\u0166"+
|
||||
"\7{\2\2\u0166J\3\2\2\2\u0167\u0168\7p\2\2\u0168\u0169\7q\2\2\u0169\u016a"+
|
||||
"\7v\2\2\u016a\u016b\7G\2\2\u016b\u016c\7o\2\2\u016c\u016d\7r\2\2\u016d"+
|
||||
"\u016e\7v\2\2\u016e\u016f\7{\2\2\u016fL\3\2\2\2\u0170\u0171\7n\2\2\u0171"+
|
||||
"\u0172\7k\2\2\u0172\u0173\7m\2\2\u0173\u0174\7g\2\2\u0174N\3\2\2\2\u0175"+
|
||||
"\u0176\7k\2\2\u0176\u0177\7n\2\2\u0177\u0178\7k\2\2\u0178\u0179\7m\2\2"+
|
||||
"\u0179\u017a\7g\2\2\u017aP\3\2\2\2\u017b\u017c\7e\2\2\u017c\u017d\7q\2"+
|
||||
"\2\u017d\u017e\7p\2\2\u017e\u017f\7v\2\2\u017f\u0180\7c\2\2\u0180\u0181"+
|
||||
"\7k\2\2\u0181\u0182\7p\2\2\u0182\u0183\7u\2\2\u0183R\3\2\2\2\u0184\u0185"+
|
||||
"\7k\2\2\u0185\u0186\7e\2\2\u0186\u0187\7q\2\2\u0187\u0188\7p\2\2\u0188"+
|
||||
"\u0189\7v\2\2\u0189\u018a\7c\2\2\u018a\u018b\7k\2\2\u018b\u018c\7p\2\2"+
|
||||
"\u018c\u018d\7u\2\2\u018dT\3\2\2\2\u018e\u018f\7u\2\2\u018f\u0190\7v\2"+
|
||||
"\2\u0190\u0191\7c\2\2\u0191\u0192\7t\2\2\u0192\u0193\7v\2\2\u0193\u0194"+
|
||||
"\7u\2\2\u0194\u0195\7Y\2\2\u0195\u0196\7k\2\2\u0196\u0197\7v\2\2\u0197"+
|
||||
"\u0198\7j\2\2\u0198V\3\2\2\2\u0199\u019a\7k\2\2\u019a\u019b\7u\2\2\u019b"+
|
||||
"\u019c\7v\2\2\u019c\u019d\7c\2\2\u019d\u019e\7t\2\2\u019e\u019f\7v\2\2"+
|
||||
"\u019f\u01a0\7u\2\2\u01a0\u01a1\7Y\2\2\u01a1\u01a2\7k\2\2\u01a2\u01a3"+
|
||||
"\7v\2\2\u01a3\u01a4\7j\2\2\u01a4X\3\2\2\2\u01a5\u01a6\7g\2\2\u01a6\u01a7"+
|
||||
"\7p\2\2\u01a7\u01a8\7f\2\2\u01a8\u01a9\7u\2\2\u01a9\u01aa\7Y\2\2\u01aa"+
|
||||
"\u01ab\7k\2\2\u01ab\u01ac\7v\2\2\u01ac\u01ad\7j\2\2\u01adZ\3\2\2\2\u01ae"+
|
||||
"\u01af\7k\2\2\u01af\u01b0\7g\2\2\u01b0\u01b1\7p\2\2\u01b1\u01b2\7f\2\2"+
|
||||
"\u01b2\u01b3\7u\2\2\u01b3\u01b4\7Y\2\2\u01b4\u01b5\7k\2\2\u01b5\u01b6"+
|
||||
"\7v\2\2\u01b6\u01b7\7j\2\2\u01b7\\\3\2\2\2\u01b8\u01b9\7?\2\2\u01b9^\3"+
|
||||
"\2\2\2\u01ba\u01bb\7g\2\2\u01bb\u01bc\7s\2\2\u01bc`\3\2\2\2\u01bd\u01be"+
|
||||
"\7@\2\2\u01beb\3\2\2\2\u01bf\u01c0\7i\2\2\u01c0\u01c1\7v\2\2\u01c1d\3"+
|
||||
"\2\2\2\u01c2\u01c3\7@\2\2\u01c3\u01c4\7?\2\2\u01c4f\3\2\2\2\u01c5\u01c6"+
|
||||
"\7i\2\2\u01c6\u01c7\7g\2\2\u01c7h\3\2\2\2\u01c8\u01c9\7i\2\2\u01c9\u01ca"+
|
||||
"\7v\2\2\u01ca\u01cb\7g\2\2\u01cbj\3\2\2\2\u01cc\u01cd\7>\2\2\u01cdl\3"+
|
||||
"\2\2\2\u01ce\u01cf\7n\2\2\u01cf\u01d0\7v\2\2\u01d0n\3\2\2\2\u01d1\u01d2"+
|
||||
"\7>\2\2\u01d2\u01d3\7?\2\2\u01d3p\3\2\2\2\u01d4\u01d5\7n\2\2\u01d5\u01d6"+
|
||||
"\7g\2\2\u01d6r\3\2\2\2\u01d7\u01d8\7n\2\2\u01d8\u01d9\7v\2\2\u01d9\u01da"+
|
||||
"\7g\2\2\u01dat\3\2\2\2\u01db\u01dc\7>\2\2\u01dc\u01dd\7@\2\2\u01ddv\3"+
|
||||
"\2\2\2\u01de\u01df\7#\2\2\u01df\u01e0\7?\2\2\u01e0x\3\2\2\2\u01e1\u01e2"+
|
||||
"\7p\2\2\u01e2\u01e3\7g\2\2\u01e3z\3\2\2\2\u01e4\u01e5\7k\2\2\u01e5\u01e6"+
|
||||
"\7g\2\2\u01e6\u01e7\7s\2\2\u01e7|\3\2\2\2\u01e8\u01e9\7k\2\2\u01e9\u01ea"+
|
||||
"\7p\2\2\u01ea\u01eb\7g\2\2\u01eb~\3\2\2\2\u01ec\u01ed\7g\2\2\u01ed\u01ee"+
|
||||
"\7s\2\2\u01ee\u01ef\7Q\2\2\u01ef\u01f0\7t\2\2\u01f0\u01f1\7P\2\2\u01f1"+
|
||||
"\u01f2\7w\2\2\u01f2\u01f3\7n\2\2\u01f3\u01f4\7n\2\2\u01f4\u0080\3\2\2"+
|
||||
"\2\u01f5\u01f6\7i\2\2\u01f6\u01f7\7v\2\2\u01f7\u01f8\7Q\2\2\u01f8\u01f9"+
|
||||
"\7t\2\2\u01f9\u01fa\7P\2\2\u01fa\u01fb\7w\2\2\u01fb\u01fc\7n\2\2\u01fc"+
|
||||
"\u01fd\7n\2\2\u01fd\u0082\3\2\2\2\u01fe\u01ff\7n\2\2\u01ff\u0200\7v\2"+
|
||||
"\2\u0200\u0201\7Q\2\2\u0201\u0202\7t\2\2\u0202\u0203\7P\2\2\u0203\u0204"+
|
||||
"\7w\2\2\u0204\u0205\7n\2\2\u0205\u0206\7n\2\2\u0206\u0084\3\2\2\2\u0207"+
|
||||
"\u0208\7<\2\2\u0208\u020c\t\2\2\2\u0209\u020b\t\3\2\2\u020a\u0209\3\2"+
|
||||
"\2\2\u020b\u020e\3\2\2\2\u020c\u020a\3\2\2\2\u020c\u020d\3\2\2\2\u020d"+
|
||||
"\u0217\3\2\2\2\u020e\u020c\3\2\2\2\u020f\u0213\7A\2\2\u0210\u0212\4\62"+
|
||||
";\2\u0211\u0210\3\2\2\2\u0212\u0215\3\2\2\2\u0213\u0211\3\2\2\2\u0213"+
|
||||
"\u0214\3\2\2\2\u0214\u0217\3\2\2\2\u0215\u0213\3\2\2\2\u0216\u0207\3\2"+
|
||||
"\2\2\u0216\u020f\3\2\2\2\u0217\u0086\3\2\2\2\u0218\u021c\t\2\2\2\u0219"+
|
||||
"\u021b\t\4\2\2\u021a\u0219\3\2\2\2\u021b\u021e\3\2\2\2\u021c\u021a\3\2"+
|
||||
"\2\2\u021c\u021d\3\2\2\2\u021d\u0088\3\2\2\2\u021e\u021c\3\2\2\2\u021f"+
|
||||
"\u0220\7b\2\2\u0220\u0221\5\u0087D\2\u0221\u0222\7b\2\2\u0222\u008a\3"+
|
||||
"\2\2\2\u0223\u0224\7u\2\2\u0224\u0225\7w\2\2\u0225\u0226\7o\2\2\u0226"+
|
||||
"\u0227\7*\2\2\u0227\u0228\3\2\2\2\u0228\u0229\5\u0087D\2\u0229\u022a\7"+
|
||||
"+\2\2\u022a\u024e\3\2\2\2\u022b\u022c\7o\2\2\u022c\u022d\7c\2\2\u022d"+
|
||||
"\u022e\7z\2\2\u022e\u022f\7*\2\2\u022f\u0230\3\2\2\2\u0230\u0231\5\u0087"+
|
||||
"D\2\u0231\u0232\7+\2\2\u0232\u024e\3\2\2\2\u0233\u0234\7o\2\2\u0234\u0235"+
|
||||
"\7k\2\2\u0235\u0236\7p\2\2\u0236\u0237\7*\2\2\u0237\u0238\3\2\2\2\u0238"+
|
||||
"\u0239\5\u0087D\2\u0239\u023a\7+\2\2\u023a\u024e\3\2\2\2\u023b\u023c\7"+
|
||||
"c\2\2\u023c\u023d\7x\2\2\u023d\u023e\7i\2\2\u023e\u023f\7*\2\2\u023f\u0240"+
|
||||
"\3\2\2\2\u0240\u0241\5\u0087D\2\u0241\u0242\7+\2\2\u0242\u024e\3\2\2\2"+
|
||||
"\u0243\u0244\7e\2\2\u0244\u0245\7q\2\2\u0245\u0246\7w\2\2\u0246\u0247"+
|
||||
"\7p\2\2\u0247\u0248\7v\2\2\u0248\u0249\7*\2\2\u0249\u024a\3\2\2\2\u024a"+
|
||||
"\u024b\5\u0087D\2\u024b\u024c\7+\2\2\u024c\u024e\3\2\2\2\u024d\u0223\3"+
|
||||
"\2\2\2\u024d\u022b\3\2\2\2\u024d\u0233\3\2\2\2\u024d\u023b\3\2\2\2\u024d"+
|
||||
"\u0243\3\2\2\2\u024e\u008c\3\2\2\2\u024f\u0250\7v\2\2\u0250\u0251\7t\2"+
|
||||
"\2\u0251\u0252\7w\2\2\u0252\u0259\7g\2\2\u0253\u0254\7h\2\2\u0254\u0255"+
|
||||
"\7c\2\2\u0255\u0256\7n\2\2\u0256\u0257\7u\2\2\u0257\u0259\7g\2\2\u0258"+
|
||||
"\u024f\3\2\2\2\u0258\u0253\3\2\2\2\u0259\u008e\3\2\2\2\u025a\u025c\7/"+
|
||||
"\2\2\u025b\u025a\3\2\2\2\u025b\u025c\3\2\2\2\u025c\u025d\3\2\2\2\u025d"+
|
||||
"\u0264\5\u0091I\2\u025e\u0260\7/\2\2\u025f\u025e\3\2\2\2\u025f\u0260\3"+
|
||||
"\2\2\2\u0260\u0261\3\2\2\2\u0261\u0264\5\u0093J\2\u0262\u0264\5\u0095"+
|
||||
"K\2\u0263\u025b\3\2\2\2\u0263\u025f\3\2\2\2\u0263\u0262\3\2\2\2\u0264"+
|
||||
"\u0090\3\2\2\2\u0265\u0267\t\5\2\2\u0266\u0265\3\2\2\2\u0267\u0268\3\2"+
|
||||
"\2\2\u0268\u0266\3\2\2\2\u0268\u0269\3\2\2\2\u0269\u026a\3\2\2\2\u026a"+
|
||||
"\u026e\7\60\2\2\u026b\u026d\t\5\2\2\u026c\u026b\3\2\2\2\u026d\u0270\3"+
|
||||
"\2\2\2\u026e\u026c\3\2\2\2\u026e\u026f\3\2\2\2\u026f\u0092\3\2\2\2\u0270"+
|
||||
"\u026e\3\2\2\2\u0271\u0275\t\6\2\2\u0272\u0274\t\5\2\2\u0273\u0272\3\2"+
|
||||
"\2\2\u0274\u0277\3\2\2\2\u0275\u0273\3\2\2\2\u0275\u0276\3\2\2\2\u0276"+
|
||||
"\u0094\3\2\2\2\u0277\u0275\3\2\2\2\u0278\u0279\7\62\2\2\u0279\u0096\3"+
|
||||
"\2\2\2\u027a\u0280\7)\2\2\u027b\u027f\n\7\2\2\u027c\u027d\7)\2\2\u027d"+
|
||||
"\u027f\7)\2\2\u027e\u027b\3\2\2\2\u027e\u027c\3\2\2\2\u027f\u0282\3\2"+
|
||||
"\2\2\u0280\u027e\3\2\2\2\u0280\u0281\3\2\2\2\u0281\u0283\3\2\2\2\u0282"+
|
||||
"\u0280\3\2\2\2\u0283\u0284\7)\2\2\u0284\u0098\3\2\2\2\u0285\u0286\t\b"+
|
||||
"\2\2\u0286\u0287\3\2\2\2\u0287\u0288\bM\2\2\u0288\u009a\3\2\2\2\21\2\u020c"+
|
||||
"\u0213\u0216\u021c\u024d\u0258\u025b\u025f\u0263\u0268\u026e\u0275\u027e"+
|
||||
"\u0280\3\b\2\2";
|
||||
public static final ATN _ATN =
|
||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||
static {
|
||||
|
||||
@@ -58,17 +58,22 @@ T__56=57
|
||||
T__57=58
|
||||
T__58=59
|
||||
T__59=60
|
||||
INPUT_VARIABLE=61
|
||||
PATH_VARIABLE=62
|
||||
QUOTED_PATH_VARIABLE=63
|
||||
PROP_FORMULA=64
|
||||
BOOLEAN_LITERAL=65
|
||||
NUMBER_LITERAL=66
|
||||
DOUBLE=67
|
||||
INT=68
|
||||
ZERO=69
|
||||
STRING_LITERAL=70
|
||||
WS=71
|
||||
T__60=61
|
||||
T__61=62
|
||||
T__62=63
|
||||
T__63=64
|
||||
T__64=65
|
||||
INPUT_VARIABLE=66
|
||||
PATH_VARIABLE=67
|
||||
QUOTED_PATH_VARIABLE=68
|
||||
PROP_FORMULA=69
|
||||
BOOLEAN_LITERAL=70
|
||||
NUMBER_LITERAL=71
|
||||
DOUBLE=72
|
||||
INT=73
|
||||
ZERO=74
|
||||
STRING_LITERAL=75
|
||||
WS=76
|
||||
'('=1
|
||||
')'=2
|
||||
'select'=3
|
||||
@@ -91,42 +96,47 @@ WS=71
|
||||
'or'=20
|
||||
'and'=21
|
||||
'not'=22
|
||||
'in'=23
|
||||
'between'=24
|
||||
'inrange'=25
|
||||
'inOrEmpty'=23
|
||||
'in'=24
|
||||
'between'=25
|
||||
'to'=26
|
||||
'is'=27
|
||||
'null'=28
|
||||
'isNull'=29
|
||||
'isNotNull'=30
|
||||
'notNull'=31
|
||||
'empty'=32
|
||||
'isEmpty'=33
|
||||
'isNotEmpty'=34
|
||||
'notEmpty'=35
|
||||
'like'=36
|
||||
'ilike'=37
|
||||
'contains'=38
|
||||
'icontains'=39
|
||||
'startsWith'=40
|
||||
'istartsWith'=41
|
||||
'endsWith'=42
|
||||
'iendsWith'=43
|
||||
'='=44
|
||||
'eq'=45
|
||||
'>'=46
|
||||
'gt'=47
|
||||
'>='=48
|
||||
'ge'=49
|
||||
'gte'=50
|
||||
'<'=51
|
||||
'lt'=52
|
||||
'<='=53
|
||||
'le'=54
|
||||
'lte'=55
|
||||
'<>'=56
|
||||
'!='=57
|
||||
'ne'=58
|
||||
'ieq'=59
|
||||
'ine'=60
|
||||
'0'=69
|
||||
'inrange'=27
|
||||
'inRange'=28
|
||||
'is'=29
|
||||
'null'=30
|
||||
'isNull'=31
|
||||
'isNotNull'=32
|
||||
'notNull'=33
|
||||
'empty'=34
|
||||
'isEmpty'=35
|
||||
'isNotEmpty'=36
|
||||
'notEmpty'=37
|
||||
'like'=38
|
||||
'ilike'=39
|
||||
'contains'=40
|
||||
'icontains'=41
|
||||
'startsWith'=42
|
||||
'istartsWith'=43
|
||||
'endsWith'=44
|
||||
'iendsWith'=45
|
||||
'='=46
|
||||
'eq'=47
|
||||
'>'=48
|
||||
'gt'=49
|
||||
'>='=50
|
||||
'ge'=51
|
||||
'gte'=52
|
||||
'<'=53
|
||||
'lt'=54
|
||||
'<='=55
|
||||
'le'=56
|
||||
'lte'=57
|
||||
'<>'=58
|
||||
'!='=59
|
||||
'ne'=60
|
||||
'ieq'=61
|
||||
'ine'=62
|
||||
'eqOrNull'=63
|
||||
'gtOrNull'=64
|
||||
'ltOrNull'=65
|
||||
'0'=74
|
||||
|
||||
@@ -287,6 +287,16 @@ public interface EQLListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitAny_expression(EQLParser.Any_expressionContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link EQLParser#inOrEmpty_expression}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by {@link EQLParser#inOrEmpty_expression}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitInOrEmpty_expression(EQLParser.InOrEmpty_expressionContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link EQLParser#in_expression}.
|
||||
* @param ctx the parse tree
|
||||
@@ -327,6 +337,16 @@ public interface EQLListener extends ParseTreeListener {
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitInrange_expression(EQLParser.Inrange_expressionContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link EQLParser#inrange_op}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void enterInrange_op(EQLParser.Inrange_opContext ctx);
|
||||
/**
|
||||
* Exit a parse tree produced by {@link EQLParser#inrange_op}.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
void exitInrange_op(EQLParser.Inrange_opContext ctx);
|
||||
/**
|
||||
* Enter a parse tree produced by {@link EQLParser#propertyBetween_expression}.
|
||||
* @param ctx the parse tree
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
/**
|
||||
* Base class for Bean and BeanCollection loading (lazy loading and query join loading).
|
||||
*/
|
||||
public abstract class DLoadBaseContext {
|
||||
abstract class DLoadBaseContext {
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
@@ -18,22 +18,21 @@ public abstract class DLoadBaseContext {
|
||||
|
||||
protected final String fullPath;
|
||||
|
||||
protected final OrmQueryProperties queryProps;
|
||||
|
||||
protected final boolean hitCache;
|
||||
|
||||
protected final String serverName;
|
||||
|
||||
protected final int firstBatchSize;
|
||||
final OrmQueryProperties queryProps;
|
||||
|
||||
protected final int secondaryBatchSize;
|
||||
final boolean hitCache;
|
||||
|
||||
protected final ObjectGraphNode objectGraphNode;
|
||||
final int firstBatchSize;
|
||||
|
||||
protected final boolean queryFetch;
|
||||
final int secondaryBatchSize;
|
||||
|
||||
final ObjectGraphNode objectGraphNode;
|
||||
|
||||
public DLoadBaseContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
final boolean queryFetch;
|
||||
|
||||
DLoadBaseContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
this.parent = parent;
|
||||
this.serverName = parent.getEbeanServer().getName();
|
||||
@@ -86,13 +85,11 @@ public abstract class DLoadBaseContext {
|
||||
|
||||
String label = parent.getPlanLabel();
|
||||
if (label != null) {
|
||||
label += "_" + fullPath;
|
||||
query.setLabel(label);
|
||||
query.setProfileLocation(parent.getProfileLocation());
|
||||
query.setProfilePath(label, fullPath, parent.getProfileLocation());
|
||||
}
|
||||
}
|
||||
|
||||
protected PersistenceContext getPersistenceContext() {
|
||||
PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
@@ -16,19 +17,22 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default implementation of LoadBeanContext.
|
||||
* ToOne bean load context.
|
||||
*/
|
||||
public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
|
||||
private final boolean cache;
|
||||
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.cache = (queryProps == null) ? false : queryProps.isCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +45,11 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
|
||||
protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
private void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
|
||||
if (cache) {
|
||||
query.setBeanCacheMode(CacheMode.ON);
|
||||
}
|
||||
setLabel(query);
|
||||
parent.propagateQueryState(query, desc.isDocStoreMapped());
|
||||
query.setParentNode(objectGraphNode);
|
||||
@@ -79,8 +86,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
LoadBeanRequest req = new LoadBeanRequest(loadBuffer, parentRequest);
|
||||
parent.getEbeanServer().loadBean(req);
|
||||
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
@@ -97,18 +103,17 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A buffer for batch loading beans on a given path.
|
||||
*/
|
||||
public static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
public LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<>(batchSize);
|
||||
@@ -186,7 +191,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
}
|
||||
}
|
||||
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, ebi.getLazyLoadProperty(), context.hitCache);
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, ebi, context.hitCache);
|
||||
context.desc.getEbeanServer().loadBean(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.ebeaninternal.server.loadcontext;
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.ObjectGraphOrigin;
|
||||
@@ -94,8 +94,8 @@ public class DLoadContext implements LoadContext {
|
||||
}
|
||||
|
||||
private ObjectGraphOrigin initOrigin() {
|
||||
CallStack callStack = ebeanServer.createCallStack();
|
||||
return new ObjectGraphOrigin(0, callStack, rootDescriptor.getFullName());
|
||||
CallOrigin callOrigin = ebeanServer.createCallOrigin();
|
||||
return new ObjectGraphOrigin(0, callOrigin, rootDescriptor.getFullName());
|
||||
}
|
||||
|
||||
public DLoadContext(OrmQueryRequest<?> request, SpiQuerySecondary secondaryQueries) {
|
||||
@@ -224,10 +224,7 @@ public class DLoadContext implements LoadContext {
|
||||
*/
|
||||
private LoadSecondaryQuery getLoadSecondaryQuery(String path) {
|
||||
LoadSecondaryQuery beanLoad = beanMap.get(path);
|
||||
if (beanLoad == null) {
|
||||
beanLoad = manyMap.get(path);
|
||||
}
|
||||
return beanLoad;
|
||||
return beanLoad == null ? manyMap.get(path) : beanLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,10 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
/**
|
||||
* ToMany bean load context.
|
||||
*/
|
||||
class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
protected final BeanPropertyAssocMany<?> property;
|
||||
|
||||
@@ -27,7 +30,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
|
||||
DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
|
||||
String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
|
||||
@@ -57,7 +60,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query) {
|
||||
private void configureQuery(SpiQuery<?> query) {
|
||||
|
||||
setLabel(query);
|
||||
parent.propagateQueryState(query, docStoreMapped);
|
||||
@@ -122,14 +125,14 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
* A buffer for batch loading bean collections on a given path.
|
||||
* Supports batch lazy loading and secondary query loading.
|
||||
*/
|
||||
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final PersistenceContext persistenceContext;
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
private final List<BeanCollection<?>> list;
|
||||
|
||||
public LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
this.context = context;
|
||||
// set the persistence context as at this moment in
|
||||
// case it changes as part of a findIterate etc
|
||||
|
||||
@@ -43,6 +43,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
|
||||
|
||||
/**
|
||||
* Persister implementation using DML.
|
||||
* <p>
|
||||
@@ -1227,11 +1229,9 @@ public final class DefaultPersister implements Persister {
|
||||
EntityBean bean = request.getEntityBean();
|
||||
Object uid = idProp.getValue(bean);
|
||||
|
||||
if (DmlUtil.isNullOrZero(uid)) {
|
||||
|
||||
if (isNullOrZero(uid)) {
|
||||
// generate the nextId and set it to the property
|
||||
Object nextId = desc.nextId(request.getTransaction());
|
||||
|
||||
// cast the data type if required and set it
|
||||
desc.convertSetId(nextId, bean);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
|
||||
|
||||
/**
|
||||
* Saves the details for a OneToMany or ManyToMany relationship (entity beans).
|
||||
*/
|
||||
@@ -222,7 +224,7 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
}
|
||||
if (detailBean instanceof EntityBean) {
|
||||
Object id = targetDescriptor.getId((EntityBean) detailBean);
|
||||
if (!DmlUtil.isNullOrZero(id)) {
|
||||
if (!isNullOrZero(id)) {
|
||||
// remember the Id (other details not in the collection) will be removed
|
||||
detailIds.add(id);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.server.core.Message;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.persist.DmlUtil;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
@@ -15,6 +14,8 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static io.ebeaninternal.server.persist.DmlUtil.isNullOrZero;
|
||||
|
||||
/**
|
||||
* Insert bean handler.
|
||||
*/
|
||||
@@ -66,7 +67,7 @@ public class InsertHandler extends DmlHandler {
|
||||
|
||||
Object idValue = desc.getId(bean);
|
||||
|
||||
boolean withId = !DmlUtil.isNullOrZero(idValue);
|
||||
boolean withId = !isNullOrZero(idValue);
|
||||
|
||||
// check to see if we are going to use generated keys
|
||||
if (!withId) {
|
||||
|
||||
@@ -11,6 +11,8 @@ import io.ebeaninternal.server.querydefn.SpiFetchGroup;
|
||||
*/
|
||||
class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
|
||||
private static final FetchConfig FETCH_CACHE = new FetchConfig().cache();
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
@@ -61,6 +63,12 @@ class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchCache(String path) {
|
||||
detail.fetch(path, null, FETCH_CACHE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchLazy(String path) {
|
||||
detail.fetch(path, null, FETCH_LAZY);
|
||||
@@ -79,6 +87,12 @@ class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchCache(String path, String properties) {
|
||||
detail.fetch(path, properties, FETCH_CACHE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchGroupBuilder<T> fetchLazy(String path, String properties) {
|
||||
detail.fetch(path, properties, FETCH_LAZY);
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.FetchGroup;
|
||||
import io.ebean.FetchGroupBuilder;
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebean.service.SpiFetchGroupService;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
|
||||
@@ -20,6 +21,11 @@ public final class DFetchGroupService implements SpiFetchGroupService {
|
||||
return new DFetchGroupBuilder<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SpiFetchGroupQuery<T> queryFor(Class<T> beanType) {
|
||||
return new DefaultFetchGroupQuery<>();
|
||||
}
|
||||
|
||||
private OrmQueryDetail detail(String select) {
|
||||
OrmQueryDetail detail = new OrmQueryDetail();
|
||||
detail.select(select);
|
||||
|
||||
@@ -0,0 +1,592 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.CountDistinctOrder;
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.FetchGroup;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.FutureIds;
|
||||
import io.ebean.FutureList;
|
||||
import io.ebean.FutureRowCount;
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.PagedList;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.QueryIterator;
|
||||
import io.ebean.QueryType;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.UpdateQuery;
|
||||
import io.ebean.Version;
|
||||
import io.ebean.service.SpiFetchGroupQuery;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Implementation of FetchGroup query for use to create FetchGroup via query beans.
|
||||
*/
|
||||
class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T> {
|
||||
|
||||
private static final FetchConfig FETCH_CACHE = new FetchConfig().cache();
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
|
||||
private OrmQueryDetail detail = new OrmQueryDetail();
|
||||
|
||||
@Override
|
||||
public FetchGroup<T> buildFetchGroup() {
|
||||
return new DFetchGroup<>(detail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> select(String columns) {
|
||||
detail.select(columns);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> select(FetchGroup fetchGroup) {
|
||||
this.detail = ((SpiFetchGroup) fetchGroup).detail();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetch(String property) {
|
||||
return fetch(property, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchQuery(String property) {
|
||||
return fetch(property, null, FETCH_QUERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchCache(String property) {
|
||||
return fetch(property, null, FETCH_CACHE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchLazy(String property) {
|
||||
return fetch(property, null, FETCH_LAZY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetch(String property, FetchConfig joinConfig) {
|
||||
return fetch(property, null, joinConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetch(String property, String columns) {
|
||||
return fetch(property, columns, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchQuery(String property, String columns) {
|
||||
return fetch(property, columns, FETCH_QUERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchCache(String property, String columns) {
|
||||
return fetch(property, columns, FETCH_CACHE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchLazy(String property, String columns) {
|
||||
return fetch(property, columns, FETCH_LAZY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetch(String property, String columns, FetchConfig config) {
|
||||
detail.fetch(property, columns, config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setProfileId(int profileId) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setProfileLocation(ProfileLocation profileLocation) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setLabel(String label) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Everything else deemed invalid
|
||||
|
||||
@Override
|
||||
public Query<T> copy() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setRawSql(RawSql rawSql) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> asOf(Timestamp asOf) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> asDraft() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <D> DtoQuery<D> asDto(Class<D> dtoClass) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateQuery<T> asUpdate() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setPersistenceContextScope(PersistenceContextScope scope) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setDocIndexName(String indexName) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTuned() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setAutoTune(boolean autoTune) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setAllowLoadErrors() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setIncludeSoftDeletes() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setDisableReadAuditing() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> apply(FetchPath fetchPath) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> usingTransaction(Transaction transaction) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> usingConnection(Connection connection) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <A> List<A> findIds() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEach(Consumer<T> consumer) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEachWhile(Predicate<T> consumer) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<T> findList() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<T> findSet() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <K> Map<K, T> findMap() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> A findSingleAttribute() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCountDistinct() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T findOne() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<T> findOneOrEmpty() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Version<T>> findVersions() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Transaction transaction) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Transaction transaction) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findCount() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FutureIds<T> findFutureIds() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FutureList<T> findFutureList() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PagedList<T> findPagedList() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setParameter(String name, Object value) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setParameter(int position, Object value) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setId(Object id) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getId() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> where(Expression expression) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> where() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> text() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> filterMany(String propertyName) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> having() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> having(Expression addExpressionToHaving) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> orderBy(String orderByClause) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> order(String orderByClause) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderBy<T> order() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderBy<T> orderBy() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setOrder(OrderBy<T> orderBy) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setOrderBy(OrderBy<T> orderBy) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setDistinct(boolean isDistinct) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setCountDistinct(CountDistinctOrder orderBy) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstRow() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setFirstRow(int firstRow) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setMaxRows(int maxRows) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setMapKey(String mapKey) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setBeanCacheMode(CacheMode beanCacheMode) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setUseQueryCache(CacheMode queryCacheMode) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setUseDocStore(boolean useDocStore) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setReadOnly(boolean readOnly) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setLoadBeanCache(boolean loadBeanCache) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setTimeout(int secs) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setBufferFetchSizeHint(int fetchSize) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGeneratedSql() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForUpdate getForUpdateMode() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> alias(String alias) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setBaseTable(String baseTable) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getBeanType() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setInheritType(Class<? extends T> type) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends T> getInheritType() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryType getQueryType() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setDisableLazyLoading(boolean disableLazyLoading) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> validate() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> orderById(boolean orderById) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user