mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge pull request #2298 from ebean-orm/FOCONIS-md5-for-querybindhash
Foconis md5 for querybindhash
This commit is contained in:
@@ -4,11 +4,7 @@ import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
@@ -54,12 +50,11 @@ public class BindParams implements Serializable {
|
||||
positionedParameters.clear();
|
||||
}
|
||||
|
||||
public int queryBindHash() {
|
||||
int hc = namedParameters.hashCode();
|
||||
for (Param positionedParameter : positionedParameters) {
|
||||
hc = hc * 92821 + positionedParameter.hashCode();
|
||||
public void queryBindHash(BindValuesKey key) {
|
||||
key.add(positionedParameters.size());
|
||||
for (Param param : positionedParameters) {
|
||||
param.queryBindHash(key);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,7 +419,14 @@ public class BindParams implements Serializable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o != null && (o == this || (o instanceof Param) && hashCode() == o.hashCode());
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Param param = (Param) o;
|
||||
return isInParam == param.isInParam && isOutParam == param.isOutParam && type == param.type && Objects.equals(inValue, param.inValue);
|
||||
}
|
||||
|
||||
void queryBindHash(BindValuesKey key) {
|
||||
key.add(isInParam).add(isOutParam).add(type).add(inValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BindValues used for L2 query cache key matching.
|
||||
* <p>
|
||||
* The equals/hashCode implementation must meet the requirement that the query bind values
|
||||
* match for L2 query cache hit (given the query plan hash is already a match).
|
||||
*/
|
||||
public class BindValuesKey {
|
||||
|
||||
private final List<Object> values = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a bind value.
|
||||
*/
|
||||
public BindValuesKey add(Object value) {
|
||||
values.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof BindValuesKey && ((BindValuesKey) obj).values.equals(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return values.hashCode();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,15 +6,14 @@ package io.ebeaninternal.api;
|
||||
public class HashQuery {
|
||||
|
||||
private final CQueryPlanKey planHash;
|
||||
|
||||
private final int bindHash;
|
||||
private final BindValuesKey bindValuesKey;
|
||||
|
||||
/**
|
||||
* Create the HashQuery.
|
||||
*/
|
||||
public HashQuery(CQueryPlanKey planHash, int bindHash) {
|
||||
public HashQuery(CQueryPlanKey planHash, BindValuesKey bindValuesKey) {
|
||||
this.planHash = planHash;
|
||||
this.bindHash = bindHash;
|
||||
this.bindValuesKey = bindValuesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,7 +24,7 @@ public class HashQuery {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = 92821 * planHash.hashCode();
|
||||
hc = 92821 * hc + bindHash;
|
||||
hc = 92821 * hc + bindValuesKey.hashCode();
|
||||
return hc;
|
||||
}
|
||||
|
||||
@@ -37,8 +36,7 @@ public class HashQuery {
|
||||
if (!(obj instanceof HashQuery)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashQuery e = (HashQuery) obj;
|
||||
return e.bindHash == bindHash && e.planHash.equals(planHash);
|
||||
return e.bindValuesKey.equals(bindValuesKey) && e.planHash.equals(planHash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ public interface SpiExpression extends Expression {
|
||||
void queryPlanHash(StringBuilder builder);
|
||||
|
||||
/**
|
||||
* Return the hash value for the values that will be bound.
|
||||
* Build the key for bind values of the query.
|
||||
*/
|
||||
int queryBindHash();
|
||||
void queryBindKey(BindValuesKey key);
|
||||
|
||||
/**
|
||||
* Return true if the expression is the same with respect to bind values.
|
||||
|
||||
@@ -629,13 +629,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
|
||||
CQueryPlanKey prepare(SpiOrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the bind values used in the query.
|
||||
* Build the key for the bind values used in the query (for l2 query cache).
|
||||
* <p>
|
||||
* Combined with queryPlanHash() to return getQueryHash (a unique hash for a
|
||||
* query).
|
||||
* </p>
|
||||
* Combined with queryPlanHash() to return queryHash (a unique key for a query).
|
||||
*/
|
||||
int queryBindHash();
|
||||
void queryBindKey(BindValuesKey key);
|
||||
|
||||
/**
|
||||
* Identifies queries that are exactly the same including bind variables.
|
||||
|
||||
+4
-3
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -37,9 +38,9 @@ public abstract class AbstractTextExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return 0;
|
||||
}
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
// do nothing, only execute against document store
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
|
||||
+4
-6
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -122,14 +123,11 @@ class AllEqualsExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
|
||||
int hc = 92821;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(propMap.size());
|
||||
for (Object value : propMap.values()) {
|
||||
hc = hc * 92821 + (value == null ? 0 : value.hashCode());
|
||||
key.add(value);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-5
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -49,12 +50,11 @@ public class ArrayContainsExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = values[0].hashCode();
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
hc = hc * 92821 + values[i].hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(values.length);
|
||||
for (Object value : values) {
|
||||
key.add(value);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -33,8 +34,8 @@ public class ArrayIsEmptyExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return empty ? 0 : 92821;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(empty);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -49,10 +50,8 @@ class BetweenExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = low().hashCode();
|
||||
hc = hc * 92821 + high().hashCode();
|
||||
return hc;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(low()).add(high());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -95,8 +96,8 @@ class BetweenPropertyExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return val().hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(val());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -39,8 +40,8 @@ class BitwiseExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return Long.hashCode(flags);
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(flags).add(match);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
@@ -69,8 +70,8 @@ class CaseInsensitiveEqualExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return val().hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(val());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-8
@@ -5,6 +5,7 @@ import io.ebean.LikeType;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -237,16 +238,12 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
|
||||
builder.append("]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash for the actual bind values used.
|
||||
*/
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = DefaultExampleExpression.class.getName().hashCode();
|
||||
for (SpiExpression aList : list) {
|
||||
hc = hc * 92821 + aList.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(list.size());
|
||||
for (SpiExpression expr : list) {
|
||||
expr.queryBindKey(key);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-8
@@ -26,6 +26,7 @@ import io.ebean.search.MultiMatch;
|
||||
import io.ebean.search.TextCommonTerms;
|
||||
import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -674,16 +675,12 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
builder.append("]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the expressions.
|
||||
*/
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hash = DefaultExpressionList.class.getName().hashCode();
|
||||
for (SpiExpression aList : list) {
|
||||
hash = hash * 92821 + aList.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(list.size());
|
||||
for (SpiExpression expr : list) {
|
||||
expr.queryBindKey(key);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -91,8 +92,8 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return subQuery.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
subQuery.queryBindKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -77,8 +78,8 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return value.hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -133,8 +134,11 @@ public class IdInExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return idCollection.hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(idCollection.size());
|
||||
for (Object elem : idCollection) {
|
||||
key.add(elem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -176,12 +177,11 @@ class InExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = 92821;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(bindValues.size());
|
||||
for (Object bindValue : bindValues) {
|
||||
hc = 92821 * hc + bindValue.hashCode();
|
||||
key.add(bindValue);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.Pairs;
|
||||
import io.ebean.Pairs.Entry;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -124,12 +125,11 @@ class InPairsExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = 92821;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(entries.size());
|
||||
for (Pairs.Entry entry : entries) {
|
||||
hc = 92821 * hc + entry.hashCode();
|
||||
key.add(entry.getA()).add(entry.getB());
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -72,8 +73,8 @@ class InQueryExpression extends AbstractExpression implements UnsupportedDocStor
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return subQuery.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
subQuery.queryBindKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -47,10 +48,8 @@ class InRangeExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = low().hashCode();
|
||||
hc = hc * 92821 + high().hashCode();
|
||||
return hc;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(low()).add(high());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -103,8 +104,8 @@ class IsEmptyExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return 1;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
// no bind values
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
|
||||
@@ -83,10 +84,8 @@ class JsonPathExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = (value == null) ? 0 : value.hashCode();
|
||||
hc = (upperValue == null) ? hc : hc * 92821 + upperValue.hashCode();
|
||||
return hc;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(value).add(upperValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-28
@@ -25,6 +25,7 @@ import io.ebean.search.MultiMatch;
|
||||
import io.ebean.search.TextCommonTerms;
|
||||
import io.ebean.search.TextQueryString;
|
||||
import io.ebean.search.TextSimple;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -113,9 +114,8 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
@Override
|
||||
public void writeDocQuery(DocQueryContext context) throws IOException {
|
||||
context.startBool(type);
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (SpiExpression aList : list) {
|
||||
aList.writeDocQuery(context);
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.writeDocQuery(context);
|
||||
}
|
||||
context.endBool();
|
||||
}
|
||||
@@ -123,9 +123,8 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
@Override
|
||||
public void writeDocQueryJunction(DocQueryContext context) throws IOException {
|
||||
context.startBoolGroupList(type);
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (SpiExpression aList : list) {
|
||||
aList.writeDocQuery(context);
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.writeDocQuery(context);
|
||||
}
|
||||
context.endBoolGroupList();
|
||||
}
|
||||
@@ -138,18 +137,15 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
|
||||
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
|
||||
// get the current state for 'require outer joins'
|
||||
boolean parentOuterJoins = manyWhereJoin.isRequireOuterJoins();
|
||||
if (type == Type.OR) {
|
||||
// turn on outer joins required for disjunction expressions
|
||||
manyWhereJoin.setRequireOuterJoins(true);
|
||||
}
|
||||
|
||||
for (SpiExpression aList : list) {
|
||||
aList.containsMany(desc, manyWhereJoin);
|
||||
for (SpiExpression expr : list) {
|
||||
expr.containsMany(desc, manyWhereJoin);
|
||||
}
|
||||
if (type == Type.OR && !parentOuterJoins) {
|
||||
// restore state to not forcing outer joins
|
||||
@@ -176,18 +172,14 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (SpiExpression aList : list) {
|
||||
aList.addBindValues(request);
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.addBindValues(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
request.append(type.prefix());
|
||||
request.append("(");
|
||||
@@ -204,9 +196,8 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public void prepareExpression(BeanQueryRequest<?> request) {
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (SpiExpression aList : list) {
|
||||
aList.prepareExpression(request);
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.prepareExpression(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,13 +216,10 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = JunctionExpression.class.getName().hashCode();
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (SpiExpression aList : list) {
|
||||
hc = hc * 92821 + aList.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
for (SpiExpression expr : exprList.internalList()) {
|
||||
expr.queryBindKey(key);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -275,7 +263,6 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.textCommonTerms(search, options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> allEq(Map<String, Object> propertyMap) {
|
||||
return exprList.allEq(propertyMap);
|
||||
@@ -1025,7 +1012,6 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public String nestedPath(BeanDescriptor<?> desc) {
|
||||
|
||||
PrepareDocNested.prepare(exprList, desc, type);
|
||||
String nestedPath = exprList.allDocNestedPath;
|
||||
if (nestedPath != null) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.LikeType;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
@@ -70,8 +71,8 @@ class LikeExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return strValue().hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(strValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.Junction;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -168,10 +169,8 @@ abstract class LogicExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = expOne.queryBindHash();
|
||||
hc = hc * 92821 + expTwo.queryBindHash();
|
||||
return hc;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(expOne).add(expTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.LikeType;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
@@ -54,8 +55,8 @@ class NativeILikeExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return val.hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -79,8 +80,8 @@ class NestedPathWrapperExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return delegate.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
delegate.queryBindKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -74,9 +75,8 @@ class NoopExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
// no bind values
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
@@ -99,8 +100,8 @@ final class NotExpression implements SpiExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return exp.queryBindHash();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
exp.queryBindKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -94,7 +95,7 @@ class NullExpression extends AbstractExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return (notNull ? 1 : 0);
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(notNull);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.expression;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
@@ -73,12 +74,11 @@ class RawExpression extends NonPrepareExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = sql.hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(values.length);
|
||||
for (Object value : values) {
|
||||
hc = hc * 92821 + value.hashCode();
|
||||
key.add(value);
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebean.plugin.ExpressionPath;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -121,8 +122,8 @@ public class SimpleExpression extends AbstractValueExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
return value().hashCode();
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(value());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Holds a list of bind values for binding to a PreparedStatement.
|
||||
*/
|
||||
class BindValues {
|
||||
|
||||
private final ArrayList<Value> list = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create with a Binder.
|
||||
*/
|
||||
public BindValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bind value with its JDBC datatype.
|
||||
*
|
||||
* @param value the bind value
|
||||
* @param dbType the type as per java.sql.Types
|
||||
*/
|
||||
public void add(Object value, int dbType, String name) {
|
||||
list.add(new Value(value, dbType, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* List of bind values.
|
||||
*/
|
||||
public ArrayList<Value> values() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Value has additionally the JDBC data type.
|
||||
*/
|
||||
public static class Value {
|
||||
|
||||
private final Object value;
|
||||
|
||||
private final int dbType;
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Create the value.
|
||||
*/
|
||||
Value(Object value, int dbType, String name) {
|
||||
this.value = value;
|
||||
this.dbType = dbType;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type as per java.sql.Types.
|
||||
*/
|
||||
public int getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,33 +77,6 @@ public class Binder {
|
||||
return asOfStandardsBased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the values to the Prepared Statement.
|
||||
*/
|
||||
public void bind(BindValues bindValues, DataBind dataBind, StringBuilder bindBuf) throws SQLException {
|
||||
String logPrefix = "";
|
||||
ArrayList<BindValues.Value> list = bindValues.values();
|
||||
for (BindValues.Value bindValue : list) {
|
||||
Object val = bindValue.getValue();
|
||||
int dt = bindValue.getDbType();
|
||||
bindObject(dataBind, val, dt);
|
||||
|
||||
if (bindBuf != null) {
|
||||
bindBuf.append(logPrefix);
|
||||
if (logPrefix.isEmpty()) {
|
||||
logPrefix = ", ";
|
||||
}
|
||||
bindBuf.append(bindValue.getName());
|
||||
bindBuf.append("=");
|
||||
if (isLob(dt)) {
|
||||
bindBuf.append("[LOB]");
|
||||
} else {
|
||||
bindBuf.append(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the parameters to the preparedStatement returning the bind log.
|
||||
*/
|
||||
|
||||
@@ -1,30 +1,7 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.CountDistinctOrder;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.Expression;
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.FetchGroup;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.FutureIds;
|
||||
import io.ebean.FutureList;
|
||||
import io.ebean.FutureRowCount;
|
||||
import io.ebean.OrderBy;
|
||||
import io.ebean.*;
|
||||
import io.ebean.OrderBy.Property;
|
||||
import io.ebean.PagedList;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.QueryIterator;
|
||||
import io.ebean.QueryType;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.UpdateQuery;
|
||||
import io.ebean.Version;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.ObjectGraphOrigin;
|
||||
@@ -32,29 +9,10 @@ import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.event.BeanQueryRequest;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.CQueryPlanKey;
|
||||
import io.ebeaninternal.api.CacheIdLookup;
|
||||
import io.ebeaninternal.api.CacheIdLookupMany;
|
||||
import io.ebeaninternal.api.CacheIdLookupSingle;
|
||||
import io.ebeaninternal.api.HashQuery;
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.api.NaturalKeyQueryData;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiExpression;
|
||||
import io.ebeaninternal.api.SpiExpressionList;
|
||||
import io.ebeaninternal.api.SpiExpressionValidation;
|
||||
import io.ebeaninternal.api.SpiNamedParam;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuerySecondary;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.server.autotune.ProfilingListener;
|
||||
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanNaturalKey;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.InheritInfo;
|
||||
import io.ebeaninternal.server.deploy.TableJoin;
|
||||
import io.ebeaninternal.server.deploy.*;
|
||||
import io.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import io.ebeaninternal.server.expression.DefaultExpressionList;
|
||||
import io.ebeaninternal.server.expression.IdInExpression;
|
||||
@@ -66,14 +24,7 @@ import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
@@ -91,8 +42,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -1269,22 +1218,13 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the bind values used in the query.
|
||||
* <p>
|
||||
* Used with queryPlanHash() to get a unique hash for a query.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = (id == null ? 0 : id.hashCode());
|
||||
hc = hc * 92821 + (whereExpressions == null ? 0 : whereExpressions.queryBindHash());
|
||||
hc = hc * 92821 + (havingExpressions == null ? 0 : havingExpressions.queryBindHash());
|
||||
hc = hc * 92821 + (bindParams == null ? 0 : bindParams.queryBindHash());
|
||||
hc = hc * 92821 + (asOf == null ? 0 : asOf.hashCode());
|
||||
hc = hc * 92821 + (versionsStart == null ? 0 : versionsStart.hashCode());
|
||||
hc = hc * 92821 + (versionsEnd == null ? 0 : versionsEnd.hashCode());
|
||||
return hc;
|
||||
public void queryBindKey(BindValuesKey key) {
|
||||
key.add(id);
|
||||
if (whereExpressions != null) whereExpressions.queryBindKey(key);
|
||||
if (havingExpressions != null) havingExpressions.queryBindKey(key);
|
||||
if (bindParams != null) bindParams.queryBindHash(key);
|
||||
key.add(asOf).add(versionsStart).add(versionsEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1298,8 +1238,9 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
public HashQuery queryHash() {
|
||||
// calculateQueryPlanHash is called just after potential AutoTune tuning
|
||||
// so queryPlanHash is calculated well before this method is called
|
||||
int hc = queryBindHash();
|
||||
return new HashQuery(queryPlanKey, hc);
|
||||
BindValuesKey bindKey = new BindValuesKey();
|
||||
queryBindKey(bindKey);
|
||||
return new HashQuery(queryPlanKey, bindKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.expression;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
|
||||
public class RawExpressionTest extends BaseExpressionTest {
|
||||
|
||||
@@ -61,11 +62,16 @@ public class RawExpressionTest extends BaseExpressionTest {
|
||||
}
|
||||
|
||||
public void assert_queryBindHash_isDifferent(RawExpression exp0, RawExpression exp1) {
|
||||
assertThat(exp0.queryBindHash()).isNotEqualTo(exp1.queryBindHash());
|
||||
assertThat(bindKey(exp0)).isNotEqualTo(bindKey(exp1));
|
||||
}
|
||||
|
||||
public void assert_queryBindHash_isSame(RawExpression exp0, RawExpression exp1) {
|
||||
assertThat(exp0.queryBindHash()).isEqualTo(exp1.queryBindHash());
|
||||
assertThat(bindKey(exp0)).isEqualTo(bindKey(exp1));
|
||||
}
|
||||
|
||||
private BindValuesKey bindKey(RawExpression query) {
|
||||
BindValuesKey bindValuesKey = new BindValuesKey();
|
||||
query.queryBindKey(bindValuesKey);
|
||||
return bindValuesKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class BindValuesKeyTest {
|
||||
|
||||
@Test
|
||||
public void update_with_null() {
|
||||
|
||||
BindValuesKey hash = new BindValuesKey();
|
||||
hash.add(1).add(null).add("hello");
|
||||
|
||||
BindValuesKey hash2 = new BindValuesKey();
|
||||
hash2.add(1).add(null).add("hello");
|
||||
|
||||
assertThat(hash).isEqualTo(hash2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notEqual() {
|
||||
|
||||
BindValuesKey hash = new BindValuesKey();
|
||||
hash.add(1).add(null).add("hello");
|
||||
|
||||
BindValuesKey hash2 = new BindValuesKey();
|
||||
hash2.add(1).add("hello");
|
||||
|
||||
BindValuesKey hash3 = new BindValuesKey();
|
||||
hash2.add(1).add(null);
|
||||
|
||||
assertThat(hash).isNotEqualTo(hash2);
|
||||
assertThat(hash).isNotEqualTo(hash3);
|
||||
assertThat(hash2).isNotEqualTo(hash3);
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -4,6 +4,7 @@ package io.ebeaninternal.server.querydefn;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebeaninternal.api.BindValuesKey;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import org.junit.Test;
|
||||
@@ -62,7 +63,7 @@ public class DefaultOrmQueryTest extends BaseTestCase {
|
||||
|
||||
prepare(q1, q2);
|
||||
assertThat(q1.createQueryPlanKey()).isNotEqualTo(q2.createQueryPlanKey());
|
||||
assertThat(q1.queryBindHash()).isNotEqualTo(q2.queryBindHash());
|
||||
assertThat(bindKey(q1)).isNotEqualTo(bindKey(q2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -73,7 +74,7 @@ public class DefaultOrmQueryTest extends BaseTestCase {
|
||||
|
||||
prepare(q1, q2);
|
||||
assertThat(q1.createQueryPlanKey()).isEqualTo(q2.createQueryPlanKey());
|
||||
assertThat(q1.queryBindHash()).isNotEqualTo(q2.queryBindHash());
|
||||
assertThat(bindKey(q1)).isNotEqualTo(bindKey(q2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,7 +85,7 @@ public class DefaultOrmQueryTest extends BaseTestCase {
|
||||
|
||||
prepare(q1, q2);
|
||||
assertThat(q1.createQueryPlanKey()).isEqualTo(q2.createQueryPlanKey());
|
||||
assertThat(q1.queryBindHash()).isEqualTo(q2.queryBindHash());
|
||||
assertThat(bindKey(q1)).isEqualTo(bindKey(q2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,4 +111,10 @@ public class DefaultOrmQueryTest extends BaseTestCase {
|
||||
OrmQueryRequest<T> r2 = createQueryRequest(SpiQuery.Type.LIST, q2, null);
|
||||
q2.prepare(r2);
|
||||
}
|
||||
|
||||
private BindValuesKey bindKey(DefaultOrmQuery<Order> query) {
|
||||
BindValuesKey key = new BindValuesKey();
|
||||
query.queryBindKey(key);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
+58
-28
@@ -3,7 +3,7 @@ package org.tests.cache;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
@@ -14,6 +14,7 @@ import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.cache.EColAB;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -26,8 +27,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
new EColAB("02", "10").save();
|
||||
|
||||
List<EColAB> list1 =
|
||||
Ebean.getServer(null)
|
||||
.find(EColAB.class)
|
||||
DB.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.where()
|
||||
.eq("columnA", "01")
|
||||
@@ -35,8 +35,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
.findList();
|
||||
|
||||
List<EColAB> list2 =
|
||||
Ebean.getServer(null)
|
||||
.find(EColAB.class)
|
||||
DB.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.where()
|
||||
.eq("columnA", "02")
|
||||
@@ -57,7 +56,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
new EColAB("03", "SingleAttribute").save();
|
||||
new EColAB("03", "SingleAttribute").save();
|
||||
|
||||
List<String> colA_first = Ebean.getServer(null)
|
||||
List<String> colA_first = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.setDistinct(true)
|
||||
@@ -66,7 +65,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
.eq("columnB", "SingleAttribute")
|
||||
.findSingleAttributeList();
|
||||
|
||||
List<String> colA_Second = Ebean.getServer(null)
|
||||
List<String> colA_Second = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.setDistinct(true)
|
||||
@@ -77,7 +76,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
assertThat(colA_Second).isSameAs(colA_first);
|
||||
|
||||
List<String> colA_NotDistinct = Ebean.getServer(null)
|
||||
List<String> colA_NotDistinct = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
@@ -89,7 +88,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
// ensure that findCount & findSingleAttribute use different
|
||||
// slots in cache. If not a "Cannot cast List to int" should happen.
|
||||
int count = Ebean.getServer(null)
|
||||
int count = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
@@ -107,13 +106,13 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int count0 = Ebean.find(EColAB.class)
|
||||
int count0 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "count")
|
||||
.findCount();
|
||||
|
||||
int count1 = Ebean.find(EColAB.class)
|
||||
int count1 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "count")
|
||||
@@ -126,7 +125,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
// and now, ensure that we hit the database
|
||||
LoggedSqlCollector.start();
|
||||
int count2 = Ebean.find(EColAB.class)
|
||||
int count2 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.OFF)
|
||||
.where()
|
||||
.eq("columnB", "count")
|
||||
@@ -142,13 +141,13 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int count0 = Ebean.find(EColAB.class)
|
||||
int count0 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "abc")
|
||||
.findCount();
|
||||
|
||||
int count1 = Ebean.find(EColAB.class)
|
||||
int count1 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "def")
|
||||
@@ -167,13 +166,13 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int count0 = Ebean.find(EColAB.class)
|
||||
int count0 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "uvw")
|
||||
.findCount();
|
||||
|
||||
int count1 = Ebean.find(EColAB.class)
|
||||
int count1 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "uvw")
|
||||
@@ -193,13 +192,13 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int count0 = Ebean.find(EColAB.class)
|
||||
int count0 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "xyz")
|
||||
.findCount();
|
||||
|
||||
int count1 = Ebean.find(EColAB.class)
|
||||
int count1 = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "xyz")
|
||||
@@ -214,26 +213,26 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void test() {
|
||||
public void testReadOnlyFind() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
ServerCache customerCache = Ebean.getServerCacheManager().getQueryCache(Customer.class);
|
||||
ServerCache customerCache = DB.getServerCacheManager().getQueryCache(Customer.class);
|
||||
customerCache.clear();
|
||||
|
||||
List<Customer> list = Ebean.find(Customer.class).setUseQueryCache(true).setReadOnly(true).where()
|
||||
List<Customer> list = DB.find(Customer.class).setUseQueryCache(true).setReadOnly(true).where()
|
||||
.ilike("name", "Rob").findList();
|
||||
|
||||
BeanCollection<Customer> bc = (BeanCollection<Customer>) list;
|
||||
Assert.assertTrue(bc.isReadOnly());
|
||||
Assert.assertFalse(bc.isEmpty());
|
||||
Assert.assertTrue(!list.isEmpty());
|
||||
Assert.assertTrue(Ebean.getBeanState(list.get(0)).isReadOnly());
|
||||
Assert.assertTrue(DB.getBeanState(list.get(0)).isReadOnly());
|
||||
|
||||
List<Customer> list2 = Ebean.find(Customer.class).setUseQueryCache(true).setReadOnly(true).where()
|
||||
List<Customer> list2 = DB.find(Customer.class).setUseQueryCache(true).setReadOnly(true).where()
|
||||
.ilike("name", "Rob").findList();
|
||||
|
||||
List<Customer> list2B = Ebean.find(Customer.class).setUseQueryCache(true)
|
||||
List<Customer> list2B = DB.find(Customer.class).setUseQueryCache(true)
|
||||
// .setReadOnly(true)
|
||||
.where().ilike("name", "Rob").findList();
|
||||
|
||||
@@ -245,7 +244,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
|
||||
|
||||
List<Customer> list3 = Ebean.find(Customer.class).setUseQueryCache(true).setReadOnly(false).where()
|
||||
List<Customer> list3 = DB.find(Customer.class).setUseQueryCache(true).setReadOnly(false).where()
|
||||
.ilike("name", "Rob").findList();
|
||||
|
||||
Assert.assertNotSame(list, list3);
|
||||
@@ -269,13 +268,13 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<Integer> colA_first = Ebean.find(EColAB.class)
|
||||
List<Integer> colA_first = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
.findIds();
|
||||
|
||||
List<Integer> colA_second = Ebean.find(EColAB.class)
|
||||
List<Integer> colA_second = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.ON)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
@@ -289,7 +288,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
// and now, ensure that we hit the database
|
||||
LoggedSqlCollector.start();
|
||||
colA_second = Ebean.find(EColAB.class)
|
||||
colA_second = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
@@ -299,4 +298,35 @@ public class TestQueryCache extends BaseTestCase {
|
||||
assertThat(sql).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findCountDifferentQueriesBit() {
|
||||
DB.getDefault().getPluginApi().getServerCacheManager().clearAll();
|
||||
differentFindCount(q->q.bitwiseAny("id",1), q->q.bitwiseAny("id",0));
|
||||
differentFindCount(q->q.bitwiseAll("id",1), q->q.bitwiseAll("id",0));
|
||||
// differentFindCount(q->q.bitwiseNot("id",1), q->q.bitwiseNot("id",0)); NOT 1 == AND 1 = 0
|
||||
differentFindCount(q->q.bitwiseAnd("id",1, 0), q->q.bitwiseAnd("id",1, 1));
|
||||
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 0), q->q.bitwiseAnd("id",4, 0));
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 1), q->q.bitwiseAnd("id",4, 1));
|
||||
// Will produce hash collision
|
||||
differentFindCount(q->q.bitwiseAnd("id",10, 0), q->q.bitwiseAnd("id",0, 928210));
|
||||
|
||||
}
|
||||
|
||||
void differentFindCount(Consumer<ExpressionList<EColAB>> q0, Consumer<ExpressionList<EColAB>> q1) {
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
ExpressionList<EColAB> el0 = DB.find(EColAB.class).setUseQueryCache(CacheMode.ON).where();
|
||||
q0.accept(el0);
|
||||
el0.findCount();
|
||||
|
||||
ExpressionList<EColAB> el1 = DB.find(EColAB.class).setUseQueryCache(CacheMode.ON).where();
|
||||
q1.accept(el1);
|
||||
el1.findCount();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql).hasSize(2); // different queries
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user