mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-24 23:56:36 +00:00
Refactor of query plan hash - add HashQueryPlan, HashQuery etc
This commit is contained in:
@@ -15,8 +15,6 @@ import java.util.List;
|
||||
* Typically you will not construct an OrderBy yourself but use one that exists
|
||||
* on the Query object.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class OrderBy<T> implements Serializable {
|
||||
|
||||
@@ -24,7 +22,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private transient Query<T> query;
|
||||
|
||||
private List<Property> list;
|
||||
private final List<Property> list;
|
||||
|
||||
/**
|
||||
* Create an empty OrderBy with no associated query.
|
||||
@@ -168,31 +166,23 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof OrderBy<?>) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
OrderBy<?> other = (OrderBy<?>) obj;
|
||||
return hashCode() == other.hashCode();
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash();
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for this OrderBy. This can be to determine logical
|
||||
* equality for OrderBy clauses.
|
||||
*/
|
||||
public int hash() {
|
||||
int hc = OrderBy.class.getName().hashCode();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
hc = hc * 31 + list.get(i).hash();
|
||||
}
|
||||
return hc;
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,11 +208,24 @@ public final class OrderBy<T> implements Serializable {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
}
|
||||
|
||||
protected int hash() {
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property e = (Property) obj;
|
||||
return e.ascending == ascending
|
||||
&& e.property.equals(property);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toStringFormat();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.meta;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Query execution statistics Meta data.
|
||||
*/
|
||||
@@ -18,9 +16,9 @@ public interface MetaBeanQueryPlanStatistic {
|
||||
public boolean isAutofetchTuned();
|
||||
|
||||
/**
|
||||
* Return the query plan hash.
|
||||
* Return a string representation of the query plan hash.
|
||||
*/
|
||||
public int getQueryPlanHash();
|
||||
public String getQueryPlanHash();
|
||||
|
||||
/**
|
||||
* Return the sql executed.
|
||||
|
||||
@@ -50,7 +50,7 @@ public class BindParams implements Serializable {
|
||||
* taken into account when calculating the query hash.
|
||||
* </p>
|
||||
*/
|
||||
public int getQueryPlanHash() {
|
||||
public void buildQueryPlanHash(HashQueryPlanBuilder builder) {
|
||||
int hc = 31;
|
||||
for (Param param : positionedParameters) {
|
||||
hc = hc * 31 + param.queryBindCount();
|
||||
@@ -61,7 +61,8 @@ public class BindParams implements Serializable {
|
||||
hc = hc * 31 + entry.getValue().queryBindCount();
|
||||
}
|
||||
|
||||
return hc;
|
||||
int bindCount = positionedParameters.size() + namedParameters.size();
|
||||
builder.add(hc).bind(bindCount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
/**
|
||||
* A hash key for a query including both the query plan and bind values.
|
||||
*/
|
||||
public class HashQuery {
|
||||
|
||||
private final HashQueryPlan planHash;
|
||||
|
||||
private final int bindHash;
|
||||
|
||||
/**
|
||||
* Create the HashQuery.
|
||||
*/
|
||||
public HashQuery(HashQueryPlan 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;
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof HashQuery)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashQuery e = (HashQuery) obj;
|
||||
return e.bindHash == bindHash && e.planHash.equals(planHash);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A hash for a query plan.
|
||||
*/
|
||||
public class HashQueryPlan {
|
||||
|
||||
private final String rawSql;
|
||||
|
||||
private final int planHash;
|
||||
|
||||
private final int bindCount;
|
||||
|
||||
public HashQueryPlan(String rawSql, int planHash, int bindCount) {
|
||||
this.rawSql = rawSql;
|
||||
this.planHash = planHash;
|
||||
this.bindCount = bindCount;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return planHash+":"+bindCount+(rawSql != null ? ":r" : "");
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = planHash;
|
||||
hc = hc * 31 + bindCount;
|
||||
hc = hc * 31 + Objects.hashCode(rawSql);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof HashQueryPlan)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashQueryPlan e = (HashQueryPlan) obj;
|
||||
return e.planHash == planHash
|
||||
&& e.bindCount == bindCount
|
||||
&& Objects.equals(e.rawSql, rawSql);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Used to build HashQueryPlan instances.
|
||||
*/
|
||||
public class HashQueryPlanBuilder {
|
||||
|
||||
private int planHash;
|
||||
|
||||
private int bindCount;
|
||||
|
||||
private String rawSql;
|
||||
|
||||
public HashQueryPlanBuilder() {
|
||||
this.planHash = 31;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return planHash+":"+bindCount+(rawSql != null ? ":r" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(Class<?> cls) {
|
||||
planHash = planHash * 31 + cls.getName().hashCode();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(Object object) {
|
||||
planHash = planHash * 31 + Objects.hashCode(object);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an integer to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(int hashValue) {
|
||||
planHash = planHash * 31 + (hashValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a boolean to the hash calculation.
|
||||
*/
|
||||
public HashQueryPlanBuilder add(boolean booleanValue) {
|
||||
planHash = planHash * 31 + (booleanValue ? 31 : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a number to the bind count for the hash.
|
||||
*/
|
||||
public HashQueryPlanBuilder bind(int extraBindCount) {
|
||||
bindCount += extraBindCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw sql to the hash.
|
||||
*/
|
||||
public HashQueryPlanBuilder addRawSql(String rawSql) {
|
||||
this.rawSql = rawSql;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the calculated HashQueryPlan.
|
||||
*/
|
||||
public HashQueryPlan build() {
|
||||
return new HashQueryPlan(rawSql, planHash, bindCount);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public interface SpiExpression extends Expression {
|
||||
* from an AutoFetch perspective and get different tuning.
|
||||
* </p>
|
||||
*/
|
||||
public int queryAutoFetchHash();
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder);
|
||||
|
||||
/**
|
||||
* Calculate a hash value for the expression.
|
||||
@@ -37,7 +37,7 @@ public interface SpiExpression extends Expression {
|
||||
* case the query execution plan can be reused.
|
||||
* </p>
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request);
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
|
||||
|
||||
/**
|
||||
* Return the hash value for the values that will be bound.
|
||||
|
||||
@@ -28,14 +28,13 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
|
||||
*/
|
||||
public void setExpressionFactory(ExpressionFactory expr);
|
||||
|
||||
/**
|
||||
* Process "Many" properties populating ManyWhereJoins.
|
||||
* <p>
|
||||
* Predicates on Many properties require an extra independent
|
||||
* join clause.
|
||||
* </p>
|
||||
*/
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
|
||||
/**
|
||||
* Process "Many" properties populating ManyWhereJoins.
|
||||
* <p>
|
||||
* Predicates on Many properties require an extra independent join clause.
|
||||
* </p>
|
||||
*/
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
|
||||
|
||||
/**
|
||||
* Return true if this list is empty.
|
||||
@@ -62,10 +61,10 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
|
||||
*/
|
||||
public ArrayList<Object> buildBindValues(SpiExpressionRequest request);
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the expressions but excluding the actual bind
|
||||
* values.
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request);
|
||||
/**
|
||||
* Calculate a hash based on the expressions but excluding the actual bind
|
||||
* values.
|
||||
*/
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
|
||||
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
* tuning/modifying the query.
|
||||
* </p>
|
||||
*/
|
||||
public int queryAutofetchHash();
|
||||
public HashQueryPlan queryAutofetchHash(HashQueryPlanBuilder builder);
|
||||
|
||||
/**
|
||||
* Identifies queries that are the same bar the bind variables.
|
||||
@@ -354,7 +354,7 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
* Excludes the actual bind values (as they don't effect the query plan).
|
||||
* </p>
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request);
|
||||
public HashQueryPlan queryPlanHash(BeanQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the bind values used in the query.
|
||||
@@ -368,7 +368,7 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
/**
|
||||
* Identifies queries that are exactly the same including bind variables.
|
||||
*/
|
||||
public int queryHash();
|
||||
public HashQuery queryHash();
|
||||
|
||||
/**
|
||||
* Return true if this is a query based on a SqlSelect rather than
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
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.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
@@ -49,9 +51,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private Integer cacheKey;
|
||||
private HashQuery cacheKey;
|
||||
|
||||
private int queryPlanHash;
|
||||
private HashQueryPlan queryPlanHash;
|
||||
|
||||
/**
|
||||
* Flag set if background fetching taking place. In this case the transaction
|
||||
@@ -332,7 +334,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* with just the bind variables changing.
|
||||
* </p>
|
||||
*/
|
||||
public int getQueryPlanHash() {
|
||||
public HashQueryPlan getQueryPlanHash() {
|
||||
return queryPlanHash;
|
||||
}
|
||||
|
||||
@@ -356,14 +358,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return null;
|
||||
}
|
||||
|
||||
if (query.getType() == null) {
|
||||
// the query plan and bind values must be the same
|
||||
cacheKey = Integer.valueOf(query.queryHash());
|
||||
|
||||
} else {
|
||||
// additionally the return type (List/Set/Map) must be the same
|
||||
cacheKey = Integer.valueOf(31 * query.queryHash() + query.getType().hashCode());
|
||||
}
|
||||
cacheKey = query.queryHash();
|
||||
|
||||
// TODO: Sort out returning BeanCollection from L2 cache
|
||||
return null;
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.avaje.ebean.meta.MetaBeanInfo;
|
||||
import com.avaje.ebean.meta.MetaBeanQueryPlanStatistic;
|
||||
import com.avaje.ebean.text.TextException;
|
||||
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdatePlan;
|
||||
@@ -87,7 +88,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final ConcurrentHashMap<Integer, SpiUpdatePlan> updatePlanCache = new ConcurrentHashMap<Integer, SpiUpdatePlan>();
|
||||
|
||||
private final ConcurrentHashMap<Integer, CQueryPlan> queryPlanCache = new ConcurrentHashMap<Integer, CQueryPlan>();
|
||||
private final ConcurrentHashMap<HashQueryPlan, CQueryPlan> queryPlanCache = new ConcurrentHashMap<HashQueryPlan, CQueryPlan>();
|
||||
|
||||
private final ConcurrentHashMap<String, ElPropertyValue> elGetCache = new ConcurrentHashMap<String, ElPropertyValue>();
|
||||
|
||||
@@ -1202,11 +1203,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return queryPlanCache.values().iterator();
|
||||
}
|
||||
|
||||
public CQueryPlan getQueryPlan(Integer key) {
|
||||
public CQueryPlan getQueryPlan(HashQueryPlan key) {
|
||||
return queryPlanCache.get(key);
|
||||
}
|
||||
|
||||
public void putQueryPlan(Integer key, CQueryPlan plan) {
|
||||
public void putQueryPlan(HashQueryPlan key, CQueryPlan plan) {
|
||||
queryPlanCache.put(key, plan);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -105,29 +107,29 @@ class AllEqualsExpression implements SpiExpression {
|
||||
* The null check is required due to the "is null" sql being generated.
|
||||
* </p>
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
|
||||
int hc = AllEqualsExpression.class.getName().hashCode();
|
||||
Set<Entry<String, Object>> entries = propMap.entrySet();
|
||||
Iterator<Entry<String, Object>> it = entries.iterator();
|
||||
builder.add(AllEqualsExpression.class);
|
||||
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<java.lang.String, java.lang.Object> entry = it.next();
|
||||
for (Entry<String, Object> entry : propMap.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
String propName = entry.getKey();
|
||||
builder.add(propName).add(value == null ? 0 : 1);
|
||||
builder.bind(value == null ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
hc = hc * 31 + (value == null ? 0 : 1);
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
int hc = 31;
|
||||
for (Object value : propMap.values()) {
|
||||
hc = hc * 31 + Objects.hashCode(value);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
return queryAutoFetchHash();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +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.SpiExpressionRequest;
|
||||
|
||||
|
||||
@@ -30,14 +31,13 @@ class BetweenExpression extends AbstractExpression {
|
||||
request.append(getPropertyName()).append(BETWEEN).append(" ? and ? ");
|
||||
}
|
||||
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = BetweenExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(BetweenExpression.class).add(propName);
|
||||
builder.bind(2);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
+6
-7
@@ -1,6 +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.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -65,15 +66,13 @@ class BetweenPropertyExpression implements SpiExpression {
|
||||
request.append(" ? ").append(BETWEEN).append(name(lowProperty)).append(" and ").append(name(highProperty));
|
||||
}
|
||||
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = BetweenPropertyExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + lowProperty.hashCode();
|
||||
hc = hc * 31 + highProperty.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(BetweenPropertyExpression.class).add(lowProperty).add(highProperty);
|
||||
builder.bind(1);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
+7
-7
@@ -1,10 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
class CaseInsensitiveEqualExpression extends AbstractExpression implements LuceneAwareExpression {
|
||||
class CaseInsensitiveEqualExpression extends AbstractExpression {
|
||||
|
||||
private static final long serialVersionUID = -6406036750998971064L;
|
||||
|
||||
@@ -40,14 +41,13 @@ class CaseInsensitiveEqualExpression extends AbstractExpression implements Lucen
|
||||
request.append("lower(").append(pname).append(") =? ");
|
||||
}
|
||||
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = CaseInsensitiveEqualExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(CaseInsensitiveEqualExpression.class).add(propName);
|
||||
builder.bind(1);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
+6
-7
@@ -6,6 +6,7 @@ import java.util.Iterator;
|
||||
import com.avaje.ebean.ExampleExpression;
|
||||
import com.avaje.ebean.LikeType;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -163,28 +164,26 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
|
||||
/**
|
||||
* Return a hash for autoFetch query identification.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
// we have not yet built the list of expressions
|
||||
// so just based on the class name
|
||||
return DefaultExampleExpression.class.getName().hashCode();
|
||||
builder.add(DefaultExampleExpression.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for query plan identification.
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
|
||||
// this is always called once, and always called before
|
||||
// addSql() and addBindValues() methods
|
||||
list = buildExpressions(request);
|
||||
|
||||
int hc = DefaultExampleExpression.class.getName().hashCode();
|
||||
builder.add(DefaultExampleExpression.class);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
hc = hc * 31 + list.get(i).queryPlanHash(request);
|
||||
list.get(i).queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +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.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -49,14 +50,13 @@ class IdExpression implements SpiExpression {
|
||||
/**
|
||||
* No properties so this is just a unique static number.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
// this number is unique for a given bean type
|
||||
// which is all that is required
|
||||
return IdExpression.class.getName().hashCode();
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(IdExpression.class);
|
||||
builder.bind(1);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -67,16 +68,13 @@ public class IdInExpression implements SpiExpression {
|
||||
/**
|
||||
* Incorporates the number of Id values to bind.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
// this number is unique for a given bean type
|
||||
// which is all that is required
|
||||
int hc = IdInExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + idList.size();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(IdInExpression.class).add(idList.size());
|
||||
builder.bind(idList.size());
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -79,19 +80,18 @@ class InExpression extends AbstractExpression {
|
||||
/**
|
||||
* Based on the number of values in the in clause.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = InExpression.class.getName().hashCode() + 31 * values.length;
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(InExpression.class).add(propName).add(values.length);
|
||||
builder.bind(values.length);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
int hc = 0;
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
int hc = 31;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
hc = 31 * hc + values[i].hashCode();
|
||||
}
|
||||
return hc;
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
@@ -26,23 +27,19 @@ class InQueryExpression extends AbstractExpression {
|
||||
this.subQuery = subQuery;
|
||||
}
|
||||
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = InQueryExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
hc = hc * 31 + subQuery.queryAutofetchHash();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(InQueryExpression.class).add(propName);
|
||||
|
||||
subQuery.queryAutofetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
|
||||
// queryPlanHash executes prior to addSql() or addBindValues()
|
||||
// ... so compiledQuery will exist
|
||||
compiledSubQuery = compileSubQuery(request);
|
||||
|
||||
int hc = InQueryExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
hc = hc * 31 + subQuery.queryPlanHash(request);
|
||||
return hc;
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryListener;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -115,28 +116,20 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
/**
|
||||
* Based on Junction type and all the expression contained.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = JunctionExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + joinType.hashCode();
|
||||
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(JunctionExpression.class).add(joinType);
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
hc = hc * 31 + list.get(i).queryAutoFetchHash();
|
||||
list.get(i).queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
int hc = JunctionExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + joinType.hashCode();
|
||||
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
builder.add(JunctionExpression.class).add(joinType);
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
hc = hc * 31 + list.get(i).queryPlanHash(request);
|
||||
list.get(i).queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -2,10 +2,11 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.LikeType;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
class LikeExpression extends AbstractExpression implements LuceneAwareExpression {
|
||||
class LikeExpression extends AbstractExpression {
|
||||
|
||||
private static final long serialVersionUID = -5398151809111172380L;
|
||||
|
||||
@@ -59,15 +60,13 @@ class LikeExpression extends AbstractExpression implements LuceneAwareExpression
|
||||
/**
|
||||
* Based on caseInsensitive and the property name.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = LikeExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + (caseInsensitive ? 0 : 1);
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(LikeExpression.class).add(caseInsensitive).add(propName);
|
||||
builder.bind(1);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.Expression;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -69,18 +70,16 @@ abstract class LogicExpression implements SpiExpression {
|
||||
/**
|
||||
* Based on the joinType plus the two expressions.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = LogicExpression.class.getName().hashCode() + joinType.hashCode();
|
||||
hc = hc * 31 + expOne.queryAutoFetchHash();
|
||||
hc = hc * 31 + expTwo.queryAutoFetchHash();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(LogicExpression.class).add(joinType);
|
||||
expOne.queryAutoFetchHash(builder);
|
||||
expTwo.queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
int hc = LogicExpression.class.getName().hashCode() + joinType.hashCode();
|
||||
hc = hc * 31 + expOne.queryPlanHash(request);
|
||||
hc = hc * 31 + expTwo.queryPlanHash(request);
|
||||
return hc;
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
builder.add(LogicExpression.class).add(joinType);
|
||||
expOne.queryPlanHash(request, builder);
|
||||
expTwo.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
/**
|
||||
* Marker interface for lucene aware expressions.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LuceneAwareExpression {
|
||||
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.Expression;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
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.server.deploy.BeanDescriptor;
|
||||
|
||||
final class NotExpression implements SpiExpression, LuceneAwareExpression {
|
||||
final class NotExpression implements SpiExpression {
|
||||
|
||||
private static final long serialVersionUID = 5648926732402355781L;
|
||||
|
||||
@@ -36,16 +37,13 @@ final class NotExpression implements SpiExpression, LuceneAwareExpression {
|
||||
/**
|
||||
* Based on the expression.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = NotExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + exp.queryAutoFetchHash();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(NotExpression.class);
|
||||
exp.queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
int hc = NotExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + exp.queryPlanHash(request);
|
||||
return hc;
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -1,6 +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.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
@@ -41,15 +42,12 @@ class NullExpression extends AbstractExpression {
|
||||
/**
|
||||
* Based on notNull flag and the propertyName.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = NullExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + (notNull ? 1 : 0);
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(NullExpression.class).add(notNull).add(propName);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Exception used to wrap Lucene parsing exceptions.
|
||||
*/
|
||||
public class PersistenceLuceneParseException extends PersistenceException {
|
||||
|
||||
private static final long serialVersionUID = 838790249273928392L;
|
||||
|
||||
public PersistenceLuceneParseException(Throwable e){
|
||||
super(e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +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.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -38,14 +39,12 @@ class RawExpression implements SpiExpression {
|
||||
/**
|
||||
* Based on the sql.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = RawExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + sql.hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(RawExpression.class).add(sql);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
public class SimpleExpression extends AbstractExpression implements LuceneAwareExpression {
|
||||
public class SimpleExpression extends AbstractExpression {
|
||||
|
||||
private static final long serialVersionUID = -382881395755603790L;
|
||||
|
||||
@@ -91,15 +92,13 @@ public class SimpleExpression extends AbstractExpression implements LuceneAwareE
|
||||
/**
|
||||
* Based on the type and propertyName.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hc = SimpleExpression.class.getName().hashCode();
|
||||
hc = hc * 31 + propName.hashCode();
|
||||
hc = hc * 31 + type.name().hashCode();
|
||||
return hc;
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(SimpleExpression.class).add(propName).add(type.name());
|
||||
builder.bind(1);
|
||||
}
|
||||
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
return queryAutoFetchHash();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlan;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
|
||||
@@ -34,7 +36,7 @@ public class CQueryPlan {
|
||||
|
||||
private final boolean autofetchTuned;
|
||||
|
||||
private final int hash;
|
||||
private final HashQueryPlan hash;
|
||||
|
||||
private final boolean rawSql;
|
||||
|
||||
@@ -86,7 +88,7 @@ public class CQueryPlan {
|
||||
|
||||
this.beanType = beanType;
|
||||
this.stats = new CQueryPlanStats(this);
|
||||
this.hash = 0;
|
||||
this.hash = buildHash(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
this.autofetchTuned = false;
|
||||
this.sql = sql;
|
||||
this.sqlTree = sqlTree;
|
||||
@@ -95,6 +97,13 @@ public class CQueryPlan {
|
||||
this.logWhereSql = logWhereSql;
|
||||
this.encryptedProps = sqlTree.getEncryptedProps();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return beanType+" hash:"+hash;
|
||||
@@ -122,7 +131,7 @@ public class CQueryPlan {
|
||||
return autofetchTuned;
|
||||
}
|
||||
|
||||
public int getHash() {
|
||||
public HashQueryPlan getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,8 +131,8 @@ public final class CQueryPlanStats {
|
||||
|
||||
|
||||
@Override
|
||||
public int getQueryPlanHash() {
|
||||
return queryPlan.getHash();
|
||||
public String getQueryPlanHash() {
|
||||
return queryPlan.getHash().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,9 @@ import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.meta.MetaAutoFetchStatistic;
|
||||
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.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
@@ -207,7 +210,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Hash of final query after AutoFetch tuning.
|
||||
*/
|
||||
private int queryPlanHash;
|
||||
private HashQueryPlan queryPlanHash;
|
||||
|
||||
private transient PersistenceContext persistenceContext;
|
||||
|
||||
@@ -627,62 +630,61 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Calculate the query hash for either AutoFetch query tuning or Query Plan caching.
|
||||
*/
|
||||
private int calculateHash(BeanQueryRequest<?> request) {
|
||||
private HashQueryPlan calculateHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
|
||||
// exclude bind values and things unrelated to
|
||||
// the sql being generated
|
||||
|
||||
if (builder == null) {
|
||||
builder = new HashQueryPlanBuilder();
|
||||
}
|
||||
|
||||
// must use String name of class as actual class hashCode
|
||||
// can change between JVM restarts.
|
||||
int hc = beanType.getName().hashCode();
|
||||
builder.add((type == null ? 0 : type.ordinal()+1));
|
||||
builder.add(useIndex).add(autoFetchTuned).add(distinct).add(query);
|
||||
builder.add(firstRow).add(maxRows).add(orderBy).add(forUpdate);
|
||||
builder.add(rawWhereClause).add(additionalWhere).add(additionalHaving);
|
||||
builder.add(mapKey);
|
||||
builder.add(id != null);
|
||||
builder.add(rawSql == null ? 0 : rawSql.queryHash());
|
||||
|
||||
hc = hc * 31 + (type == null ? 0 : type.ordinal());
|
||||
hc = hc * 31 + (useIndex == null ? 0 : useIndex.hashCode());
|
||||
|
||||
hc = hc * 31 + (rawSql == null ? 0 : rawSql.queryHash());
|
||||
|
||||
hc = hc * 31 + (autoFetchTuned ? 31 : 0);
|
||||
hc = hc * 31 + (distinct ? 31 : 0);
|
||||
hc = hc * 31 + (query == null ? 0 : query.hashCode());
|
||||
hc = hc * 31 + detail.queryPlanHash(request);
|
||||
|
||||
hc = hc * 31 + (firstRow == 0 ? 0 : firstRow);
|
||||
hc = hc * 31 + (maxRows == 0 ? 0 : maxRows);
|
||||
hc = hc * 31 + (orderBy == null ? 0 : orderBy.hash());
|
||||
hc = hc * 31 + (rawWhereClause == null ? 0 : rawWhereClause.hashCode());
|
||||
|
||||
hc = hc * 31 + (additionalWhere == null ? 0 : additionalWhere.hashCode());
|
||||
hc = hc * 31 + (additionalHaving == null ? 0 : additionalHaving.hashCode());
|
||||
hc = hc * 31 + (mapKey == null ? 0 : mapKey.hashCode());
|
||||
hc = hc * 31 + (id == null ? 0 : 1);
|
||||
|
||||
if (bindParams != null) {
|
||||
hc = hc * 31 + bindParams.getQueryPlanHash();
|
||||
if (detail != null) {
|
||||
detail.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
if (bindParams != null) {
|
||||
bindParams.buildQueryPlanHash(builder);
|
||||
}
|
||||
|
||||
if (request == null) {
|
||||
// for AutoFetch...
|
||||
hc = hc * 31 + (whereExpressions == null ? 0 : whereExpressions.queryAutoFetchHash());
|
||||
hc = hc * 31 + (havingExpressions == null ? 0 : havingExpressions.queryAutoFetchHash());
|
||||
builder.add(true);
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.queryAutoFetchHash(builder);
|
||||
}
|
||||
if (havingExpressions != null) {
|
||||
havingExpressions.queryAutoFetchHash(builder);
|
||||
}
|
||||
|
||||
} else {
|
||||
// for query plan...
|
||||
hc = hc * 31 + (whereExpressions == null ? 0 : whereExpressions.queryPlanHash(request));
|
||||
hc = hc * 31 + (havingExpressions == null ? 0 : havingExpressions.queryPlanHash(request));
|
||||
builder.add(false);
|
||||
if (whereExpressions != null) {
|
||||
whereExpressions.queryPlanHash(request, builder);
|
||||
}
|
||||
if (havingExpressions != null) {
|
||||
havingExpressions.queryPlanHash(request, builder);
|
||||
}
|
||||
}
|
||||
|
||||
hc = hc * 31 + (forUpdate ? 31 : 0);
|
||||
|
||||
return hc;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash used by AutoFetch to identify when a query has changed
|
||||
* (and hence potentially needs a new tuned query plan to be developed).
|
||||
*/
|
||||
public int queryAutofetchHash() {
|
||||
public HashQueryPlan queryAutofetchHash(HashQueryPlanBuilder builder) {
|
||||
|
||||
return calculateHash(null);
|
||||
return calculateHash(null, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,9 +697,9 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* This is calculated AFTER AutoFetch query tuning has occurred.
|
||||
* </p>
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
public HashQueryPlan queryPlanHash(BeanQueryRequest<?> request) {
|
||||
|
||||
queryPlanHash = calculateHash(request);
|
||||
queryPlanHash = calculateHash(request, null);
|
||||
return queryPlanHash;
|
||||
}
|
||||
|
||||
@@ -724,12 +726,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* (including bind values) before.
|
||||
* </p>
|
||||
*/
|
||||
public int queryHash() {
|
||||
public HashQuery queryHash() {
|
||||
// calculateQueryPlanHash is called just after potential AutoFetch tuning
|
||||
// so queryPlanHash is calculated well before this method is called
|
||||
int hc = queryPlanHash;
|
||||
hc = hc * 31 + queryBindHash();
|
||||
return hc;
|
||||
int hc = queryBindHash();
|
||||
|
||||
return new HashQuery(queryPlanHash, hc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.FetchConfig;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
@@ -63,17 +64,19 @@ public class OrmQueryDetail implements Serializable {
|
||||
/**
|
||||
* Calculate the hash for the query plan.
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
|
||||
int hc = (baseProps == null ? 1 : baseProps.queryPlanHash(request));
|
||||
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
hc = hc * 31 + p.queryPlanHash(request);
|
||||
}
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
if (baseProps == null) {
|
||||
builder.add(false);
|
||||
} else {
|
||||
builder.add(true);
|
||||
baseProps.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
p.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.avaje.ebean.FetchConfig;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionFactory;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
@@ -355,17 +356,18 @@ public class OrmQueryProperties implements Serializable {
|
||||
* Calculate the query plan hash.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
|
||||
int hc = (path != null ? path.hashCode() : 1);
|
||||
if (properties != null){
|
||||
hc = hc * 31 + properties.hashCode();
|
||||
} else {
|
||||
hc = hc * 31 + (included != null ? included.hashCode() : 1);
|
||||
}
|
||||
hc = hc * 31 + (filterMany != null ? filterMany.queryPlanHash(request) : 1);
|
||||
|
||||
return hc;
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
|
||||
builder.add(path);
|
||||
if (properties != null) {
|
||||
builder.add(properties);
|
||||
} else {
|
||||
builder.add(included);
|
||||
}
|
||||
builder.add(filterMany != null);
|
||||
if (filterMany != null) {
|
||||
filterMany.queryPlanHash(request, builder);
|
||||
}
|
||||
}
|
||||
|
||||
public String getProperties() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryListener;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import com.avaje.ebeaninternal.api.ManyWhereJoins;
|
||||
import com.avaje.ebeaninternal.api.SpiExpression;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
@@ -283,26 +284,24 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
* Calculate a hash based on the expressions but excluding the actual bind
|
||||
* values.
|
||||
*/
|
||||
public int queryAutoFetchHash() {
|
||||
int hash = DefaultExpressionList.class.getName().hashCode();
|
||||
public void queryAutoFetchHash(HashQueryPlanBuilder builder) {
|
||||
builder.add(DefaultExpressionList.class);
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
SpiExpression expression = list.get(i);
|
||||
hash = hash * 31 + expression.queryAutoFetchHash();
|
||||
expression.queryAutoFetchHash(builder);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the expressions but excluding the actual bind
|
||||
* values.
|
||||
*/
|
||||
public int queryPlanHash(BeanQueryRequest<?> request) {
|
||||
int hash = DefaultExpressionList.class.getName().hashCode();
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
builder.add(DefaultExpressionList.class);
|
||||
for (int i = 0, size = list.size(); i < size; i++) {
|
||||
SpiExpression expression = list.get(i);
|
||||
hash = hash * 31 + expression.queryPlanHash(request);
|
||||
expression.queryPlanHash(request, builder);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user