mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#566 - Refactor internals - SpiExpression, add prepareExpression() to merge queryAutoTuneHash() and queryPlanHash() - sameByPlan() & sameByBind()
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
/**
|
||||
* Key used for caching query plans for ORM and RawSql queries.
|
||||
*/
|
||||
public interface CQueryPlanKey {
|
||||
|
||||
/**
|
||||
* Used by read audit such that we can log read audit entries without the full sql
|
||||
* (which would make the read audit logs verbose).
|
||||
*/
|
||||
String getPartialKey();
|
||||
|
||||
}
|
||||
@@ -5,32 +5,18 @@ package com.avaje.ebeaninternal.api;
|
||||
*/
|
||||
public class HashQuery {
|
||||
|
||||
private final HashQueryPlan planHash;
|
||||
private final CQueryPlanKey planHash;
|
||||
|
||||
private final int bindHash;
|
||||
|
||||
/**
|
||||
* Create the HashQuery.
|
||||
*/
|
||||
public HashQuery(HashQueryPlan planHash, int bindHash) {
|
||||
public HashQuery(CQueryPlanKey planHash, int bindHash) {
|
||||
this.planHash = planHash;
|
||||
this.bindHash = bindHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query plan hash.
|
||||
*/
|
||||
public HashQueryPlan getPlanHash() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind values hash.
|
||||
*/
|
||||
public int getBindHash() {
|
||||
return bindHash;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * planHash.hashCode();
|
||||
hc = 31 * hc + bindHash;
|
||||
|
||||
@@ -9,14 +9,12 @@ public class HashQueryPlanBuilder {
|
||||
|
||||
private int bindCount;
|
||||
|
||||
private String rawSql;
|
||||
|
||||
public HashQueryPlanBuilder() {
|
||||
this.planHash = 92821;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return planHash+":"+bindCount+(rawSql != null ? ":r" : "");
|
||||
return planHash+":"+bindCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,19 +56,24 @@ public class HashQueryPlanBuilder {
|
||||
bindCount += extraBindCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw sql to the hash.
|
||||
*/
|
||||
public void addRawSql(String rawSql) {
|
||||
this.rawSql = rawSql;
|
||||
public void bindIfNotNull(Object someValue) {
|
||||
if (someValue != null) {
|
||||
bindCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the calculated HashQueryPlan.
|
||||
*/
|
||||
public HashQueryPlan build() {
|
||||
return new HashQueryPlan(rawSql, planHash, bindCount);
|
||||
public String build() {
|
||||
return planHash+"_"+bindCount;
|
||||
}
|
||||
|
||||
|
||||
public int getPlanHash() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
public int getBindCount() {
|
||||
return bindCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,16 @@ public interface SpiExpression extends Expression {
|
||||
*/
|
||||
int queryBindHash();
|
||||
|
||||
/**
|
||||
* Return true if the expression is the same without taking into account bind values.
|
||||
*/
|
||||
boolean isSameByPlan(SpiExpression other);
|
||||
|
||||
/**
|
||||
* Return true if the expression is the same with respect to bind values.
|
||||
*/
|
||||
boolean isSameByBind(SpiExpression other);
|
||||
|
||||
/**
|
||||
* Add some sql to the query.
|
||||
* <p>
|
||||
@@ -65,4 +75,10 @@ public interface SpiExpression extends Expression {
|
||||
* Validate all the properties/paths associated with this expression.
|
||||
*/
|
||||
void validate(SpiExpressionValidation validation);
|
||||
|
||||
/**
|
||||
* Return a copy of the expression for use in the query plan key.
|
||||
*/
|
||||
SpiExpression copyForPlanKey();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Internal extension of ExpressionList.
|
||||
*/
|
||||
public interface SpiExpressionList<T> extends ExpressionList<T> {
|
||||
public interface SpiExpressionList<T> extends ExpressionList<T>, SpiExpression {
|
||||
|
||||
/**
|
||||
* Return the underlying list of expressions.
|
||||
@@ -22,57 +19,9 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
|
||||
*/
|
||||
SpiExpressionList<?> trimPath(int prefixTrim);
|
||||
|
||||
/**
|
||||
* Restore the ExpressionFactory after deserialisation.
|
||||
*/
|
||||
void setExpressionFactory(ExpressionFactory expr);
|
||||
|
||||
/**
|
||||
* Process "Many" properties populating ManyWhereJoins.
|
||||
* <p>
|
||||
* Predicates on Many properties require an extra independent join clause.
|
||||
* </p>
|
||||
*/
|
||||
void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
|
||||
|
||||
/**
|
||||
* Return true if this list is empty.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Concatenate the expression sql into a String.
|
||||
* <p>
|
||||
* The list of expressions are evaluated in order building a sql statement
|
||||
* with bind parameters.
|
||||
* </p>
|
||||
*/
|
||||
String buildSql(SpiExpressionRequest request);
|
||||
|
||||
/**
|
||||
* Combine the expression bind values into a list.
|
||||
* <p>
|
||||
* Expressions are evaluated in order and all the resulting bind values are
|
||||
* returned as a List.
|
||||
* </p>
|
||||
*
|
||||
* @return the list of all the bind values in order.
|
||||
*/
|
||||
List<Object> buildBindValues(SpiExpressionRequest request);
|
||||
|
||||
/**
|
||||
* Prepare the expressions contained in the list. For example, compile sub-query expressions etc.
|
||||
*/
|
||||
void prepareExpression(BeanQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the expressions but excluding the actual bind
|
||||
* values.
|
||||
*/
|
||||
void queryPlanHash(HashQueryPlanBuilder builder);
|
||||
|
||||
/**
|
||||
* Validate all the properties/paths used in this expression list.
|
||||
*/
|
||||
void validate(SpiExpressionValidation validation);
|
||||
}
|
||||
|
||||
@@ -467,17 +467,13 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Identifies queries that are the same bar the bind variables.
|
||||
* Prepare the query which prepares sub-query expressions and calculates
|
||||
* and returns the query plan key.
|
||||
* <p>
|
||||
* This is used AFTER AutoTune has potentially tuned the query. This is
|
||||
* used to identify and reused query plans (the final SQL string and
|
||||
* associated SqlTree object).
|
||||
* </p>
|
||||
* <p>
|
||||
* Excludes the actual bind values (as they don't effect the query plan).
|
||||
* The query plan excludes actual bind values (as they don't effect the query plan).
|
||||
* </p>
|
||||
*/
|
||||
HashQueryPlan queryPlanHash(BeanQueryRequest<?> request);
|
||||
CQueryPlanKey prepare(BeanQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the bind values used in the query.
|
||||
|
||||
@@ -1110,7 +1110,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
// the query hash after any tuning
|
||||
request.calculateQueryPlanHash();
|
||||
request.prepareQuery();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
@@ -16,8 +13,8 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Type;
|
||||
@@ -32,6 +29,13 @@ import com.avaje.ebeaninternal.server.query.CQueryPlan;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a Query.
|
||||
*/
|
||||
@@ -55,7 +59,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
private HashQuery cacheKey;
|
||||
|
||||
private HashQueryPlan queryPlanHash;
|
||||
private CQueryPlanKey queryPlanKey;
|
||||
|
||||
/**
|
||||
* Create the InternalQueryRequest.
|
||||
@@ -126,10 +130,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the query plan hash AFTER any potential AutoTune tuning.
|
||||
* Prepare the query and calculate the query plan key.
|
||||
*/
|
||||
public void calculateQueryPlanHash() {
|
||||
this.queryPlanHash = query.queryPlanHash(this);
|
||||
public void prepareQuery() {
|
||||
this.queryPlanKey = query.prepare(this);
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
@@ -355,7 +359,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* query plan for this query exists.
|
||||
*/
|
||||
public CQueryPlan getQueryPlan() {
|
||||
return beanDescriptor.getQueryPlan(queryPlanHash);
|
||||
return beanDescriptor.getQueryPlan(queryPlanKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,15 +370,15 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* with just the bind variables changing.
|
||||
* </p>
|
||||
*/
|
||||
public HashQueryPlan getQueryPlanHash() {
|
||||
return queryPlanHash;
|
||||
public CQueryPlanKey getQueryPlanKey() {
|
||||
return queryPlanKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the QueryPlan into the cache.
|
||||
*/
|
||||
public void putQueryPlan(CQueryPlan queryPlan) {
|
||||
beanDescriptor.putQueryPlan(queryPlanHash, queryPlan);
|
||||
beanDescriptor.putQueryPlan(queryPlanKey, queryPlan);
|
||||
}
|
||||
|
||||
public boolean isUseBeanCache() {
|
||||
@@ -401,7 +405,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
for (T bean : actualDetails) {
|
||||
ids.add(beanDescriptor.getIdForJson(bean));
|
||||
}
|
||||
beanDescriptor.readAuditMany(queryPlanHash.getPartialKey(), "l2-query-cache", ids);
|
||||
beanDescriptor.readAuditMany(queryPlanKey.getPartialKey(), "l2-query-cache", ids);
|
||||
}
|
||||
|
||||
return cached;
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.avaje.ebean.event.readaudit.ReadEvent;
|
||||
import com.avaje.ebean.meta.MetaBeanInfo;
|
||||
import com.avaje.ebean.meta.MetaQueryPlanStatistic;
|
||||
import com.avaje.ebean.plugin.SpiBeanType;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
@@ -87,7 +87,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
|
||||
|
||||
private final ConcurrentHashMap<Integer, SpiUpdatePlan> updatePlanCache = new ConcurrentHashMap<Integer, SpiUpdatePlan>();
|
||||
|
||||
private final ConcurrentHashMap<HashQueryPlan, CQueryPlan> queryPlanCache = new ConcurrentHashMap<HashQueryPlan, CQueryPlan>();
|
||||
private final ConcurrentHashMap<CQueryPlanKey, CQueryPlan> queryPlanCache = new ConcurrentHashMap<CQueryPlanKey, CQueryPlan>();
|
||||
|
||||
private final ConcurrentHashMap<String, ElPropertyValue> elCache = new ConcurrentHashMap<String, ElPropertyValue>();
|
||||
|
||||
@@ -1163,11 +1163,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public CQueryPlan getQueryPlan(HashQueryPlan key) {
|
||||
public CQueryPlan getQueryPlan(CQueryPlanKey key) {
|
||||
return queryPlanCache.get(key);
|
||||
}
|
||||
|
||||
public void putQueryPlan(HashQueryPlan key, CQueryPlan plan) {
|
||||
public void putQueryPlan(CQueryPlanKey key, CQueryPlan plan) {
|
||||
queryPlanCache.put(key, plan);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.expression.IdInExpression;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionRequest;
|
||||
|
||||
public class IntersectionRow {
|
||||
|
||||
|
||||
@@ -63,6 +63,32 @@ public final class TableJoin {
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TableJoin that = (TableJoin) o;
|
||||
|
||||
if (!table.equals(that.table)) return false;
|
||||
if (type != that.type) return false;
|
||||
if (columns.length != that.columns.length) return false;
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
if (!columns[i].equals(that.columns[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return a hash value for adding to a query plan.
|
||||
*/
|
||||
|
||||
@@ -8,76 +8,97 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
*/
|
||||
public class TableJoinColumn {
|
||||
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
private final String localDbColumn;
|
||||
/**
|
||||
* The local database column name.
|
||||
*/
|
||||
private final String localDbColumn;
|
||||
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
private final String foreignDbColumn;
|
||||
/**
|
||||
* The foreign database column name.
|
||||
*/
|
||||
private final String foreignDbColumn;
|
||||
|
||||
private final boolean insertable;
|
||||
|
||||
private final boolean updateable;
|
||||
private final boolean insertable;
|
||||
|
||||
/**
|
||||
* Hash for including in a query plan
|
||||
*/
|
||||
private final int queryHash;
|
||||
private final boolean updateable;
|
||||
|
||||
/**
|
||||
* Create the pair.
|
||||
*/
|
||||
public TableJoinColumn(DeployTableJoinColumn deploy) {
|
||||
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
|
||||
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
|
||||
this.insertable = deploy.isInsertable();
|
||||
this.updateable = deploy.isUpdateable();
|
||||
this.queryHash = hashOf(localDbColumn) * 31 + hashOf(foreignDbColumn);
|
||||
}
|
||||
/**
|
||||
* Hash for including in a query plan
|
||||
*/
|
||||
private final int queryHash;
|
||||
|
||||
private int hashOf(String value) {
|
||||
return (value == null) ? 0 : value.hashCode();
|
||||
}
|
||||
/**
|
||||
* Create the pair.
|
||||
*/
|
||||
public TableJoinColumn(DeployTableJoinColumn deploy) {
|
||||
this.localDbColumn = InternString.intern(deploy.getLocalDbColumn());
|
||||
this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn());
|
||||
this.insertable = deploy.isInsertable();
|
||||
this.updateable = deploy.isUpdateable();
|
||||
this.queryHash = hash();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return localDbColumn+" = "+foreignDbColumn;
|
||||
}
|
||||
int hash() {
|
||||
int result = localDbColumn != null ? localDbColumn.hashCode() : 0;
|
||||
result = 31 * result + (foreignDbColumn != null ? foreignDbColumn.hashCode() : 0);
|
||||
result = 31 * result + (insertable ? 1 : 0);
|
||||
result = 31 * result + (updateable ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for including in a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
TableJoinColumn that = (TableJoinColumn) o;
|
||||
if (insertable != that.insertable) return false;
|
||||
if (updateable != that.updateable) return false;
|
||||
if (!localDbColumn.equals(that.localDbColumn)) return false;
|
||||
return foreignDbColumn.equals(that.foreignDbColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
public String toString() {
|
||||
return localDbColumn + " = " + foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
/**
|
||||
* Return a hash for including in a query plan.
|
||||
*/
|
||||
public int queryHash() {
|
||||
return queryHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign database column name.
|
||||
*/
|
||||
public String getForeignDbColumn() {
|
||||
return foreignDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local database column name.
|
||||
*/
|
||||
public String getLocalDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be insertable.
|
||||
*/
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this column should be updateable.
|
||||
*/
|
||||
public boolean isUpdateable() {
|
||||
return updateable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,20 @@ public abstract class AbstractExpression implements SpiExpression {
|
||||
this.propName = propName;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propName;
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
if (propertyName != null) {
|
||||
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propertyName);
|
||||
if (propName != null) {
|
||||
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propName);
|
||||
if (elProp != null) {
|
||||
if (elProp.containsFormulaWithJoin()) {
|
||||
// for findRowCount query select clause
|
||||
manyWhereJoin.addFormulaWithJoin(propertyName);
|
||||
manyWhereJoin.addFormulaWithJoin(propName);
|
||||
}
|
||||
if (elProp.containsMany()) {
|
||||
// for findRowCount we join to a many property
|
||||
@@ -51,12 +52,11 @@ public abstract class AbstractExpression implements SpiExpression {
|
||||
|
||||
@Override
|
||||
public void validate(SpiExpressionValidation validation) {
|
||||
validation.validate(getPropertyName());
|
||||
validation.validate(propName);
|
||||
}
|
||||
|
||||
protected ElPropertyValue getElProp(SpiExpressionRequest request) {
|
||||
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
return request.getBeanDescriptor().getElGetValue(propertyName);
|
||||
return request.getBeanDescriptor().getElGetValue(propName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -102,7 +104,7 @@ class AllEqualsExpression extends NonPrepareExpression {
|
||||
Object value = entry.getValue();
|
||||
String propName = entry.getKey();
|
||||
builder.add(propName).add(value == null ? 0 : 1);
|
||||
builder.bind(value == null ? 0 : 1);
|
||||
builder.bindIfNotNull(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,4 +118,48 @@ class AllEqualsExpression extends NonPrepareExpression {
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof AllEqualsExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AllEqualsExpression that = (AllEqualsExpression) other;
|
||||
return isSameByValue(that, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
if (!(other instanceof AllEqualsExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AllEqualsExpression that = (AllEqualsExpression) other;
|
||||
return isSameByValue(that, true);
|
||||
}
|
||||
|
||||
private boolean isSameByValue(AllEqualsExpression that, boolean byValue) {
|
||||
|
||||
if (propMap.size() != that.propMap.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Iterator<Entry<String, Object>> thisIt = propMap.entrySet().iterator();
|
||||
Iterator<Entry<String, Object>> thatIt = that.propMap.entrySet().iterator();
|
||||
|
||||
while (thisIt.hasNext() && thatIt.hasNext()) {
|
||||
Entry<String, Object> thisNext = thisIt.next();
|
||||
Entry<String, Object> thatNext = thatIt.next();
|
||||
|
||||
if (!thisNext.getKey().equals(thatNext.getKey())) {
|
||||
return false;
|
||||
}
|
||||
if (!Same.sameBy(byValue, thisNext.getValue(), thatNext.getValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
|
||||
class BetweenExpression extends AbstractExpression {
|
||||
|
||||
private static final long serialVersionUID = 2078918165221454910L;
|
||||
@@ -30,7 +29,7 @@ class BetweenExpression extends AbstractExpression {
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
request.append(getPropertyName()).append(BETWEEN).append(" ? and ? ");
|
||||
request.append(propName).append(BETWEEN).append(" ? and ? ");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,4 +44,21 @@ class BetweenExpression extends AbstractExpression {
|
||||
hc = hc * 31 + valueHigh.hashCode();
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof BetweenExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BetweenExpression that = (BetweenExpression) other;
|
||||
return this.propName.equals(that.propName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
BetweenExpression that = (BetweenExpression) other;
|
||||
return valueLow.equals(that.valueLow)
|
||||
&& valueHigh.equals(that.valueHigh);
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -50,6 +51,7 @@ class BetweenPropertyExpression extends NonPrepareExpression {
|
||||
validation.validate(highProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
request.addBindValue(value);
|
||||
}
|
||||
@@ -70,4 +72,21 @@ class BetweenPropertyExpression extends NonPrepareExpression {
|
||||
public int queryBindHash() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof BetweenPropertyExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BetweenPropertyExpression that = (BetweenPropertyExpression) other;
|
||||
return lowProperty.equals(that.lowProperty)
|
||||
&& highProperty.equals(that.highProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
BetweenPropertyExpression that = (BetweenPropertyExpression) other;
|
||||
return value.equals(that.value);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-5
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -16,6 +16,7 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
|
||||
this.value = value.toLowerCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
@@ -28,14 +29,13 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
|
||||
request.addBindValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
String pname = propertyName;
|
||||
|
||||
String pname = propName;
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
pname = prop.getBeanProperty().getDecryptProperty(propertyName);
|
||||
pname = prop.getBeanProperty().getDecryptProperty(propName);
|
||||
}
|
||||
|
||||
request.append("lower(").append(pname).append(") =? ");
|
||||
@@ -51,4 +51,20 @@ class CaseInsensitiveEqualExpression extends AbstractExpression {
|
||||
public int queryBindHash() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof CaseInsensitiveEqualExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CaseInsensitiveEqualExpression that = (CaseInsensitiveEqualExpression) other;
|
||||
return this.propName.equals(that.propName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
CaseInsensitiveEqualExpression that = (CaseInsensitiveEqualExpression) other;
|
||||
return value.equals(that.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,19 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
|
||||
this.likeType = likeType;
|
||||
}
|
||||
|
||||
DefaultExampleExpression(ArrayList<SpiExpression> source) {
|
||||
this.entity = null;
|
||||
this.list = new ArrayList<SpiExpression>(source.size());
|
||||
for (SpiExpression expression : source) {
|
||||
list.add(expression.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new DefaultExampleExpression(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
|
||||
if (list != null) {
|
||||
@@ -201,6 +214,38 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof DefaultExampleExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultExampleExpression that = (DefaultExampleExpression) other;
|
||||
if (this.list.size() != that.list.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (!list.get(i).isSameByPlan(that.list.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
DefaultExampleExpression that = (DefaultExampleExpression) other;
|
||||
if (this.list.size() != that.list.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (!list.get(i).isSameByBind(that.list.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the List of expressions.
|
||||
*/
|
||||
|
||||
+49
-19
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebeaninternal.util;
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
@@ -56,6 +56,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
this.listAndJoin = " and ";
|
||||
}
|
||||
|
||||
private DefaultExpressionList() {
|
||||
this(null, null, null, new ArrayList<SpiExpression>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpressionList<?> trimPath(int prefixTrim) {
|
||||
throw new RuntimeException("Only allowed on FilterExpressionList");
|
||||
@@ -65,17 +69,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ExpressionFactory.
|
||||
* <p>
|
||||
* After deserialisation so that it can be further modified.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void setExpressionFactory(ExpressionFactory expr) {
|
||||
this.expr = expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the expression list.
|
||||
* <p>
|
||||
@@ -88,6 +81,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return copy;
|
||||
}
|
||||
|
||||
public DefaultExpressionList<T> copyForPlanKey() {
|
||||
DefaultExpressionList<T> copy = new DefaultExpressionList<T>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
copy.list.add(list.get(i).copyForPlanKey());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if one of the expressions is related to a Many property.
|
||||
*/
|
||||
@@ -325,7 +326,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildSql(SpiExpressionRequest request) {
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
request.append(listAndStart);
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
@@ -336,17 +337,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
expression.addSql(request);
|
||||
}
|
||||
request.append(listAndEnd);
|
||||
return request.getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> buildBindValues(SpiExpressionRequest request) {
|
||||
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
SpiExpression expression = list.get(i);
|
||||
expression.addBindValues(request);
|
||||
list.get(i).addBindValues(request);
|
||||
}
|
||||
return request.getBindValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -371,6 +368,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
/**
|
||||
* Calculate a hash based on the expressions.
|
||||
*/
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hash = DefaultExpressionList.class.getName().hashCode();
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
@@ -379,6 +377,38 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof DefaultExpressionList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultExpressionList<?> that = (DefaultExpressionList<?>)other;
|
||||
if (list.size() != that.list.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
if (!list.get(i).isSameByPlan(that.list.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
DefaultExpressionList<?> that = (DefaultExpressionList<?>)other;
|
||||
if (list.size() != that.list.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
if (!list.get(i).isSameByBind(that.list.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
+14
-3
@@ -1,4 +1,4 @@
|
||||
package com.avaje.ebeaninternal.util;
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -40,7 +40,7 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
this.binder = binder;
|
||||
this.expressionList = expressionList;
|
||||
// immediately build the list of bind values (callback style)
|
||||
expressionList.buildBindValues(this);
|
||||
expressionList.addBindValues(this);
|
||||
}
|
||||
|
||||
public DefaultExpressionRequest(BeanDescriptor<?> beanDescriptor) {
|
||||
@@ -55,7 +55,8 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
* Build sql for the underlying expression list.
|
||||
*/
|
||||
public String buildSql() {
|
||||
return expressionList.buildSql(this);
|
||||
expressionList.addSql(this);
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,10 +72,12 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonExpressionHandler getJsonHandler() {
|
||||
return binder.getJsonExpressionHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseDeploy(String logicalProp) {
|
||||
|
||||
String s = deployParser.getDeployWord(logicalProp);
|
||||
@@ -94,14 +97,17 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
/**
|
||||
* Increments the parameter index and returns that value.
|
||||
*/
|
||||
@Override
|
||||
public int nextParameter() {
|
||||
return ++paramIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiOrmQueryRequest<?> getQueryRequest() {
|
||||
return queryRequest;
|
||||
}
|
||||
@@ -109,16 +115,19 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
/**
|
||||
* Append text the underlying sql expression.
|
||||
*/
|
||||
@Override
|
||||
public SpiExpressionRequest append(String sqlExpression) {
|
||||
sql.append(sqlExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindEncryptKey(Object bindValue) {
|
||||
bindValues.add(bindValue);
|
||||
bindLog("****");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValue(Object bindValue) {
|
||||
bindValues.add(bindValue);
|
||||
bindLog(bindValue);
|
||||
@@ -137,10 +146,12 @@ public class DefaultExpressionRequest implements SpiExpressionRequest {
|
||||
return bindLog == null ? "" : bindLog.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql() {
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getBindValues() {
|
||||
return bindValues;
|
||||
}
|
||||
@@ -17,19 +17,26 @@ public class ExistsExpression implements SpiExpression {
|
||||
|
||||
private static final long serialVersionUID = 666990277309851644L;
|
||||
|
||||
private final boolean not;
|
||||
protected final boolean not;
|
||||
|
||||
private final SpiQuery<?> subQuery;
|
||||
protected final SpiQuery<?> subQuery;
|
||||
|
||||
private List<Object> bindParams;
|
||||
protected List<Object> bindParams;
|
||||
|
||||
private String sql;
|
||||
protected String sql;
|
||||
|
||||
public ExistsExpression(SpiQuery<?> subQuery, boolean not) {
|
||||
this.subQuery = subQuery;
|
||||
this.not = not;
|
||||
}
|
||||
|
||||
ExistsExpression(boolean not, String sql , List<Object> bindParams) {
|
||||
this.not = not;
|
||||
this.sql = sql;
|
||||
this.bindParams = bindParams;
|
||||
this.subQuery = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareExpression(BeanQueryRequest<?> request) {
|
||||
|
||||
@@ -38,10 +45,15 @@ public class ExistsExpression implements SpiExpression {
|
||||
this.sql = subQuery.getGeneratedSql().replace('\n', ' ');
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile/build the sub query.
|
||||
*/
|
||||
private CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
|
||||
protected CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
|
||||
SpiEbeanServer ebeanServer = (SpiEbeanServer) queryRequest.getEbeanServer();
|
||||
return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction());
|
||||
}
|
||||
@@ -76,6 +88,32 @@ public class ExistsExpression implements SpiExpression {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof ExistsExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExistsExpression that = (ExistsExpression) other;
|
||||
return this.sql.equals(that.sql)
|
||||
&& this.not == that.not
|
||||
&& this.bindParams.size() == that.bindParams.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
ExistsExpression that = (ExistsExpression) other;
|
||||
if (this.bindParams.size() != that.bindParams.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bindParams.size(); i++) {
|
||||
if (!bindParams.get(i).equals(that.bindParams.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
|
||||
// Nothing to do for exists expression
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
package com.avaje.ebeaninternal.util;
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
@@ -6,7 +6,6 @@ import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
|
||||
|
||||
/**
|
||||
* Slightly redundant as Query.setId() ultimately also does the same job.
|
||||
@@ -69,4 +68,14 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
return other instanceof IdExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
IdExpression that = (IdExpression) other;
|
||||
return value.equals(that.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -86,4 +86,27 @@ public class IdInExpression extends NonPrepareExpression {
|
||||
return idList.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof IdInExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IdInExpression that = (IdInExpression) other;
|
||||
return this.idList.size() == that.idList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
IdInExpression that = (IdInExpression) other;
|
||||
if (this.idList.size() != that.idList.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < idList.size(); i++) {
|
||||
if (!idList.get(i).equals(that.idList.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -61,20 +61,18 @@ class InExpression extends AbstractExpression {
|
||||
return;
|
||||
}
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && !prop.isAssocId()) {
|
||||
prop = null;
|
||||
}
|
||||
|
||||
if (prop != null) {
|
||||
request.append(prop.getAssocIdInExpr(propertyName));
|
||||
request.append(prop.getAssocIdInExpr(propName));
|
||||
String inClause = prop.getAssocIdInValueExpr(values.length);
|
||||
request.append(inClause);
|
||||
|
||||
} else {
|
||||
request.append(propertyName);
|
||||
request.append(propName);
|
||||
if (not) {
|
||||
request.append(" not");
|
||||
}
|
||||
@@ -105,4 +103,29 @@ class InExpression extends AbstractExpression {
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof InExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InExpression that = (InExpression) other;
|
||||
return propName.equals(that.propName)
|
||||
&& not == that.not
|
||||
&& values.length == that.values.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
InExpression that = (InExpression) other;
|
||||
if (this.values.length != that.values.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (!values[i].equals(that.values[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* In expression using a sub query.
|
||||
*/
|
||||
@@ -24,12 +25,20 @@ class InQueryExpression extends AbstractExpression {
|
||||
|
||||
private String sql;
|
||||
|
||||
public InQueryExpression(String propertyName, SpiQuery<?> subQuery, boolean not) {
|
||||
InQueryExpression(String propertyName, SpiQuery<?> subQuery, boolean not) {
|
||||
super(propertyName);
|
||||
this.subQuery = subQuery;
|
||||
this.not = not;
|
||||
}
|
||||
|
||||
InQueryExpression(String propertyName, boolean not, String sql, List<Object> bindParams) {
|
||||
super(propertyName);
|
||||
this.subQuery = null;
|
||||
this.not = not;
|
||||
this.sql = sql;
|
||||
this.bindParams = bindParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareExpression(BeanQueryRequest<?> request) {
|
||||
|
||||
@@ -61,7 +70,7 @@ class InQueryExpression extends AbstractExpression {
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
request.append(" (").append(getPropertyName()).append(")");
|
||||
request.append(" (").append(propName).append(")");
|
||||
if (not) {
|
||||
request.append(" not");
|
||||
}
|
||||
@@ -77,4 +86,31 @@ class InQueryExpression extends AbstractExpression {
|
||||
request.addBindValue(bindParams.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof InQueryExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InQueryExpression that = (InQueryExpression) other;
|
||||
return propName.equals(that.propName)
|
||||
&& sql.equals(that.sql)
|
||||
&& not == that.not
|
||||
&& bindParams.size() == that.bindParams.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
InQueryExpression that = (InQueryExpression) other;
|
||||
if (this.bindParams.size() != that.bindParams.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bindParams.size(); i++) {
|
||||
if (!bindParams.get(i).equals(that.bindParams.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
/**
|
||||
@@ -60,6 +60,8 @@ class JsonPathExpression extends AbstractExpression {
|
||||
@Override
|
||||
public void queryPlanHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(JsonPathExpression.class).add(propName).add(path).add(operator);
|
||||
builder.bindIfNotNull(value);
|
||||
builder.bindIfNotNull(upperValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,6 +71,27 @@ class JsonPathExpression extends AbstractExpression {
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof JsonPathExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonPathExpression that = (JsonPathExpression) other;
|
||||
return propName.equals(that.propName)
|
||||
&& operator == that.operator
|
||||
&& Same.sameByValue(path, that.path)
|
||||
&& Same.sameByNull(value, that.value)
|
||||
&& Same.sameByNull(upperValue, that.upperValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
JsonPathExpression that = (JsonPathExpression) other;
|
||||
if (value != null ? !value.equals(that.value) : that.value != null) return false;
|
||||
return upperValue != null ? upperValue.equals(that.upperValue) : that.upperValue == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionList;
|
||||
|
||||
/**
|
||||
* Junction implementation.
|
||||
@@ -35,6 +34,14 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
Conjunction(com.avaje.ebean.Query<T> query, ExpressionList<T> parent) {
|
||||
super(false, AND, query, parent);
|
||||
}
|
||||
|
||||
Conjunction(DefaultExpressionList<T> expressionList) {
|
||||
super(false, AND, expressionList);
|
||||
}
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new Conjunction<T>(exprList.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
|
||||
static class Disjunction<T> extends JunctionExpression<T> {
|
||||
@@ -44,9 +51,18 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
Disjunction(com.avaje.ebean.Query<T> query, ExpressionList<T> parent) {
|
||||
super(true, OR, query, parent);
|
||||
}
|
||||
|
||||
Disjunction(DefaultExpressionList<T> expressionList) {
|
||||
super(true, OR, expressionList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new Disjunction<T>(exprList.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
|
||||
private final DefaultExpressionList<T> exprList;
|
||||
protected final DefaultExpressionList<T> exprList;
|
||||
|
||||
private final String joinType;
|
||||
|
||||
@@ -61,6 +77,15 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
this.exprList = new DefaultExpressionList<T>(query, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for copyForPlanKey.
|
||||
*/
|
||||
JunctionExpression(boolean disjunction, String joinType, DefaultExpressionList<T> exprList) {
|
||||
this.disjunction = disjunction;
|
||||
this.joinType = joinType;
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
|
||||
|
||||
@@ -163,6 +188,25 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
|
||||
if (!(other instanceof JunctionExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JunctionExpression that = (JunctionExpression) other;
|
||||
return joinType.equals(that.joinType)
|
||||
&& exprList.isSameByPlan(that.exprList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
JunctionExpression that = (JunctionExpression) other;
|
||||
return joinType.equals(that.joinType)
|
||||
&& exprList.isSameByBind(that.exprList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endJunction() {
|
||||
return exprList.endJunction();
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.LikeType;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -22,6 +23,7 @@ class LikeExpression extends AbstractExpression {
|
||||
this.val = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
@@ -35,14 +37,13 @@ class LikeExpression extends AbstractExpression {
|
||||
request.addBindValue(bindValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
String pname = propertyName;
|
||||
|
||||
String pname = propName;
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null && prop.isDbEncrypted()) {
|
||||
pname = prop.getBeanProperty().getDecryptProperty(propertyName);
|
||||
pname = prop.getBeanProperty().getDecryptProperty(propName);
|
||||
}
|
||||
if (caseInsensitive) {
|
||||
request.append("lower(").append(pname).append(")");
|
||||
@@ -71,6 +72,24 @@ class LikeExpression extends AbstractExpression {
|
||||
return val.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof LikeExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LikeExpression that = (LikeExpression) other;
|
||||
return this.propName.equals(that.propName)
|
||||
&& this.caseInsensitive == that.caseInsensitive
|
||||
&& this.type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
LikeExpression that = (LikeExpression) other;
|
||||
return val.equals(that.val);
|
||||
}
|
||||
|
||||
private static String getValue(String value, boolean caseInsensitive, LikeType type) {
|
||||
if (caseInsensitive) {
|
||||
value = value.toLowerCase();
|
||||
|
||||
@@ -26,6 +26,12 @@ abstract class LogicExpression implements SpiExpression {
|
||||
And(Expression expOne, Expression expTwo) {
|
||||
super(AND, expOne, expTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new And(expOne.copyForPlanKey(), expTwo.copyForPlanKey());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Or extends LogicExpression {
|
||||
@@ -35,11 +41,16 @@ abstract class LogicExpression implements SpiExpression {
|
||||
Or(Expression expOne, Expression expTwo) {
|
||||
super(OR, expOne, expTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new Or(expOne.copyForPlanKey(), expTwo.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
|
||||
private final SpiExpression expOne;
|
||||
protected final SpiExpression expOne;
|
||||
|
||||
private final SpiExpression expTwo;
|
||||
protected final SpiExpression expTwo;
|
||||
|
||||
private final String joinType;
|
||||
|
||||
@@ -49,6 +60,7 @@ abstract class LogicExpression implements SpiExpression {
|
||||
this.expTwo = (SpiExpression) expTwo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
|
||||
expOne.containsMany(desc, manyWhereJoin);
|
||||
expTwo.containsMany(desc, manyWhereJoin);
|
||||
@@ -60,11 +72,13 @@ abstract class LogicExpression implements SpiExpression {
|
||||
expTwo.validate(validation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
expOne.addBindValues(request);
|
||||
expTwo.addBindValues(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
request.append("(");
|
||||
@@ -83,16 +97,38 @@ abstract class LogicExpression implements SpiExpression {
|
||||
/**
|
||||
* Based on the joinType plus the two expressions.
|
||||
*/
|
||||
@Override
|
||||
public void queryPlanHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(LogicExpression.class).add(joinType);
|
||||
expOne.queryPlanHash(builder);
|
||||
expTwo.queryPlanHash(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = expOne.queryBindHash();
|
||||
hc = hc * 31 + expTwo.queryBindHash();
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
|
||||
if (!(other instanceof LogicExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogicExpression that = (LogicExpression) other;
|
||||
return this.joinType.equals(that.joinType)
|
||||
&& this.expOne.isSameByPlan(that.expOne)
|
||||
&& this.expTwo.isSameByPlan(that.expTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
LogicExpression that = (LogicExpression) other;
|
||||
return this.expOne.isSameByBind(that.expOne)
|
||||
&& this.expTwo.isSameByBind(that.expTwo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,4 +12,9 @@ abstract class NonPrepareExpression implements SpiExpression {
|
||||
public void prepareExpression(BeanQueryRequest<?> request) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ class NoopExpression implements SpiExpression {
|
||||
|
||||
protected static final NoopExpression INSTANCE = new NoopExpression();
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
|
||||
// nothing to do
|
||||
@@ -50,4 +55,14 @@ class NoopExpression implements SpiExpression {
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
return other instanceof NoopExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ final class NotExpression implements SpiExpression {
|
||||
|
||||
private static final long serialVersionUID = 5648926732402355781L;
|
||||
|
||||
private static final String NOT = "not (";
|
||||
private static final String NOT_START = "not (";
|
||||
private static final String NOT_END = ") ";
|
||||
|
||||
private final SpiExpression exp;
|
||||
|
||||
@@ -21,6 +22,12 @@ final class NotExpression implements SpiExpression {
|
||||
this.exp = (SpiExpression) exp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new NotExpression(exp.copyForPlanKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
|
||||
exp.containsMany(desc, manyWhereJoin);
|
||||
}
|
||||
@@ -30,14 +37,16 @@ final class NotExpression implements SpiExpression {
|
||||
exp.validate(validation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
exp.addBindValues(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
request.append(NOT);
|
||||
request.append(NOT_START);
|
||||
exp.addSql(request);
|
||||
request.append(") ");
|
||||
request.append(NOT_END);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,8 +63,23 @@ final class NotExpression implements SpiExpression {
|
||||
exp.queryPlanHash(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return exp.queryBindHash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof NotExpression)) {
|
||||
return false;
|
||||
}
|
||||
NotExpression that = (NotExpression) other;
|
||||
return exp.isSameByPlan(that.exp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
NotExpression that = (NotExpression) other;
|
||||
return exp.isSameByBind(that.exp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -28,7 +28,7 @@ class NullExpression extends AbstractExpression {
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
String propertyName = propName;
|
||||
|
||||
String nullExpr = notNull ? " is not null " : " is null ";
|
||||
|
||||
@@ -41,6 +41,23 @@ class NullExpression extends AbstractExpression {
|
||||
request.append(propertyName).append(nullExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof NullExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NullExpression that = (NullExpression) other;
|
||||
return this.propName.equals(that.propName)
|
||||
&& this.notNull == that.notNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
// no bind values so always true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on notNull flag and the propertyName.
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -55,4 +56,31 @@ class RawExpression extends NonPrepareExpression {
|
||||
public int queryBindHash() {
|
||||
return sql.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof RawExpression)) {
|
||||
return false;
|
||||
}
|
||||
RawExpression that = (RawExpression) other;
|
||||
return sql.equals(that.sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
if (!(other instanceof RawExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RawExpression that = (RawExpression) other;
|
||||
if (values.length != that.values.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (!Same.sameByValue(values[i], that.values[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
/**
|
||||
* Utility to help isSame methods.
|
||||
*/
|
||||
public class Same {
|
||||
|
||||
/**
|
||||
* Return true if both values are null or both an not null.
|
||||
*/
|
||||
public static boolean sameByNull(Object v1, Object v2) {
|
||||
return v1 == null ? v2 == null : v2 != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null safe equals check.
|
||||
*/
|
||||
public static boolean sameByValue(Object v1, Object v2) {
|
||||
return v1 == null ? v2 == null : v1.equals(v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null safe check by sameByValue or sameByNull based on byValue.
|
||||
*/
|
||||
public static boolean sameBy(boolean byValue, Object value, Object value1) {
|
||||
|
||||
if (byValue) {
|
||||
return sameByValue(value, value1);
|
||||
} else {
|
||||
return sameByNull(value, value1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -20,17 +20,25 @@ public class SimpleExpression extends AbstractExpression {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public final String getPropName() {
|
||||
return propName;
|
||||
}
|
||||
|
||||
public boolean isOpEquals() {
|
||||
return Op.EQ.equals(type);
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null) {
|
||||
if (prop.isAssocId()) {
|
||||
Object[] ids = prop.getAssocOneIdValues((EntityBean)value);
|
||||
Object[] ids = prop.getAssocOneIdValues((EntityBean) value);
|
||||
if (ids != null) {
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
request.addBindValue(ids[i]);
|
||||
@@ -54,12 +62,10 @@ public class SimpleExpression extends AbstractExpression {
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
String propertyName = getPropertyName();
|
||||
|
||||
ElPropertyValue prop = getElProp(request);
|
||||
if (prop != null) {
|
||||
if (prop.isAssocId()) {
|
||||
request.append(prop.getAssocOneIdExpr(propertyName, type.bind()));
|
||||
request.append(prop.getAssocOneIdExpr(propName, type.bind()));
|
||||
return;
|
||||
}
|
||||
if (prop.isDbEncrypted()) {
|
||||
@@ -68,7 +74,7 @@ public class SimpleExpression extends AbstractExpression {
|
||||
return;
|
||||
}
|
||||
}
|
||||
request.append(propertyName).append(type.bind());
|
||||
request.append(propName).append(type.bind());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,8 +91,20 @@ public class SimpleExpression extends AbstractExpression {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
@Override
|
||||
public boolean isSameByPlan(SpiExpression other) {
|
||||
if (!(other instanceof SimpleExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SimpleExpression that = (SimpleExpression) other;
|
||||
return this.propName.equals(that.propName)
|
||||
&& this.type == that.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
SimpleExpression that = (SimpleExpression) other;
|
||||
return value.equals(that.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -18,6 +13,10 @@ import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Represents a query for a given SQL statement.
|
||||
* <p>
|
||||
@@ -45,7 +44,7 @@ public class CQueryPlan {
|
||||
|
||||
private final boolean autoTuned;
|
||||
|
||||
private final HashQueryPlan hash;
|
||||
private final CQueryPlanKey planKey;
|
||||
|
||||
private final boolean rawSql;
|
||||
|
||||
@@ -79,7 +78,7 @@ public class CQueryPlan {
|
||||
this.server = request.getServer();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.hash = request.getQueryPlanHash();
|
||||
this.planKey = request.getQueryPlanKey();
|
||||
this.autoTuned = request.getQuery().isAutoTuned();
|
||||
if (sqlRes != null) {
|
||||
this.sql = sqlRes.getSql();
|
||||
@@ -103,7 +102,7 @@ public class CQueryPlan {
|
||||
this.server = request.getServer();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.hash = buildHash(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
this.autoTuned = false;
|
||||
this.sql = sql;
|
||||
this.sqlTree = sqlTree;
|
||||
@@ -114,15 +113,13 @@ public class CQueryPlan {
|
||||
}
|
||||
|
||||
|
||||
private HashQueryPlan buildHash(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
|
||||
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
|
||||
builder.add(sql).add(rawSql).add(rowNumberIncluded).add(logWhereSql);
|
||||
builder.addRawSql(sql);
|
||||
return builder.build();
|
||||
private CQueryPlanKey buildPlanKey(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
|
||||
|
||||
return new RawSqlQueryPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return beanType + " hash:" + hash;
|
||||
return beanType + " hash:" + planKey;
|
||||
}
|
||||
|
||||
public Class<?> getBeanType() {
|
||||
@@ -147,8 +144,8 @@ public class CQueryPlan {
|
||||
return autoTuned;
|
||||
}
|
||||
|
||||
public HashQueryPlan getHash() {
|
||||
return hash;
|
||||
public CQueryPlanKey getPlanKey() {
|
||||
return planKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +161,7 @@ public class CQueryPlan {
|
||||
|
||||
private String calcAuditQueryKey() {
|
||||
// rawSql needs to include the MD5 hash of the sql
|
||||
return rawSql ? hash.getPartialKey() + "_" + getSqlMd5Hash() : hash.getPartialKey();
|
||||
return rawSql ? planKey.getPartialKey() + "_" + getSqlMd5Hash() : planKey.getPartialKey();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -233,7 +233,7 @@ public final class CQueryPlanStats {
|
||||
|
||||
@Override
|
||||
public String getQueryPlanHash() {
|
||||
return queryPlan.getHash().toString();
|
||||
return queryPlan.getPlanKey().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.util.BindParamsParser;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
|
||||
/**
|
||||
* QueryPlanKey for RawSql queries.
|
||||
*/
|
||||
public class RawSqlQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
private final String sql;
|
||||
private final boolean rawSql;
|
||||
private final boolean rowNumberIncluded;
|
||||
private final String logWhereSql;
|
||||
|
||||
public RawSqlQueryPlanKey(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
|
||||
this.sql = sql;
|
||||
this.rawSql = rawSql;
|
||||
this.rowNumberIncluded = rowNumberIncluded;
|
||||
this.logWhereSql = logWhereSql;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getPartialKey() + ":r";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as a partial key. For rawSql hash the sql is part of the key and as such
|
||||
* needs to be included in order to have a complete key. Typically the MD5 of the sql
|
||||
* can be used as a short form proxy for the actual sql.
|
||||
*/
|
||||
public String getPartialKey() {
|
||||
return hashCode() + "_0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
RawSqlQueryPlanKey that = (RawSqlQueryPlanKey) o;
|
||||
|
||||
if (rawSql != that.rawSql) return false;
|
||||
if (rowNumberIncluded != that.rowNumberIncluded) return false;
|
||||
if (!sql.equals(that.sql)) return false;
|
||||
return logWhereSql != null ? logWhereSql.equals(that.logWhereSql) : that.logWhereSql == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = sql.hashCode();
|
||||
result = 31 * result + (rawSql ? 1 : 0);
|
||||
result = 31 * result + (rowNumberIncluded ? 1 : 0);
|
||||
result = 31 * result + logWhereSql.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,8 @@ import com.avaje.ebean.plugin.SpiBeanType;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
|
||||
@@ -28,7 +27,7 @@ import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.expression.SimpleExpression;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
import com.avaje.ebeaninternal.util.DefaultExpressionList;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.Timestamp;
|
||||
@@ -234,7 +233,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Hash of final query after AutoTune tuning.
|
||||
*/
|
||||
private HashQueryPlan queryPlanHash;
|
||||
private CQueryPlanKey queryPlanKey;
|
||||
|
||||
private transient PersistenceContext persistenceContext;
|
||||
|
||||
@@ -493,7 +492,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
if (se instanceof SimpleExpression) {
|
||||
SimpleExpression e = (SimpleExpression) se;
|
||||
if (e.isOpEquals()) {
|
||||
return new NaturalKeyBindParam(e.getPropertyName(), e.getValue());
|
||||
return new NaturalKeyBindParam(e.getPropName(), e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,55 +758,34 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Calculate the query hash for either AutoTune query tuning or Query Plan caching.
|
||||
*/
|
||||
HashQueryPlan calculateQueryPlanHash() {
|
||||
|
||||
// exclude bind values and things unrelated to the sql being generated
|
||||
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
|
||||
|
||||
builder.add((type == null ? 0 : type.ordinal() + 1));
|
||||
builder.add(autoTuned).add(distinct).add(sqlDistinct).add(query);
|
||||
builder.add(firstRow).add(maxRows).add(orderBy).add(forUpdate);
|
||||
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
|
||||
builder.add(mapKey);
|
||||
builder.add(disableLazyLoading);
|
||||
builder.add(id != null);
|
||||
builder.add(temporalMode);
|
||||
builder.add(rawSql == null ? 0 : rawSql.queryHash());
|
||||
builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
|
||||
builder.add(rootTableAlias);
|
||||
|
||||
if (detail != null) {
|
||||
detail.queryPlanHash(builder);
|
||||
}
|
||||
if (bindParams != null) {
|
||||
bindParams.buildQueryPlanHash(builder);
|
||||
}
|
||||
CQueryPlanKey createQueryPlanKey() {
|
||||
|
||||
DefaultExpressionList<T> where = null;
|
||||
DefaultExpressionList<T> having = null;
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.queryPlanHash(builder);
|
||||
where = whereExpressions.copyForPlanKey();
|
||||
}
|
||||
if (havingExpressions != null) {
|
||||
havingExpressions.queryPlanHash(builder);
|
||||
having = havingExpressions.copyForPlanKey();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
queryPlanKey = new OrmQueryPlanKey(includeTableJoin, type, detail, maxRows, firstRow,
|
||||
disableLazyLoading, rawWhereClause, orderBy, query, additionalWhere, additionalHaving,
|
||||
distinct, sqlDistinct, mapKey, id, bindParams, where, having,
|
||||
temporalMode, forUpdate, rootTableAlias, rawSql);
|
||||
|
||||
return queryPlanKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash that should be unique for the generated SQL across a given bean type.
|
||||
* <p>
|
||||
* This can used to enable the caching and reuse of a 'query plan'.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is calculated AFTER AutoTune query tuning has occurred.
|
||||
* </p>
|
||||
* Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key.
|
||||
*/
|
||||
public HashQueryPlan queryPlanHash(BeanQueryRequest<?> request) {
|
||||
public CQueryPlanKey prepare(BeanQueryRequest<?> request) {
|
||||
|
||||
prepareExpressions(request);
|
||||
|
||||
queryPlanHash = calculateQueryPlanHash();
|
||||
return queryPlanHash;
|
||||
queryPlanKey = createQueryPlanKey();
|
||||
return queryPlanKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -852,7 +830,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
// so queryPlanHash is calculated well before this method is called
|
||||
int hc = queryBindHash();
|
||||
|
||||
return new HashQuery(queryPlanHash, hc);
|
||||
return new HashQuery(queryPlanKey, hc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
/**
|
||||
* Query plan key for ORM queries.
|
||||
*/
|
||||
public class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
private final TableJoin includeTableJoin;
|
||||
private final String orderByAsSting;
|
||||
private final OrmQueryDetail detail;
|
||||
private final BindParams bindParams;
|
||||
private final SpiExpression whereExpressions;
|
||||
private final SpiExpression havingExpressions;
|
||||
private final RawSql rawSql;
|
||||
private final boolean hasIdValue;
|
||||
|
||||
private final SpiQuery.Type type;
|
||||
private final int maxRows;
|
||||
private final int firstRow;
|
||||
private final boolean disableLazyLoading;
|
||||
private final String rawWhereClause;
|
||||
private final String query;
|
||||
private final String additionalWhere;
|
||||
private final String additionalHaving;
|
||||
private final boolean distinct;
|
||||
private final boolean sqlDistinct;
|
||||
private final String mapKey;
|
||||
private final SpiQuery.TemporalMode temporalMode;
|
||||
private final boolean forUpdate;
|
||||
private final String rootTableAlias;
|
||||
|
||||
private final int planHash;
|
||||
private final int bindCount;
|
||||
|
||||
public OrmQueryPlanKey(TableJoin includeTableJoin, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, String rawWhereClause, OrderBy<?> orderBy, String query, String additionalWhere, String additionalHaving, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql) {
|
||||
|
||||
this.includeTableJoin = includeTableJoin;
|
||||
this.type = type;
|
||||
this.detail = detail;
|
||||
this.maxRows = maxRows;
|
||||
this.firstRow = firstRow;
|
||||
this.disableLazyLoading = disableLazyLoading;
|
||||
this.rawWhereClause = rawWhereClause;
|
||||
this.orderByAsSting = (orderBy == null) ? null : orderBy.toStringFormat();
|
||||
this.query = query;
|
||||
this.additionalWhere = additionalWhere;
|
||||
this.additionalHaving = additionalHaving;
|
||||
this.distinct = distinct;
|
||||
this.sqlDistinct = sqlDistinct;
|
||||
this.mapKey = mapKey;
|
||||
this.hasIdValue = (id != null);
|
||||
this.bindParams = bindParams;
|
||||
this.whereExpressions = whereExpressions;
|
||||
this.havingExpressions = havingExpressions;
|
||||
this.temporalMode = temporalMode;
|
||||
this.forUpdate = forUpdate;
|
||||
this.rootTableAlias = rootTableAlias;
|
||||
this.rawSql = rawSql;
|
||||
|
||||
// exclude bind values and things unrelated to the sql being generated
|
||||
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
|
||||
|
||||
builder.add((type == null ? 0 : type.ordinal() + 1));
|
||||
builder.add(distinct).add(sqlDistinct).add(query);
|
||||
builder.add(firstRow).add(maxRows);
|
||||
builder.add(orderBy).add(forUpdate);
|
||||
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
|
||||
builder.add(mapKey);
|
||||
builder.add(disableLazyLoading);
|
||||
builder.add(hasIdValue);
|
||||
builder.add(temporalMode);
|
||||
builder.add(rawSql == null ? 0 : rawSql.queryHash());
|
||||
builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
|
||||
builder.add(rootTableAlias);
|
||||
|
||||
if (detail != null) {
|
||||
detail.queryPlanHash(builder);
|
||||
}
|
||||
if (bindParams != null) {
|
||||
bindParams.buildQueryPlanHash(builder);
|
||||
}
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.queryPlanHash(builder);
|
||||
}
|
||||
if (havingExpressions != null) {
|
||||
havingExpressions.queryPlanHash(builder);
|
||||
}
|
||||
|
||||
this.planHash = builder.getPlanHash();
|
||||
this.bindCount = builder.getBindCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartialKey() {
|
||||
return planHash + "_" + bindCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return planHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
OrmQueryPlanKey that = (OrmQueryPlanKey) o;
|
||||
|
||||
if (planHash != that.planHash) return false;
|
||||
if (bindCount != that.bindCount) return false;
|
||||
|
||||
if (maxRows != that.maxRows) return false;
|
||||
if (firstRow != that.firstRow) return false;
|
||||
if (disableLazyLoading != that.disableLazyLoading) return false;
|
||||
|
||||
if (distinct != that.distinct) return false;
|
||||
if (sqlDistinct != that.sqlDistinct) return false;
|
||||
if (forUpdate != that.forUpdate) return false;
|
||||
if (hasIdValue != that.hasIdValue) return false;
|
||||
if (type != that.type) return false;
|
||||
if (temporalMode != that.temporalMode) return false;
|
||||
if (includeTableJoin != null ? !includeTableJoin.equals(that.includeTableJoin) : that.includeTableJoin != null) return false;
|
||||
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null) return false;
|
||||
|
||||
if (whereExpressions != null ? !whereExpressions.isSameByPlan(that.whereExpressions) : that.whereExpressions != null) return false;
|
||||
if (havingExpressions != null ? !havingExpressions.isSameByPlan(that.havingExpressions) : that.havingExpressions != null) return false;
|
||||
|
||||
// if (detail != null ? !detail.equals(that.detail) : that.detail != null) return false;
|
||||
// if (bindParams != null ? !bindParams.equals(that.bindParams) : that.bindParams != null) return false;
|
||||
// if (rawSql != null ? !rawSql.equals(that.rawSql) : that.rawSql != null) return false;
|
||||
|
||||
if (rawWhereClause != null ? !rawWhereClause.equals(that.rawWhereClause) : that.rawWhereClause != null) return false;
|
||||
if (query != null ? !query.equals(that.query) : that.query != null) return false;
|
||||
if (additionalWhere != null ? !additionalWhere.equals(that.additionalWhere) : that.additionalWhere != null) return false;
|
||||
if (additionalHaving != null ? !additionalHaving.equals(that.additionalHaving) : that.additionalHaving != null) return false;
|
||||
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
|
||||
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.util.FilterExpressionList;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExpressionList;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
Reference in New Issue
Block a user