FIX: Pairs must not be modified by query (#1539)

* FIX: Pairs must not be modified by query

* Modification can also occur on inValues.

* fixed tests

* removed obsolete line
This commit is contained in:
Roland Praml
2018-11-13 23:41:36 +13:00
committed by Rob Bygrave
parent 01d9dd3fe8
commit 105f08cca1
5 changed files with 47 additions and 27 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
package io.ebean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -125,7 +126,7 @@ public class Pairs {
* Return all the value pairs.
*/
public List<Entry> getEntries() {
return entries;
return Collections.unmodifiableList(entries);
}
/**
@@ -25,7 +25,7 @@ public class NaturalKeyQueryData<T> {
private List<Pairs.Entry> inPairs;
// IN clause - only one allowed
private Collection<?> inValues;
private List<Object> inValues;
private String inProperty;
// normal EQ expressions
@@ -52,36 +52,36 @@ public class NaturalKeyQueryData<T> {
/**
* Match for In Pairs expression. We only allow one IN clause.
*/
public boolean matchInPairs(Pairs pairs) {
public List<Pairs.Entry> matchInPairs(String property0, String property1, List<Pairs.Entry> inPairs) {
if (hasIn) {
// only 1 IN allowed (to project naturalIds)
return false;
return null;
}
if (matchProperty(pairs.getProperty0()) && matchProperty(pairs.getProperty1())) {
if (matchProperty(property0) && matchProperty(property1)) {
this.hasIn = true;
this.inProperty0 = pairs.getProperty0();
this.inProperty1 = pairs.getProperty1();
this.inPairs = pairs.getEntries();
return true;
this.inProperty0 = property0;
this.inProperty1 = property1;
this.inPairs = new ArrayList<>(inPairs); // will be modified
return this.inPairs;
}
return false;
return null;
}
/**
* Match for IN expression. We only allow one IN clause.
*/
public boolean matchIn(String propName, Collection<?> sourceValues) {
public List<Object> matchIn(String propName, List<Object> sourceValues) {
if (hasIn) {
// only 1 IN allowed (to project naturalIds)
return false;
return null;
}
if (matchProperty(propName)) {
this.hasIn = true;
this.inProperty = propName;
this.inValues = sourceValues;
return true;
this.inValues = new ArrayList<>(sourceValues);
return this.inValues;
}
return false;
return null;
}
/**
@@ -48,8 +48,16 @@ class InExpression extends AbstractExpression {
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache for NOT IN
return !not && data.matchIn(propName, bindValues);
// can't use naturalKey cache for NOT IN or if multi values are used
if (not || multiValueSupported) {
return false;
}
List<Object> copy = data.matchIn(propName, bindValues);
if (copy == null) {
return false;
}
bindValues = copy;
return true;
}
@Override
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.expression;
import io.ebean.Pairs;
import io.ebean.Pairs.Entry;
import io.ebean.event.BeanQueryRequest;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
@@ -15,11 +16,9 @@ class InPairsExpression extends AbstractExpression {
private final boolean not;
private final Pairs pairs;
private final String property0, property1;
private final List<Pairs.Entry> entries;
private List<Pairs.Entry> entries;
private boolean multiValueSupported;
@@ -31,9 +30,9 @@ class InPairsExpression extends AbstractExpression {
InPairsExpression(Pairs pairs, boolean not) {
super(pairs.getProperty0());
this.pairs = pairs;
this.property0 = pairs.getProperty0();
this.property1 = pairs.getProperty1();
// the entries might be modified on cache hit.
this.entries = pairs.getEntries();
this.not = not;
this.separator = pairs.getConcatSeparator();
@@ -42,7 +41,15 @@ class InPairsExpression extends AbstractExpression {
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
return !not && data.matchInPairs(pairs);
if (not) {
return false;
}
List<Entry> copy = data.matchInPairs(property0, property1, entries);
if (copy == null) {
return false;
}
entries = copy;
return true;
}
@Override