diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java b/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java index 28cdf61c5..d2987fc53 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java @@ -17,32 +17,26 @@ public interface SpiExpression extends Expression { *

*/ void containsMany(BeanDescriptor desc, ManyWhereJoins whereManyJoins); - - /** + + /** + * Prepare the expression. For example, compile sub-query expressions etc. + */ + void prepareExpression(BeanQueryRequest request); + + /** * Calculate a hash value used to identify a query for AutoTune tuning. *

* That is, if the hash changes then the query will be considered different * from an AutoTune perspective and get different tuning. *

*/ - void queryAutoTuneHash(HashQueryPlanBuilder builder); - - /** - * Calculate a hash value for the expression. - * This includes the expression type and property but should exclude - * the bind values. - *

- * This is used where queries are the same except for the bind values, in which - * case the query execution plan can be reused. - *

- */ - void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder); - + void queryPlanHash(HashQueryPlanBuilder builder); + /** * Return the hash value for the values that will be bound. */ int queryBindHash(); - + /** * Add some sql to the query. *

@@ -61,7 +55,7 @@ public interface SpiExpression extends Expression { /** * Add the parameter values to be set against query. For each ? place holder * there should be a corresponding value that is added to the bindList. - * + * * @param request * the associated request. */ diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiExpressionList.java b/src/main/java/com/avaje/ebeaninternal/api/SpiExpressionList.java index 1cacf0a45..98c7ee1fd 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiExpressionList.java @@ -1,13 +1,12 @@ package com.avaje.ebeaninternal.api; -import java.util.ArrayList; -import java.util.List; - 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. */ @@ -59,13 +58,18 @@ public interface SpiExpressionList extends ExpressionList { * * @return the list of all the bind values in order. */ - ArrayList buildBindValues(SpiExpressionRequest request); - + List 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(BeanQueryRequest request, HashQueryPlanBuilder builder); + void queryPlanHash(HashQueryPlanBuilder builder); /** * Validate all the properties/paths used in this expression list. diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java index fd4e8c926..63b72bcb6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java @@ -1,5 +1,6 @@ package com.avaje.ebeaninternal.server.expression; +import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebeaninternal.api.ManyWhereJoins; import com.avaje.ebeaninternal.api.SpiExpression; import com.avaje.ebeaninternal.api.SpiExpressionRequest; @@ -43,6 +44,11 @@ public abstract class AbstractExpression implements SpiExpression { } } + @Override + public void prepareExpression(BeanQueryRequest request) { + // do nothing + } + @Override public void validate(SpiExpressionValidation validation) { validation.validate(getPropertyName()); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/AllEqualsExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/AllEqualsExpression.java index 8f4edfdca..2b338b234 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/AllEqualsExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/AllEqualsExpression.java @@ -1,18 +1,16 @@ package com.avaje.ebeaninternal.server.expression; -import java.util.Map; -import java.util.Map.Entry; - -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.api.SpiExpressionValidation; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.el.ElPropertyDeploy; -class AllEqualsExpression implements SpiExpression { +import java.util.Map; +import java.util.Map.Entry; + +class AllEqualsExpression extends NonPrepareExpression { private static final long serialVersionUID = -8691773558205937025L; @@ -26,6 +24,7 @@ class AllEqualsExpression implements SpiExpression { return propName; } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { if (propMap != null) { for (String propertyName : propMap.keySet()) { @@ -44,6 +43,7 @@ class AllEqualsExpression implements SpiExpression { } } + @Override public void addBindValues(SpiExpressionRequest request) { if (propMap.isEmpty()) { @@ -57,6 +57,7 @@ class AllEqualsExpression implements SpiExpression { } } + @Override public void addSql(SpiExpressionRequest request) { if (propMap.isEmpty()) { @@ -92,7 +93,8 @@ class AllEqualsExpression implements SpiExpression { * The null check is required due to the "is null" sql being generated. *

*/ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(AllEqualsExpression.class); @@ -104,10 +106,7 @@ class AllEqualsExpression implements SpiExpression { } } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { int hc = 31; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenExpression.java index d47c4f594..20aa4dbf5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenExpression.java @@ -21,25 +21,25 @@ class BetweenExpression extends AbstractExpression { this.valueHigh = valHigh; } + @Override public void addBindValues(SpiExpressionRequest request) { request.addBindValue(valueLow); request.addBindValue(valueHigh); } + @Override public void addSql(SpiExpressionRequest request) { request.append(getPropertyName()).append(BETWEEN).append(" ? and ? "); } - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(BetweenExpression.class).add(propName); builder.bind(2); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { int hc = valueLow.hashCode(); hc = hc * 31 + valueHigh.hashCode(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenPropertyExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenPropertyExpression.java index c8f8193e1..b3a92dd00 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenPropertyExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/BetweenPropertyExpression.java @@ -1,9 +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; import com.avaje.ebeaninternal.api.SpiExpressionValidation; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; @@ -12,7 +10,7 @@ import com.avaje.ebeaninternal.server.el.ElPropertyDeploy; /** * Between expression where a value is between two properties. */ -class BetweenPropertyExpression implements SpiExpression { +class BetweenPropertyExpression extends NonPrepareExpression { private static final long serialVersionUID = 2078918165221454910L; @@ -32,6 +30,7 @@ class BetweenPropertyExpression implements SpiExpression { return propName; } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { ElPropertyDeploy elProp = desc.getElPropertyDeploy(name(lowProperty)); @@ -55,20 +54,19 @@ class BetweenPropertyExpression implements SpiExpression { request.addBindValue(value); } + @Override public void addSql(SpiExpressionRequest request) { request.append(" ? ").append(BETWEEN).append(name(lowProperty)).append(" and ").append(name(highProperty)); } - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(BetweenPropertyExpression.class).add(lowProperty).add(highProperty); builder.bind(1); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return value.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java index 3fd9f08e5..2492b96c3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java @@ -41,15 +41,13 @@ class CaseInsensitiveEqualExpression extends AbstractExpression { request.append("lower(").append(pname).append(") =? "); } - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(CaseInsensitiveEqualExpression.class).add(propName); builder.bind(1); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return value.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java index c21867998..8b642f30b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java @@ -86,6 +86,7 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio this.likeType = likeType; } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins whereManyJoins) { if (list != null) { for (int i = 0; i < list.size(); i++) { @@ -94,31 +95,37 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio } } + @Override public ExampleExpression includeZeros() { includeZeros = true; return this; } + @Override public ExampleExpression caseInsensitive() { caseInsensitive = true; return this; } + @Override public ExampleExpression useStartsWith() { likeType = LikeType.STARTS_WITH; return this; } + @Override public ExampleExpression useContains() { likeType = LikeType.CONTAINS; return this; } + @Override public ExampleExpression useEndsWith() { likeType = LikeType.ENDS_WITH; return this; } + @Override public ExampleExpression useEqualTo() { likeType = LikeType.EQUAL_TO; return this; @@ -134,6 +141,7 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio /** * Adds bind values to the request. */ + @Override public void addBindValues(SpiExpressionRequest request) { for (int i = 0; i < list.size(); i++) { @@ -145,6 +153,7 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio /** * Generates and adds the sql to the request. */ + @Override public void addSql(SpiExpressionRequest request) { if (!list.isEmpty()) { @@ -162,34 +171,27 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio } } - /** - * Return a hash for AutoTune query identification. - */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { - // we have not yet built the list of expressions - // so just based on the class name - builder.add(DefaultExampleExpression.class); + @Override + public void prepareExpression(BeanQueryRequest request) { + list = buildExpressions(request); } /** - * Return a hash for query plan identification. + * Return a hash for AutoTune query identification. */ - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - - // this is always called once, and always called before - // addSql() and addBindValues() methods - list = buildExpressions(request); + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(DefaultExampleExpression.class); - for (int i = 0; i < list.size(); i++) { - list.get(i).queryPlanHash(request, builder); + list.get(i).queryPlanHash(builder); } } /** * Return a hash for the actual bind values used. */ + @Override public int queryBindHash() { int hc = DefaultExampleExpression.class.getName().hashCode(); for (int i = 0; i < list.size(); i++) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsExpression.java index d0b65a6ed..7071bdb48 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsExpression.java @@ -28,19 +28,17 @@ public class ExistsExpression implements SpiExpression { this.not = not; } - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { - builder.add(ExistsExpression.class).add(not); - - subQuery.queryAutoTuneHash(builder); - } - - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - + @Override + public void prepareExpression(BeanQueryRequest request) { // queryPlanHash executes prior to addSql() or addBindValues() // ... so compiledQuery will exist compiledSubQuery = compileSubQuery(request); + } - queryAutoTuneHash(builder); + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { + builder.add(ExistsExpression.class).add(not); + subQuery.queryAutoTuneHash(builder); } /** @@ -52,10 +50,12 @@ public class ExistsExpression implements SpiExpression { return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction()); } + @Override public int queryBindHash() { return subQuery.queryBindHash(); } + @Override public void addSql(SpiExpressionRequest request) { String subSelect = compiledSubQuery.getGeneratedSql(); @@ -69,6 +69,7 @@ public class ExistsExpression implements SpiExpression { request.append(") "); } + @Override public void addBindValues(SpiExpressionRequest request) { List bindParams = compiledSubQuery.getPredicates().getWhereExprBindValues(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/IdExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/IdExpression.java index ce122251b..27493d159 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/IdExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/IdExpression.java @@ -1,6 +1,5 @@ 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; @@ -12,7 +11,7 @@ import com.avaje.ebeaninternal.util.DefaultExpressionRequest; /** * Slightly redundant as Query.setId() ultimately also does the same job. */ -class IdExpression implements SpiExpression { +class IdExpression extends NonPrepareExpression implements SpiExpression { private static final long serialVersionUID = -3065936341718489842L; @@ -25,6 +24,7 @@ class IdExpression implements SpiExpression { /** * Always returns false. */ + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { } @@ -34,6 +34,7 @@ class IdExpression implements SpiExpression { // always valid } + @Override public void addBindValues(SpiExpressionRequest request) { // 'flatten' EmbeddedId and multiple Id cases @@ -45,6 +46,7 @@ class IdExpression implements SpiExpression { } } + @Override public void addSql(SpiExpressionRequest request) { DefaultExpressionRequest r = (DefaultExpressionRequest) request; @@ -56,15 +58,13 @@ class IdExpression implements SpiExpression { /** * No properties so this is just a unique static number. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(IdExpression.class); builder.bind(1); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return value.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/IdInExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/IdInExpression.java index ee3fa0bad..cff55539a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/IdInExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/IdInExpression.java @@ -1,21 +1,19 @@ 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; 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; + /** * Slightly redundant as Query.setId() ultimately also does the same job. */ -public class IdInExpression implements SpiExpression { +public class IdInExpression extends NonPrepareExpression { private static final long serialVersionUID = 1L; @@ -25,6 +23,7 @@ public class IdInExpression implements SpiExpression { this.idList = idList; } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { } @@ -33,6 +32,7 @@ public class IdInExpression implements SpiExpression { // always valid } + @Override public void addBindValues(SpiExpressionRequest request) { // Bind the Id values including EmbeddedId and multiple Id @@ -60,6 +60,7 @@ public class IdInExpression implements SpiExpression { request.append(inClause); } + @Override public void addSql(SpiExpressionRequest request) { DefaultExpressionRequest r = (DefaultExpressionRequest) request; @@ -74,15 +75,13 @@ public class IdInExpression implements SpiExpression { /** * Incorporates the number of Id values to bind. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(IdInExpression.class).add(idList.size()); builder.bind(idList.size()); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return idList.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/InExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/InExpression.java index f4e23718d..477f46ad3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/InExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/InExpression.java @@ -28,6 +28,7 @@ class InExpression extends AbstractExpression { this.not = not; } + @Override public void addBindValues(SpiExpressionRequest request) { ElPropertyValue prop = getElProp(request); @@ -51,6 +52,7 @@ class InExpression extends AbstractExpression { } } + @Override public void addSql(SpiExpressionRequest request) { if (values.length == 0) { @@ -88,15 +90,13 @@ class InExpression extends AbstractExpression { /** * Based on the number of values in the in clause. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(InExpression.class).add(propName).add(values.length).add(not); builder.bind(values.length); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { int hc = 31; for (int i = 0; i < values.length; i++) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/InQueryExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/InQueryExpression.java index 2781d0897..1934fc3cf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/InQueryExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/InQueryExpression.java @@ -28,18 +28,15 @@ class InQueryExpression extends AbstractExpression { this.not = not; } - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { - builder.add(InQueryExpression.class).add(propName).add(not); - subQuery.queryAutoTuneHash(builder); + @Override + public void prepareExpression(BeanQueryRequest request) { + compiledSubQuery = compileSubQuery(request); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - - // queryPlanHash executes prior to addSql() or addBindValues() - // ... so compiledQuery will exist - compiledSubQuery = compileSubQuery(request); - - queryAutoTuneHash(builder); + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { + builder.add(InQueryExpression.class).add(propName).add(not); + subQuery.queryAutoTuneHash(builder); } /** @@ -51,10 +48,12 @@ class InQueryExpression extends AbstractExpression { return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction()); } + @Override public int queryBindHash() { return subQuery.queryBindHash(); } + @Override public void addSql(SpiExpressionRequest request) { String subSelect = compiledSubQuery.getGeneratedSql(); @@ -70,6 +69,7 @@ class InQueryExpression extends AbstractExpression { request.append(") "); } + @Override public void addBindValues(SpiExpressionRequest request) { List bindParams = compiledSubQuery.getPredicates().getWhereExprBindValues(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JsonPathExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JsonPathExpression.java index 5489c0f72..547fa7001 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JsonPathExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JsonPathExpression.java @@ -58,15 +58,10 @@ class JsonPathExpression extends AbstractExpression { } @Override - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(JsonPathExpression.class).add(propName).add(path).add(operator); } - @Override - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - @Override public int queryBindHash() { int hc = (value == null) ? 0 : value.hashCode(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 08916044c..d4d88ffad 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -131,24 +131,23 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr } } + @Override + public void prepareExpression(BeanQueryRequest request) { + List list = exprList.internalList(); + for (int i = 0; i < list.size(); i++) { + list.get(i).prepareExpression(request); + } + } + /** * Based on Junction type and all the expression contained. */ @Override - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(JunctionExpression.class).add(joinType); List list = exprList.internalList(); for (int i = 0; i < list.size(); i++) { - list.get(i).queryAutoTuneHash(builder); - } - } - - @Override - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - builder.add(JunctionExpression.class).add(joinType); - List list = exprList.internalList(); - for (int i = 0; i < list.size(); i++) { - list.get(i).queryPlanHash(request, builder); + list.get(i).queryPlanHash(builder); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/LikeExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/LikeExpression.java index 9f0d9f475..cf3e49ae0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/LikeExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/LikeExpression.java @@ -1,7 +1,6 @@ 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; @@ -61,15 +60,13 @@ class LikeExpression extends AbstractExpression { /** * Based on caseInsensitive and the property name. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(LikeExpression.class).add(caseInsensitive).add(propName); builder.bind(1); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return val.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java index 981e6b563..71d4fe100 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java @@ -74,19 +74,19 @@ abstract class LogicExpression implements SpiExpression { request.append(") "); } + @Override + public void prepareExpression(BeanQueryRequest request) { + expOne.prepareExpression(request); + expTwo.prepareExpression(request); + } + /** * Based on the joinType plus the two expressions. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(LogicExpression.class).add(joinType); - expOne.queryAutoTuneHash(builder); - expTwo.queryAutoTuneHash(builder); - } - - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - builder.add(LogicExpression.class).add(joinType); - expOne.queryPlanHash(request, builder); - expTwo.queryPlanHash(request, builder); + expOne.queryPlanHash(builder); + expTwo.queryPlanHash(builder); } public int queryBindHash() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java new file mode 100644 index 000000000..e72bbf19a --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java @@ -0,0 +1,15 @@ +package com.avaje.ebeaninternal.server.expression; + +import com.avaje.ebean.event.BeanQueryRequest; +import com.avaje.ebeaninternal.api.SpiExpression; + +/** + * Base abstract expression that does nothing for prepareExpression(). + */ +abstract class NonPrepareExpression implements SpiExpression { + + @Override + public void prepareExpression(BeanQueryRequest request) { + // do nothing + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java index 549ecb60d..6fe932fe3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java @@ -26,13 +26,13 @@ class NoopExpression implements SpiExpression { } @Override - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { - builder.add(NoopExpression.class); + public void prepareExpression(BeanQueryRequest request) { + // do nothing } @Override - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); + public void queryPlanHash(HashQueryPlanBuilder builder) { + builder.add(NoopExpression.class); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java index a34fc1bbe..21c6c2dbe 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java @@ -40,17 +40,18 @@ final class NotExpression implements SpiExpression { request.append(") "); } + @Override + public void prepareExpression(BeanQueryRequest request) { + exp.prepareExpression(request); + } + /** * Based on the expression. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(NotExpression.class); - exp.queryAutoTuneHash(builder); - } - - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - builder.add(NotExpression.class); - exp.queryPlanHash(request, builder); + exp.queryPlanHash(builder); } public int queryBindHash() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NullExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NullExpression.java index bcbab597d..c84784501 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NullExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NullExpression.java @@ -20,10 +20,12 @@ class NullExpression extends AbstractExpression { this.notNull = notNull; } + @Override public void addBindValues(SpiExpressionRequest request) { } + @Override public void addSql(SpiExpressionRequest request) { String propertyName = getPropertyName(); @@ -42,14 +44,12 @@ class NullExpression extends AbstractExpression { /** * Based on notNull flag and the propertyName. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(NullExpression.class).add(notNull).add(propName); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return (notNull ? 1 : 0); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/RawExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/RawExpression.java index e078b87c9..7b37424e1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/RawExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/RawExpression.java @@ -1,14 +1,12 @@ 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; import com.avaje.ebeaninternal.api.SpiExpressionValidation; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -class RawExpression implements SpiExpression { +class RawExpression extends NonPrepareExpression { private static final long serialVersionUID = 7973903141340334606L; @@ -21,6 +19,7 @@ class RawExpression implements SpiExpression { this.values = values; } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { } @@ -30,6 +29,7 @@ class RawExpression implements SpiExpression { // always ignored } + @Override public void addBindValues(SpiExpressionRequest request) { if (values != null) { for (int i = 0; i < values.length; i++) { @@ -38,6 +38,7 @@ class RawExpression implements SpiExpression { } } + @Override public void addSql(SpiExpressionRequest request) { request.append(sql); } @@ -45,14 +46,12 @@ class RawExpression implements SpiExpression { /** * Based on the sql. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(RawExpression.class).add(sql); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return sql.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java index 8cde6e3ef..20e4cd6f4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java @@ -24,6 +24,7 @@ public class SimpleExpression extends AbstractExpression { return Op.EQ.equals(type); } + @Override public void addBindValues(SpiExpressionRequest request) { ElPropertyValue prop = getElProp(request); @@ -50,6 +51,7 @@ public class SimpleExpression extends AbstractExpression { request.addBindValue(value); } + @Override public void addSql(SpiExpressionRequest request) { String propertyName = getPropertyName(); @@ -72,15 +74,13 @@ public class SimpleExpression extends AbstractExpression { /** * Based on the type and propertyName. */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { + @Override + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(SimpleExpression.class).add(propName).add(type.name()); builder.bind(1); } - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { - queryAutoTuneHash(builder); - } - + @Override public int queryBindHash() { return value.hashCode(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 86f94831d..f21eae234 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -759,7 +759,7 @@ public class DefaultOrmQuery implements SpiQuery { /** * Calculate the query hash for either AutoTune query tuning or Query Plan caching. */ - private HashQueryPlan calculateHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { + private HashQueryPlan calculateHash(HashQueryPlanBuilder builder) { // exclude bind values and things unrelated to the sql being generated @@ -780,31 +780,17 @@ public class DefaultOrmQuery implements SpiQuery { builder.add(rootTableAlias); if (detail != null) { - detail.queryPlanHash(request, builder); + detail.queryPlanHash(builder); } if (bindParams != null) { bindParams.buildQueryPlanHash(builder); } - if (request == null) { - // for AutoTune... - builder.add(true); - if (whereExpressions != null) { - whereExpressions.queryAutoTuneHash(builder); - } - if (havingExpressions != null) { - havingExpressions.queryAutoTuneHash(builder); - } - - } else { - // for query plan... - builder.add(false); - if (whereExpressions != null) { - whereExpressions.queryPlanHash(request, builder); - } - if (havingExpressions != null) { - havingExpressions.queryPlanHash(request, builder); - } + if (whereExpressions != null) { + whereExpressions.queryPlanHash(builder); + } + if (havingExpressions != null) { + havingExpressions.queryPlanHash(builder); } return builder.build(); @@ -816,7 +802,7 @@ public class DefaultOrmQuery implements SpiQuery { */ public HashQueryPlan queryAutoTuneHash(HashQueryPlanBuilder builder) { - return calculateHash(null, builder); + return calculateHash(builder); } /** @@ -830,10 +816,25 @@ public class DefaultOrmQuery implements SpiQuery { */ public HashQueryPlan queryPlanHash(BeanQueryRequest request) { - queryPlanHash = calculateHash(request, null); + prepareExpressions(request); + + queryPlanHash = calculateHash(null); return queryPlanHash; } + /** + * Prepare the expressions (compile sub-queries etc). + */ + private void prepareExpressions(BeanQueryRequest request) { + + if (whereExpressions != null) { + whereExpressions.prepareExpression(request); + } + if (havingExpressions != null) { + havingExpressions.prepareExpression(request); + } + } + /** * Calculate a hash based on the bind values used in the query. *

diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetail.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetail.java index e8d0cc46b..4140c607e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetail.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetail.java @@ -1,5 +1,14 @@ package com.avaje.ebeaninternal.server.querydefn; +import com.avaje.ebean.FetchConfig; +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; +import com.avaje.ebeaninternal.server.el.ElPropertyValue; +import com.avaje.ebeaninternal.server.query.SplitName; + +import javax.persistence.PersistenceException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; @@ -11,17 +20,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -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; -import com.avaje.ebeaninternal.server.el.ElPropertyValue; -import com.avaje.ebeaninternal.server.query.SplitName; - /** * Represents the internal structure of an Object Relational query. *

@@ -65,17 +63,17 @@ public class OrmQueryDetail implements Serializable { /** * Calculate the hash for the query plan. */ - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { if (baseProps == null) { builder.add(false); } else { builder.add(true); - baseProps.queryPlanHash(request, builder); + baseProps.queryPlanHash(builder); } if (fetchPaths != null) { for (OrmQueryProperties p : fetchPaths.values()) { - p.queryPlanHash(request, builder); + p.queryPlanHash(builder); } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryProperties.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryProperties.java index 21dba9a65..75171d86e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryProperties.java @@ -1,18 +1,9 @@ package com.avaje.ebeaninternal.server.querydefn; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - import com.avaje.ebean.ExpressionFactory; 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.SpiExpression; import com.avaje.ebeaninternal.api.SpiExpressionFactory; @@ -23,6 +14,14 @@ import com.avaje.ebeaninternal.server.lib.util.StringHelper; import com.avaje.ebeaninternal.server.query.SplitName; import com.avaje.ebeaninternal.util.FilterExpressionList; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + /** * Represents the Properties of an Object Relational query. */ @@ -334,7 +333,7 @@ public class OrmQueryProperties implements Serializable { * Calculate the query plan hash. */ @SuppressWarnings("unchecked") - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(path); if (properties != null) { @@ -344,7 +343,7 @@ public class OrmQueryProperties implements Serializable { } builder.add(filterMany != null); if (filterMany != null) { - filterMany.queryPlanHash(request, builder); + filterMany.queryPlanHash(builder); } builder.add(lazyFetchBatch); builder.add(queryFetchBatch); diff --git a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java index 7715da72c..313c31288 100644 --- a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java @@ -349,15 +349,10 @@ public class DefaultExpressionList implements SpiExpressionList { return request.getBindValues(); } - /** - * Calculate a hash based on the expressions but excluding the actual bind - * values. - */ - public void queryAutoTuneHash(HashQueryPlanBuilder builder) { - builder.add(DefaultExpressionList.class); + @Override + public void prepareExpression(BeanQueryRequest request) { for (int i = 0, size = list.size(); i < size; i++) { - SpiExpression expression = list.get(i); - expression.queryAutoTuneHash(builder); + list.get(i).prepareExpression(request); } } @@ -366,11 +361,10 @@ public class DefaultExpressionList implements SpiExpressionList { * values. */ @Override - public void queryPlanHash(BeanQueryRequest request, HashQueryPlanBuilder builder) { + public void queryPlanHash(HashQueryPlanBuilder builder) { builder.add(DefaultExpressionList.class); for (int i = 0, size = list.size(); i < size; i++) { - SpiExpression expression = list.get(i); - expression.queryPlanHash(request, builder); + list.get(i).queryPlanHash(builder); } } @@ -380,8 +374,7 @@ public class DefaultExpressionList implements SpiExpressionList { public int queryBindHash() { int hash = DefaultExpressionList.class.getName().hashCode(); for (int i = 0, size = list.size(); i < size; i++) { - SpiExpression expression = list.get(i); - hash = hash * 31 + expression.queryBindHash(); + hash = hash * 31 + list.get(i).queryBindHash(); } return hash; } diff --git a/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java b/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java index 3e6ad2696..4cdade37c 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java @@ -42,8 +42,10 @@ public class DefaultExampleExpressionTest extends BaseTestCase { BeanQueryRequest request = create(query, desc); + expr.prepareExpression(request); + HashQueryPlanBuilder builder = new HashQueryPlanBuilder(); - expr.queryPlanHash(request, builder); + expr.queryPlanHash(builder); TDSpiExpressionRequest req = new TDSpiExpressionRequest(desc); expr.addBindValues(req); diff --git a/src/test/java/com/avaje/ebeaninternal/server/expression/InExpressionTest.java b/src/test/java/com/avaje/ebeaninternal/server/expression/InExpressionTest.java index 7c1b6e8ae..6930d0942 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/expression/InExpressionTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/expression/InExpressionTest.java @@ -20,10 +20,10 @@ public class InExpressionTest { InExpression ex2 = new InExpression("bar", values, false); HashQueryPlanBuilder b1 = new HashQueryPlanBuilder(); - ex1.queryPlanHash(null, b1); + ex1.queryPlanHash(b1); HashQueryPlanBuilder b2 = new HashQueryPlanBuilder(); - ex2.queryPlanHash(null, b2); + ex2.queryPlanHash(b2); assertNotEquals(b1.build(), b2.build()); } @@ -38,10 +38,10 @@ public class InExpressionTest { InExpression ex2 = new InExpression("foo", values2, false); HashQueryPlanBuilder b1 = new HashQueryPlanBuilder(); - ex1.queryPlanHash(null, b1); + ex1.queryPlanHash(b1); HashQueryPlanBuilder b2 = new HashQueryPlanBuilder(); - ex2.queryPlanHash(null, b2); + ex2.queryPlanHash(b2); assertNotEquals(b1.build(), b2.build()); } @@ -55,10 +55,10 @@ public class InExpressionTest { InExpression ex2 = new InExpression("foo", values, false); HashQueryPlanBuilder b1 = new HashQueryPlanBuilder(); - ex1.queryPlanHash(null, b1); + ex1.queryPlanHash(b1); HashQueryPlanBuilder b2 = new HashQueryPlanBuilder(); - ex2.queryPlanHash(null, b2); + ex2.queryPlanHash(b2); assertNotEquals(b1.build(), b2.build()); } @@ -72,10 +72,10 @@ public class InExpressionTest { InExpression ex2 = new InExpression("foo", values, true); HashQueryPlanBuilder b1 = new HashQueryPlanBuilder(); - ex1.queryPlanHash(null, b1); + ex1.queryPlanHash(b1); HashQueryPlanBuilder b2 = new HashQueryPlanBuilder(); - ex2.queryPlanHash(null, b2); + ex2.queryPlanHash(b2); assertEquals(b1.build(), b2.build()); }