#1100 - Refactor OrmQueryPlanKey to use string expression for where

This commit is contained in:
rob bygrave
2017-08-31 02:11:49 +12:00
parent a695fb59b2
commit f83c7fdac8
54 changed files with 359 additions and 723 deletions
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchConfig;
import io.ebeaninternal.api.HashQueryPlanBuilder;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.el.ElPropertyDeploy;
@@ -56,16 +55,10 @@ public class OrmQueryDetail implements Serializable {
return copy;
}
public int queryPlanHash() {
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
queryPlanHash(builder);
return builder.getPlanHash();
}
/**
* Calculate the hash for the query plan.
*/
public void queryPlanHash(HashQueryPlanBuilder builder) {
public void queryPlanHash(StringBuilder builder) {
baseProps.queryPlanHash(builder);
if (fetchPaths != null) {
for (OrmQueryProperties p : fetchPaths.values()) {
@@ -74,36 +67,6 @@ public class OrmQueryDetail implements Serializable {
}
}
/**
* Return true if the details are the same for query plan purposes.
*/
public boolean isSameByPlan(OrmQueryDetail otherDetail) {
if (!isSameByPlan(baseProps, otherDetail.baseProps)) {
return false;
}
if (fetchPaths == null) {
return otherDetail.fetchPaths == null;
}
if (fetchPaths.size() != otherDetail.fetchPaths.size()) {
return false;
}
// check with ordering being important
Iterator<Map.Entry<String, OrmQueryProperties>> thisIt = fetchPaths.entrySet().iterator();
Iterator<Map.Entry<String, OrmQueryProperties>> thatIt = otherDetail.fetchPaths.entrySet().iterator();
while (thisIt.hasNext() && thatIt.hasNext()) {
Map.Entry<String, OrmQueryProperties> thisEntry = thisIt.next();
Map.Entry<String, OrmQueryProperties> thatEntry = thatIt.next();
if (!thisEntry.getKey().equals(thatEntry.getKey())) {
return false;
}
if (!thisEntry.getValue().isSameByPlan(thatEntry.getValue())) {
return false;
}
}
return true;
}
/**
* Return true if equal in terms of autoTune (select and fetch without property ordering).
*/
@@ -133,10 +96,6 @@ public class OrmQueryDetail implements Serializable {
return p1 == null ? p2 == null : p1.isSameByAutoTune(p2);
}
private boolean isSameByPlan(OrmQueryProperties p1, OrmQueryProperties p2) {
return p1 == null ? p2 == null : p1.isSameByPlan(p2);
}
@Override
public String toString() {
return asString();
@@ -312,7 +271,7 @@ public class OrmQueryDetail implements Serializable {
public void sortFetchPaths(BeanDescriptor<?> d) {
sortFetchPaths(d, true);
}
private void sortFetchPaths(BeanDescriptor<?> d, boolean addIds) {
if (!fetchPaths.isEmpty()) {
@@ -5,7 +5,6 @@ import io.ebean.Query;
import io.ebean.RawSql;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.CQueryPlanKey;
import io.ebeaninternal.api.HashQueryPlanBuilder;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -15,16 +14,11 @@ import io.ebeaninternal.server.deploy.TableJoin;
*/
class OrmQueryPlanKey implements CQueryPlanKey {
private final SpiExpression where;
private final SpiExpression having;
private final RawSql.Key rawSqlKey;
private final int maxRows;
private final int firstRow;
private final OrmUpdateProperties updateProperties;
private final int planHash;
private final int bindCount;
private final String options;
private final String description;
OrmQueryPlanKey(String discValue, TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading,
OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams,
@@ -68,43 +62,46 @@ class OrmQueryPlanKey implements CQueryPlanKey {
if (mapKey != null) {
sb.append(",mapKey:").append(mapKey);
}
this.options = sb.toString();
this.maxRows = maxRows;
this.firstRow = firstRow;
this.where = (whereExpressions == null) ? null : whereExpressions.copyForPlanKey();
this.having = (havingExpressions == null) ? null : havingExpressions.copyForPlanKey();
this.updateProperties = updateProperties;
this.rawSqlKey = (rawSql == null) ? null : rawSql.getKey();
// exclude bind values and things unrelated to the sql being generated
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
builder.add(options.hashCode());
builder.add(firstRow).add(maxRows);
builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode());
if (detail != null) {
detail.queryPlanHash(builder);
sb.append(" detail[");
detail.queryPlanHash(sb);
sb.append("]");
}
if (bindParams != null) {
bindParams.buildQueryPlanHash(builder);
sb.append(" bindParams[");
bindParams.buildQueryPlanHash(sb);
sb.append("]");
}
if (where != null) {
where.queryPlanHash(builder);
if (whereExpressions != null) {
sb.append(" where[");
whereExpressions.queryPlanHash(sb);
sb.append("]");
}
if (having != null) {
having.queryPlanHash(builder);
if (havingExpressions != null) {
sb.append(" having[");
havingExpressions.queryPlanHash(sb);
sb.append("]");
}
if (updateProperties != null) {
updateProperties.buildQueryPlanHash(builder);
sb.append(" update[");
updateProperties.buildQueryPlanHash(sb);
sb.append("]");
}
this.planHash = builder.getPlanHash();
this.bindCount = builder.getBindCount();
this.description = sb.toString();
int hc = description.hashCode();
hc = hc * 92821 + (maxRows);
hc = hc * 92821 + (firstRow);
this.planHash = hc;
}
@Override
public String getPartialKey() {
return planHash + "_" + bindCount;
return description;
}
@Override
@@ -119,14 +116,9 @@ class OrmQueryPlanKey implements CQueryPlanKey {
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 (!options.equals(that.options)) return false;
if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false;
if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false;
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null) return false;
if (!description.equals(that.description)) return false;
return rawSqlKey != null ? rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey == null;
}
}
@@ -4,14 +4,12 @@ import io.ebean.ExpressionFactory;
import io.ebean.FetchConfig;
import io.ebean.OrderBy;
import io.ebean.Query;
import io.ebeaninternal.api.HashQueryPlanBuilder;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionFactory;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.expression.FilterExprPath;
import io.ebeaninternal.server.expression.FilterExpressionList;
import io.ebeaninternal.server.expression.Same;
import io.ebeaninternal.server.query.SplitName;
import java.io.Serializable;
@@ -476,33 +474,30 @@ public class OrmQueryProperties implements Serializable {
return included.equals(p2.included);
}
/**
* Properties are the same for query plan purposes.
*/
public boolean isSameByPlan(OrmQueryProperties p2) {
if (!Same.sameByValue(secondaryQueryJoins, p2.secondaryQueryJoins)) return false;
if (!Same.sameByValue(included, p2.included)) return false;
if (!Same.sameByNull(filterMany, p2.filterMany)) return false;
if (filterMany != null && !filterMany.isSameByPlan(p2.filterMany)) return false;
return fetchConfig.equals(p2.fetchConfig);
}
/**
* Calculate the query plan hash.
*/
public void queryPlanHash(HashQueryPlanBuilder builder) {
public void queryPlanHash(StringBuilder builder) {
builder.add(path);
builder.addOrdered(included);
builder.add(secondaryQueryJoins);
builder.add(filterMany != null);
if (filterMany != null) {
filterMany.queryPlanHash(builder);
builder.append("qpp[");
builder.append(path);
if (included != null){
builder.append(" included:").append(included);
}
builder.add(fetchConfig.hashCode());
if (secondaryQueryJoins != null) {
builder.append(" secondary:").append(secondaryQueryJoins);
}
if (filterMany != null) {
builder.append(" filterMany[");
filterMany.queryPlanHash(builder);
builder.append("]");
}
if (fetchConfig != null) {
builder.append(" config:").append(fetchConfig.hashCode());
}
builder.append("]");
}
}
@@ -149,23 +149,14 @@ public class OrmUpdateProperties {
}
}
/**
* Return true if this update has the same logical set clause.
*/
public boolean isSameByPlan(OrmUpdateProperties that) {
return that.values.size() == values.size()
&& logicalSetClause().equals(that.logicalSetClause());
}
/**
* Build the hash for the query plan caching.
*/
void buildQueryPlanHash(HashQueryPlanBuilder builder) {
builder.add(OrmUpdateProperties.class);
void buildQueryPlanHash(StringBuilder builder) {
Set<Map.Entry<String, Value>> entries = values.entrySet();
for (Map.Entry<String, Value> entry : entries) {
builder.add(entry.getKey());
builder.bind(entry.getValue().getBindCount());
builder.append("key:").append(entry.getKey());
builder.append(" ?:").append(entry.getValue().getBindCount());
}
}