mirror of https://github.com/apache/lucene.git
SOLR-10830: Solr now correctly enforces that the '_root_' field has the same fieldType as the uniqueKey field
This commit is contained in:
parent
e50332507a
commit
6396cb759f
|
@ -156,6 +156,10 @@ Bug Fixes
|
|||
|
||||
* SOLR-10223: Allow running examples as root on Linux with -force option (janhoy)
|
||||
|
||||
* SOLR-10830: Solr now correctly enforces that the '_root_' field has the same fieldType as the
|
||||
uniqueKey field. With out this enforcement, child document updating was unreliable. (hossman)
|
||||
|
||||
|
||||
Optimizations
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
|
|||
if (min == null) {
|
||||
actualMin = Double.NEGATIVE_INFINITY;
|
||||
} else {
|
||||
actualMin = Double.parseDouble(min);
|
||||
actualMin = parseDoubleFromUser(field.getName(), min);
|
||||
if (!minInclusive) {
|
||||
actualMin = DoublePoint.nextUp(actualMin);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
|
|||
if (max == null) {
|
||||
actualMax = Double.POSITIVE_INFINITY;
|
||||
} else {
|
||||
actualMax = Double.parseDouble(max);
|
||||
actualMax = parseDoubleFromUser(field.getName(), max);
|
||||
if (!maxInclusive) {
|
||||
actualMax = DoublePoint.nextDown(actualMax);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
|
|||
|
||||
@Override
|
||||
protected Query getExactQuery(SchemaField field, String externalVal) {
|
||||
return DoublePoint.newExactQuery(field.getName(), Double.parseDouble(externalVal));
|
||||
return DoublePoint.newExactQuery(field.getName(), parseDoubleFromUser(field.getName(), externalVal));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +112,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
|
|||
double[] values = new double[externalVal.size()];
|
||||
int i = 0;
|
||||
for (String val:externalVal) {
|
||||
values[i] = Double.parseDouble(val);
|
||||
values[i] = parseDoubleFromUser(field.getName(), val);
|
||||
i++;
|
||||
}
|
||||
return DoublePoint.newSetQuery(field.getName(), values);
|
||||
|
@ -127,7 +127,7 @@ public class DoublePointField extends PointField implements DoubleValueFieldType
|
|||
public void readableToIndexed(CharSequence val, BytesRefBuilder result) {
|
||||
result.grow(Double.BYTES);
|
||||
result.setLength(Double.BYTES);
|
||||
DoublePoint.encodeDimension(Double.parseDouble(val.toString()), result.bytes(), 0);
|
||||
DoublePoint.encodeDimension(parseDoubleFromUser(null, val.toString()), result.bytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -61,7 +61,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
|
|||
if (min == null) {
|
||||
actualMin = Float.NEGATIVE_INFINITY;
|
||||
} else {
|
||||
actualMin = Float.parseFloat(min);
|
||||
actualMin = parseFloatFromUser(field.getName(), min);
|
||||
if (!minInclusive) {
|
||||
actualMin = FloatPoint.nextUp(actualMin);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
|
|||
if (max == null) {
|
||||
actualMax = Float.POSITIVE_INFINITY;
|
||||
} else {
|
||||
actualMax = Float.parseFloat(max);
|
||||
actualMax = parseFloatFromUser(field.getName(), max);
|
||||
if (!maxInclusive) {
|
||||
actualMax = FloatPoint.nextDown(actualMax);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
|
|||
|
||||
@Override
|
||||
protected Query getExactQuery(SchemaField field, String externalVal) {
|
||||
return FloatPoint.newExactQuery(field.getName(), Float.parseFloat(externalVal));
|
||||
return FloatPoint.newExactQuery(field.getName(), parseFloatFromUser(field.getName(), externalVal));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +112,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
|
|||
float[] values = new float[externalVal.size()];
|
||||
int i = 0;
|
||||
for (String val:externalVal) {
|
||||
values[i] = Float.parseFloat(val);
|
||||
values[i] = parseFloatFromUser(field.getName(), val);
|
||||
i++;
|
||||
}
|
||||
return FloatPoint.newSetQuery(field.getName(), values);
|
||||
|
@ -127,7 +127,7 @@ public class FloatPointField extends PointField implements FloatValueFieldType {
|
|||
public void readableToIndexed(CharSequence val, BytesRefBuilder result) {
|
||||
result.grow(Float.BYTES);
|
||||
result.setLength(Float.BYTES);
|
||||
FloatPoint.encodeDimension(Float.parseFloat(val.toString()), result.bytes(), 0);
|
||||
FloatPoint.encodeDimension(parseFloatFromUser(null, val.toString()), result.bytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -113,6 +113,7 @@ public class IndexSchema {
|
|||
public static final String SOURCE = "source";
|
||||
public static final String TYPE = "type";
|
||||
public static final String TYPES = "types";
|
||||
public static final String ROOT_FIELD_NAME = "_root_";
|
||||
public static final String UNIQUE_KEY = "uniqueKey";
|
||||
public static final String VERSION = "version";
|
||||
|
||||
|
@ -517,6 +518,20 @@ public class IndexSchema {
|
|||
log.warn("no " + UNIQUE_KEY + " specified in schema.");
|
||||
} else {
|
||||
uniqueKeyField=getIndexedField(node.getNodeValue().trim());
|
||||
uniqueKeyFieldName=uniqueKeyField.getName();
|
||||
uniqueKeyFieldType=uniqueKeyField.getType();
|
||||
|
||||
// we fail on init if the ROOT field is *explicitly* defined as incompatible with uniqueKey
|
||||
// we don't want ot fail if there happens to be a dynamicField matching ROOT, (ie: "*")
|
||||
// because the user may not care about child docs at all. The run time code
|
||||
// related to child docs can catch that if it happens
|
||||
if (fields.containsKey(ROOT_FIELD_NAME) && ! isUsableForChildDocs()) {
|
||||
String msg = ROOT_FIELD_NAME + " field must be defined using the exact same fieldType as the " +
|
||||
UNIQUE_KEY + " field ("+uniqueKeyFieldName+") uses: " + uniqueKeyFieldType.getTypeName();
|
||||
log.error(msg);
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
|
||||
}
|
||||
|
||||
if (null != uniqueKeyField.getDefaultValue()) {
|
||||
String msg = UNIQUE_KEY + " field ("+uniqueKeyFieldName+
|
||||
") can not be configured with a default value ("+
|
||||
|
@ -542,9 +557,6 @@ public class IndexSchema {
|
|||
throw new SolrException(ErrorCode.SERVER_ERROR, msg);
|
||||
}
|
||||
|
||||
uniqueKeyFieldName=uniqueKeyField.getName();
|
||||
uniqueKeyFieldType=uniqueKeyField.getType();
|
||||
|
||||
// Unless the uniqueKeyField is marked 'required=false' then make sure it exists
|
||||
if( Boolean.FALSE != explicitRequiredProp.get( uniqueKeyFieldName ) ) {
|
||||
uniqueKeyField.required = true;
|
||||
|
@ -1914,4 +1926,17 @@ public class IndexSchema {
|
|||
+ XPATH_OR + stepsToPath(SCHEMA, TYPES, FIELD_TYPE);
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that returns <code>true</code> if the {@link #ROOT_FIELD_NAME} uses the exact
|
||||
* same 'type' as the {@link #getUniqueKeyField()}
|
||||
*
|
||||
* @lucene.internal
|
||||
*/
|
||||
public boolean isUsableForChildDocs() {
|
||||
FieldType rootType = getFieldType(ROOT_FIELD_NAME);
|
||||
return (null != uniqueKeyFieldType &&
|
||||
null != rootType &&
|
||||
rootType.getTypeName().equals(uniqueKeyFieldType.getTypeName()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
|
|||
if (min == null) {
|
||||
actualMin = Integer.MIN_VALUE;
|
||||
} else {
|
||||
actualMin = Integer.parseInt(min);
|
||||
actualMin = parseIntFromUser(field.getName(), min);
|
||||
if (!minInclusive) {
|
||||
actualMin++;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
|
|||
if (max == null) {
|
||||
actualMax = Integer.MAX_VALUE;
|
||||
} else {
|
||||
actualMax = Integer.parseInt(max);
|
||||
actualMax = parseIntFromUser(field.getName(), max);
|
||||
if (!maxInclusive) {
|
||||
actualMax--;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
|
|||
|
||||
@Override
|
||||
protected Query getExactQuery(SchemaField field, String externalVal) {
|
||||
return IntPoint.newExactQuery(field.getName(), Integer.parseInt(externalVal));
|
||||
return IntPoint.newExactQuery(field.getName(), parseIntFromUser(field.getName(), externalVal));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +109,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
|
|||
int[] values = new int[externalVal.size()];
|
||||
int i = 0;
|
||||
for (String val:externalVal) {
|
||||
values[i] = Integer.parseInt(val);
|
||||
values[i] = parseIntFromUser(field.getName(), val);
|
||||
i++;
|
||||
}
|
||||
return IntPoint.newSetQuery(field.getName(), values);
|
||||
|
@ -124,7 +124,7 @@ public class IntPointField extends PointField implements IntValueFieldType {
|
|||
public void readableToIndexed(CharSequence val, BytesRefBuilder result) {
|
||||
result.grow(Integer.BYTES);
|
||||
result.setLength(Integer.BYTES);
|
||||
IntPoint.encodeDimension(Integer.parseInt(val.toString()), result.bytes(), 0);
|
||||
IntPoint.encodeDimension(parseIntFromUser(null, val.toString()), result.bytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -63,7 +63,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
|
|||
if (min == null) {
|
||||
actualMin = Long.MIN_VALUE;
|
||||
} else {
|
||||
actualMin = Long.parseLong(min);
|
||||
actualMin = parseLongFromUser(field.getName(), min);
|
||||
if (!minInclusive) {
|
||||
actualMin++;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
|
|||
if (max == null) {
|
||||
actualMax = Long.MAX_VALUE;
|
||||
} else {
|
||||
actualMax = Long.parseLong(max);
|
||||
actualMax = parseLongFromUser(field.getName(), max);
|
||||
if (!maxInclusive) {
|
||||
actualMax--;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
|
|||
|
||||
@Override
|
||||
protected Query getExactQuery(SchemaField field, String externalVal) {
|
||||
return LongPoint.newExactQuery(field.getName(), Long.parseLong(externalVal));
|
||||
return LongPoint.newExactQuery(field.getName(), parseLongFromUser(field.getName(), externalVal));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,7 +108,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
|
|||
long[] values = new long[externalVal.size()];
|
||||
int i = 0;
|
||||
for (String val:externalVal) {
|
||||
values[i] = Long.parseLong(val);
|
||||
values[i] = parseLongFromUser(field.getName(), val);
|
||||
i++;
|
||||
}
|
||||
return LongPoint.newSetQuery(field.getName(), values);
|
||||
|
@ -123,7 +123,7 @@ public class LongPointField extends PointField implements LongValueFieldType {
|
|||
public void readableToIndexed(CharSequence val, BytesRefBuilder result) {
|
||||
result.grow(Long.BYTES);
|
||||
result.setLength(Long.BYTES);
|
||||
LongPoint.encodeDimension(Long.parseLong(val.toString()), result.bytes(), 0);
|
||||
LongPoint.encodeDimension(parseLongFromUser(null, val.toString()), result.bytes(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -56,8 +56,8 @@ public abstract class NumericFieldType extends PrimitiveFieldType {
|
|||
switch (getNumberType()) {
|
||||
case INTEGER:
|
||||
return numericDocValuesRangeQuery(field.getName(),
|
||||
min == null ? null : (long) Integer.parseInt(min),
|
||||
max == null ? null : (long) Integer.parseInt(max),
|
||||
min == null ? null : (long) parseIntFromUser(field.getName(), min),
|
||||
max == null ? null : (long) parseIntFromUser(field.getName(), max),
|
||||
minInclusive, maxInclusive, field.multiValued());
|
||||
case FLOAT:
|
||||
if (field.multiValued()) {
|
||||
|
@ -67,8 +67,8 @@ public abstract class NumericFieldType extends PrimitiveFieldType {
|
|||
}
|
||||
case LONG:
|
||||
return numericDocValuesRangeQuery(field.getName(),
|
||||
min == null ? null : Long.parseLong(min),
|
||||
max == null ? null : Long.parseLong(max),
|
||||
min == null ? null : parseLongFromUser(field.getName(), min),
|
||||
max == null ? null : parseLongFromUser(field.getName(),max),
|
||||
minInclusive, maxInclusive, field.multiValued());
|
||||
case DOUBLE:
|
||||
if (field.multiValued()) {
|
||||
|
@ -90,8 +90,8 @@ public abstract class NumericFieldType extends PrimitiveFieldType {
|
|||
Query query;
|
||||
String fieldName = sf.getName();
|
||||
|
||||
Number minVal = min == null ? null : getNumberType() == NumberType.FLOAT ? Float.parseFloat(min): Double.parseDouble(min);
|
||||
Number maxVal = max == null ? null : getNumberType() == NumberType.FLOAT ? Float.parseFloat(max): Double.parseDouble(max);
|
||||
Number minVal = min == null ? null : getNumberType() == NumberType.FLOAT ? parseFloatFromUser(sf.getName(), min): parseDoubleFromUser(sf.getName(), min);
|
||||
Number maxVal = max == null ? null : getNumberType() == NumberType.FLOAT ? parseFloatFromUser(sf.getName(), max): parseDoubleFromUser(sf.getName(), max);
|
||||
|
||||
Long minBits =
|
||||
min == null ? null : getNumberType() == NumberType.FLOAT ? (long) Float.floatToIntBits(minVal.floatValue()): Double.doubleToLongBits(minVal.doubleValue());
|
||||
|
@ -124,14 +124,14 @@ public abstract class NumericFieldType extends PrimitiveFieldType {
|
|||
}
|
||||
|
||||
protected Query getRangeQueryForMultiValuedDoubleDocValues(SchemaField sf, String min, String max, boolean minInclusive, boolean maxInclusive) {
|
||||
Long minBits = min == null ? NumericUtils.doubleToSortableLong(Double.NEGATIVE_INFINITY): NumericUtils.doubleToSortableLong(Double.parseDouble(min));
|
||||
Long maxBits = max == null ? NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY): NumericUtils.doubleToSortableLong(Double.parseDouble(max));
|
||||
Long minBits = min == null ? NumericUtils.doubleToSortableLong(Double.NEGATIVE_INFINITY): NumericUtils.doubleToSortableLong(parseDoubleFromUser(sf.getName(), min));
|
||||
Long maxBits = max == null ? NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY): NumericUtils.doubleToSortableLong(parseDoubleFromUser(sf.getName(), max));
|
||||
return numericDocValuesRangeQuery(sf.getName(), minBits, maxBits, minInclusive, maxInclusive, true);
|
||||
}
|
||||
|
||||
protected Query getRangeQueryForMultiValuedFloatDocValues(SchemaField sf, String min, String max, boolean minInclusive, boolean maxInclusive) {
|
||||
Long minBits = (long)(min == null ? NumericUtils.floatToSortableInt(Float.NEGATIVE_INFINITY): NumericUtils.floatToSortableInt(Float.parseFloat(min)));
|
||||
Long maxBits = (long)(max == null ? NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY): NumericUtils.floatToSortableInt(Float.parseFloat(max)));
|
||||
Long minBits = (long)(min == null ? NumericUtils.floatToSortableInt(Float.NEGATIVE_INFINITY): NumericUtils.floatToSortableInt(parseFloatFromUser(sf.getName(), min)));
|
||||
Long maxBits = (long)(max == null ? NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY): NumericUtils.floatToSortableInt(parseFloatFromUser(sf.getName(), max)));
|
||||
return numericDocValuesRangeQuery(sf.getName(), minBits, maxBits, minInclusive, maxInclusive, true);
|
||||
}
|
||||
|
||||
|
@ -169,4 +169,72 @@ public abstract class NumericFieldType extends PrimitiveFieldType {
|
|||
return NumericDocValuesField.newRangeQuery(field, actualLowerValue, actualUpperValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link Long#parseLong(String)} that throws a BAD_REQUEST error if the input is not valid
|
||||
* @param fieldName used in any exception, may be null
|
||||
* @param val string to parse, NPE if null
|
||||
*/
|
||||
static long parseLongFromUser(String fieldName, String val) {
|
||||
if (val == null) {
|
||||
throw new NullPointerException("Invalid input" + (null == fieldName ? "" : " for field " + fieldName));
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(val);
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Invalid Number: " + val + (null == fieldName ? "" : " for field " + fieldName);
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link Integer#parseInt(String)} that throws a BAD_REQUEST error if the input is not valid
|
||||
* @param fieldName used in any exception, may be null
|
||||
* @param val string to parse, NPE if null
|
||||
*/
|
||||
static int parseIntFromUser(String fieldName, String val) {
|
||||
if (val == null) {
|
||||
throw new NullPointerException("Invalid input" + (null == fieldName ? "" : " for field " + fieldName));
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(val);
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Invalid Number: " + val + (null == fieldName ? "" : " for field " + fieldName);
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link Double#parseDouble(String)} that throws a BAD_REQUEST error if the input is not valid
|
||||
* @param fieldName used in any exception, may be null
|
||||
* @param val string to parse, NPE if null
|
||||
*/
|
||||
static double parseDoubleFromUser(String fieldName, String val) {
|
||||
if (val == null) {
|
||||
throw new NullPointerException("Invalid input" + (null == fieldName ? "" : " for field " + fieldName));
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(val);
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Invalid Number: " + val + (null == fieldName ? "" : " for field " + fieldName);
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link Float#parseFloat(String)} that throws a BAD_REQUEST error if the input is not valid
|
||||
* @param fieldName used in any exception, may be null
|
||||
* @param val string to parse, NPE if null
|
||||
*/
|
||||
static float parseFloatFromUser(String fieldName, String val) {
|
||||
if (val == null) {
|
||||
throw new NullPointerException("Invalid input" + (null == fieldName ? "" : " for field " + fieldName));
|
||||
}
|
||||
try {
|
||||
return Float.parseFloat(val);
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Invalid Number: " + val + (null == fieldName ? "" : " for field " + fieldName);
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,6 +191,11 @@ public abstract class PointField extends NumericFieldType {
|
|||
|
||||
protected abstract String indexedToReadable(BytesRef indexedForm);
|
||||
|
||||
@Override
|
||||
public Query getPrefixQuery(QParser parser, SchemaField sf, String termStr) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can't run prefix queries on numeric fields");
|
||||
}
|
||||
|
||||
protected boolean isFieldUsed(SchemaField field) {
|
||||
boolean indexed = field.indexed();
|
||||
boolean stored = field.stored();
|
||||
|
|
|
@ -352,26 +352,26 @@ public class TrieField extends NumericFieldType {
|
|||
switch (type) {
|
||||
case INTEGER:
|
||||
query = LegacyNumericRangeQuery.newIntRange(field.getName(), ps,
|
||||
min == null ? null : Integer.parseInt(min),
|
||||
max == null ? null : Integer.parseInt(max),
|
||||
min == null ? null : parseIntFromUser(field.getName(), min),
|
||||
max == null ? null : parseIntFromUser(field.getName(), max),
|
||||
minInclusive, maxInclusive);
|
||||
break;
|
||||
case FLOAT:
|
||||
query = LegacyNumericRangeQuery.newFloatRange(field.getName(), ps,
|
||||
min == null ? null : Float.parseFloat(min),
|
||||
max == null ? null : Float.parseFloat(max),
|
||||
min == null ? null : parseFloatFromUser(field.getName(), min),
|
||||
max == null ? null : parseFloatFromUser(field.getName(), max),
|
||||
minInclusive, maxInclusive);
|
||||
break;
|
||||
case LONG:
|
||||
query = LegacyNumericRangeQuery.newLongRange(field.getName(), ps,
|
||||
min == null ? null : Long.parseLong(min),
|
||||
max == null ? null : Long.parseLong(max),
|
||||
min == null ? null : parseLongFromUser(field.getName(), min),
|
||||
max == null ? null : parseLongFromUser(field.getName(), max),
|
||||
minInclusive, maxInclusive);
|
||||
break;
|
||||
case DOUBLE:
|
||||
query = LegacyNumericRangeQuery.newDoubleRange(field.getName(), ps,
|
||||
min == null ? null : Double.parseDouble(min),
|
||||
max == null ? null : Double.parseDouble(max),
|
||||
min == null ? null : parseDoubleFromUser(field.getName(), min),
|
||||
max == null ? null : parseDoubleFromUser(field.getName(), max),
|
||||
minInclusive, maxInclusive);
|
||||
break;
|
||||
case DATE:
|
||||
|
@ -383,7 +383,6 @@ public class TrieField extends NumericFieldType {
|
|||
default:
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field");
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
@ -413,19 +412,18 @@ public class TrieField extends NumericFieldType {
|
|||
@Override
|
||||
public void readableToIndexed(CharSequence val, BytesRefBuilder result) {
|
||||
String s = val.toString();
|
||||
try {
|
||||
switch (type) {
|
||||
case INTEGER:
|
||||
LegacyNumericUtils.intToPrefixCoded(Integer.parseInt(s), 0, result);
|
||||
LegacyNumericUtils.intToPrefixCoded(parseIntFromUser(null, s), 0, result);
|
||||
break;
|
||||
case FLOAT:
|
||||
LegacyNumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(Float.parseFloat(s)), 0, result);
|
||||
LegacyNumericUtils.intToPrefixCoded(NumericUtils.floatToSortableInt(parseFloatFromUser(null, s)), 0, result);
|
||||
break;
|
||||
case LONG:
|
||||
LegacyNumericUtils.longToPrefixCoded(Long.parseLong(s), 0, result);
|
||||
LegacyNumericUtils.longToPrefixCoded(parseLongFromUser(null, s), 0, result);
|
||||
break;
|
||||
case DOUBLE:
|
||||
LegacyNumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(Double.parseDouble(s)), 0, result);
|
||||
LegacyNumericUtils.longToPrefixCoded(NumericUtils.doubleToSortableLong(parseDoubleFromUser(null, s)), 0, result);
|
||||
break;
|
||||
case DATE:
|
||||
LegacyNumericUtils.longToPrefixCoded(DateMathParser.parseMath(null, s).getTime(), 0, result);
|
||||
|
@ -433,10 +431,6 @@ public class TrieField extends NumericFieldType {
|
|||
default:
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + type);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||
"Invalid Number: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -191,7 +191,7 @@ public class AddUpdateCommand extends UpdateCommand implements Iterable<Document
|
|||
boolean isVersion = version != 0;
|
||||
|
||||
for (SolrInputDocument sdoc : all) {
|
||||
sdoc.setField("_root_", idField); // should this be a string or the same type as the ID?
|
||||
sdoc.setField(IndexSchema.ROOT_FIELD_NAME, idField);
|
||||
if(isVersion) sdoc.setField(CommonParams.VERSION_FIELD, version);
|
||||
// TODO: if possible concurrent modification exception (if SolrInputDocument not cloned and is being forwarded to replicas)
|
||||
// then we could add this field to the generated lucene document instead.
|
||||
|
@ -220,6 +220,12 @@ public class AddUpdateCommand extends UpdateCommand implements Iterable<Document
|
|||
private List<SolrInputDocument> flatten(SolrInputDocument root) {
|
||||
List<SolrInputDocument> unwrappedDocs = new ArrayList<>();
|
||||
recUnwrapp(unwrappedDocs, root);
|
||||
if (1 < unwrappedDocs.size() && ! req.getSchema().isUsableForChildDocs()) {
|
||||
throw new SolrException
|
||||
(SolrException.ErrorCode.BAD_REQUEST, "Unable to index docs with children: the schema must " +
|
||||
"include definitions for both a uniqueKey field and the '" + IndexSchema.ROOT_FIELD_NAME +
|
||||
"' field, using the exact same fieldType");
|
||||
}
|
||||
return unwrappedDocs;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.apache.solr.request.LocalSolrQueryRequest;
|
|||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.request.SolrRequestInfo;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.schema.IndexSchema;
|
||||
import org.apache.solr.schema.SchemaField;
|
||||
import org.apache.solr.search.FunctionRangeQuery;
|
||||
import org.apache.solr.search.QParser;
|
||||
|
@ -394,7 +395,7 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
|
|||
}
|
||||
|
||||
private Term getIdTerm(AddUpdateCommand cmd) {
|
||||
return new Term(cmd.isBlock() ? "_root_" : idField.getName(), cmd.getIndexedId());
|
||||
return new Term(cmd.isBlock() ? IndexSchema.ROOT_FIELD_NAME : idField.getName(), cmd.getIndexedId());
|
||||
}
|
||||
|
||||
private void updateDeleteTrackers(DeleteUpdateCommand cmd) {
|
||||
|
|
|
@ -176,7 +176,7 @@ public class DocumentBuilder {
|
|||
// check if the copy field is a multivalued or not
|
||||
if (!destinationField.multiValued() && destHasValues) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||
"ERROR: "+getID(doc, schema)+"multiple values encountered for non multiValued copy field " +
|
||||
"Multiple values encountered for non multiValued copy field " +
|
||||
destinationField.getName() + ": " + v);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,9 @@ public class DocumentBuilder {
|
|||
}
|
||||
}
|
||||
catch( SolrException ex ) {
|
||||
throw ex;
|
||||
throw new SolrException(SolrException.ErrorCode.getErrorCode(ex.code()),
|
||||
"ERROR: "+getID(doc, schema)+"Error adding field '" +
|
||||
field.getName() + "'='" +field.getValue()+"' msg=" + ex.getMessage(), ex );
|
||||
}
|
||||
catch( Exception ex ) {
|
||||
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<schema name="bad-schema-uniquekey-diff-type-dynamic-root" version="1.4">
|
||||
<!-- NOTE: these fieldTypes are defined with same class, and same props, but schema should
|
||||
still error because the type *names* used not identical.
|
||||
this is risky, because it means the types could diverge over time, and we wnat to
|
||||
protect the user fromthat.
|
||||
-->
|
||||
<fieldType name="string1" class="solr.StrField"/>
|
||||
<fieldType name="string2" class="solr.StrField"/>
|
||||
|
||||
<uniqueKey>id</uniqueKey>
|
||||
<field name="id" type="string1" indexed="true" stored="true" />
|
||||
|
||||
<!-- BEGIN BAD STUFF -->
|
||||
<!-- matches '_root_' -->
|
||||
<dynamicField name="*" type="string2" indexed="true" stored="true" />
|
||||
<!-- END BAD STUFF -->
|
||||
|
||||
</schema>
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<schema name="bad-schema-uniquekey-diff-type-root" version="1.4">
|
||||
<!-- NOTE: these fieldTypes are defined with same class, and same props, but schema should
|
||||
still error because the type *names* used not identical.
|
||||
this is risky, because it means the types could diverge over time, and we wnat to
|
||||
protect the user fromthat.
|
||||
-->
|
||||
<fieldType name="string1" class="solr.StrField"/>
|
||||
<fieldType name="string2" class="solr.StrField"/>
|
||||
|
||||
<uniqueKey>id</uniqueKey>
|
||||
<field name="id" type="string1" indexed="true" stored="true" />
|
||||
|
||||
<!-- BEGIN BAD STUFF -->
|
||||
<field name="_root_" type="string2" indexed="true" stored="true" />
|
||||
<!-- END BAD STUFF -->
|
||||
|
||||
</schema>
|
|
@ -734,12 +734,26 @@
|
|||
useDocValuesAsStored="true"/>
|
||||
<dynamicField name="*_s_dvo" multiValued="false" type="string" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
<dynamicField name="*_l_dvo" multiValued="false" type="${solr.tests.longClass:plong}" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
<dynamicField name="*_f_dvo" multiValued="false" type="${solr.tests.floatClass:pfloat}" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
<dynamicField name="*_dt_dvo" multiValued="false" type="${solr.tests.dateClass:pdate}" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
|
||||
<dynamicField name="*_ii_dvo" multiValued="true" type="${solr.tests.intClass:pint}" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
<dynamicField name="*_dd_dvo" multiValued="true" type="${solr.tests.doubleClass:pdouble}" docValues="true" indexed="false" stored="false"
|
||||
useDocValuesAsStored="true"/>
|
||||
|
||||
|
||||
<!-- Only Stored numerics -->
|
||||
<dynamicField name="*_i_os" type="${solr.tests.intClass:pint}" indexed="false" stored="true" docValues="false"/>
|
||||
<dynamicField name="*_l_os" type="${solr.tests.longClass:plong}" indexed="false" stored="true" docValues="false"/>
|
||||
<dynamicField name="*_f_os" type="${solr.tests.floatClass:pfloat}" indexed="false" stored="true" docValues="false"/>
|
||||
<dynamicField name="*_d_os" type="${solr.tests.doubleClass:pdouble}" indexed="false" stored="true" docValues="false"/>
|
||||
<dynamicField name="*_dt_os" type="${solr.tests.dateClass:pdate}" indexed="false" stored="true" docValues="false"/>
|
||||
|
||||
<!-- Non-stored, DocValues=true, useDocValuesAsStored=false -->
|
||||
<field name="single_i_dvn" multiValued="false" type="${solr.tests.intClass:pint}" indexed="true" stored="true"/>
|
||||
<field name="single_d_dvn" multiValued="false" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true"/>
|
||||
|
|
|
@ -413,6 +413,10 @@ valued. -->
|
|||
<dynamicField name="*_ds_p" type="pdouble" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_d_ni_p" type="pdouble" indexed="false" stored="true" docValues="true"/>
|
||||
<dynamicField name="*_ds_ni_p" type="pdouble" indexed="false" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_dt_p" type="pdate" indexed="true" stored="true" docValues="true"/>
|
||||
<dynamicField name="*_dts_p" type="pdate" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_dt_ni_p" type="pdate" indexed="false" stored="true" docValues="true"/>
|
||||
<dynamicField name="*_dts_ni_p" type="pdate" indexed="false" stored="true" docValues="true" multiValued="true"/>
|
||||
|
||||
<dynamicField name="*_t" type="text" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
|
||||
|
|
|
@ -604,16 +604,33 @@
|
|||
<dynamicField name="*_is" type="${solr.tests.intClass:pint}" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_i_dv" type="${solr.tests.intClass:pint}" indexed="true" stored="true" docValues="true" multiValued="false"/>
|
||||
<dynamicField name="*_is_dv" type="${solr.tests.intClass:pint}" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_i_dvo" type="${solr.tests.intClass:pint}" indexed="false" stored="true" docValues="true"/>
|
||||
|
||||
<dynamicField name="*_f" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_fs" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_f_dv" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true" docValues="true" multiValued="false"/>
|
||||
<dynamicField name="*_fs_dv" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_f_dvo" type="${solr.tests.floatClass:pfloat}" indexed="false" stored="true" docValues="true"/>
|
||||
|
||||
<dynamicField name="*_l" type="${solr.tests.longClass:plong}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_ls" type="${solr.tests.longClass:plong}" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_l_dv" type="${solr.tests.longClass:plong}" indexed="true" stored="true" docValues="true" multiValued="false"/>
|
||||
<dynamicField name="*_ls_dv" type="${solr.tests.longClass:plong}" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_l_dvo" type="${solr.tests.longClass:plong}" indexed="false" stored="true" docValues="true"/>
|
||||
|
||||
<dynamicField name="*_d" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_ds" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_d_dv" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true" docValues="true" multiValued="false"/>
|
||||
<dynamicField name="*_ds_dv" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true" docValues="true" multiValued="true"/>
|
||||
<dynamicField name="*_d_dvo" type="${solr.tests.doubleClass:pdouble}" indexed="false" stored="true" docValues="true"/>
|
||||
|
||||
<dynamicField name="*_s1" type="string" indexed="true" stored="true" multiValued="false"/>
|
||||
<!-- :TODO: why are these identical?!?!?! -->
|
||||
<dynamicField name="*_s" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_ss" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||
<dynamicField name="*_l" type="${solr.tests.longClass:plong}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_t" type="text" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_tt" type="text" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_f" type="${solr.tests.floatClass:pfloat}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_d" type="${solr.tests.doubleClass:pdouble}" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_dt" type="${solr.tests.dateClass:pdate}" indexed="true" stored="true"/>
|
||||
|
||||
<dynamicField name="*_pi" type="pint" indexed="true" stored="true" docValues="false" multiValued="false"/>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dynamicField name="*" type="string" indexed="true" stored="true"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dynamicField name="*" type="string" indexed="true" stored="true"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dynamicField name="*" type="string" indexed="true" stored="true"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dynamicField name="*" type="string" indexed="true" stored="true"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<dynamicField name="*" type="string" indexed="true" stored="true"/>
|
||||
<!-- for versioning -->
|
||||
<field name="_version_" type="long" indexed="true" stored="true"/>
|
||||
<field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="id" type="string" indexed="true" stored="true"/>
|
||||
<uniqueKey>id</uniqueKey>
|
||||
</schema>
|
||||
|
|
|
@ -341,6 +341,59 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientErrorOnMalformedDate() throws Exception {
|
||||
final String BAD_VALUE = "NOT_A_DATE";
|
||||
ignoreException(BAD_VALUE);
|
||||
|
||||
final List<String> FIELDS = new LinkedList<>();
|
||||
for (String type : new String[] {
|
||||
"tdt", "tdt1", "tdtdv", "tdtdv1",
|
||||
"dt_dv", "dt_dvo", "dt", "dt1", "dt_os"
|
||||
}) {
|
||||
FIELDS.add("malformed_" + type);
|
||||
}
|
||||
|
||||
// test that malformed numerics cause client error not server error
|
||||
for (String field : FIELDS) {
|
||||
try {
|
||||
h.update(add( doc("id","100", field, BAD_VALUE)));
|
||||
fail("Didn't encounter an error trying to add a bad date: " + field);
|
||||
} catch (SolrException e) {
|
||||
String msg = e.toString();
|
||||
assertTrue("not an (update) client error on field: " + field +" : "+ msg,
|
||||
400 <= e.code() && e.code() < 500);
|
||||
assertTrue("(update) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
assertTrue("client error does not mention document id: " + msg,
|
||||
msg.contains("[doc=100]"));
|
||||
}
|
||||
SchemaField sf = h.getCore().getLatestSchema().getField(field);
|
||||
if (!sf.hasDocValues() && !sf.indexed()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
h.query(req("q",field + ":" + BAD_VALUE));
|
||||
fail("Didn't encounter an error trying to query a bad date: " + field);
|
||||
} catch (SolrException e) {
|
||||
String msg = e.toString();
|
||||
assertTrue("not a (search) client error on field: " + field +" : "+ msg,
|
||||
400 <= e.code() && e.code() < 500);
|
||||
assertTrue("(search) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
}
|
||||
try {
|
||||
h.query(req("q",field + ":[NOW TO " + BAD_VALUE + "]"));
|
||||
fail("Didn't encounter an error trying to query a bad date: " + field);
|
||||
} catch (SolrException e) {
|
||||
String msg = e.toString();
|
||||
assertTrue("not a (search) client error on field: " + field +" : "+ msg,
|
||||
400 <= e.code() && e.code() < 500);
|
||||
assertTrue("(search) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientErrorOnMalformedNumbers() throws Exception {
|
||||
|
@ -349,7 +402,13 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 {
|
|||
ignoreException(BAD_VALUE);
|
||||
|
||||
final List<String> FIELDS = new LinkedList<>();
|
||||
for (String type : new String[] { "ti", "tf", "td", "tl" }) {
|
||||
for (String type : new String[] {
|
||||
"ti", "tf", "td", "tl",
|
||||
"i", "f", "d", "l",
|
||||
"i_dv", "f_dv", "d_dv", "l_dv",
|
||||
"i_dvo", "f_dvo", "d_dvo", "l_dvo",
|
||||
"i_os", "f_os", "d_os", "l_os"
|
||||
}) {
|
||||
FIELDS.add("malformed_" + type);
|
||||
}
|
||||
|
||||
|
@ -364,6 +423,12 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 {
|
|||
400 <= e.code() && e.code() < 500);
|
||||
assertTrue("(update) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
assertTrue("client error does not mention document id",
|
||||
msg.contains("[doc=100]"));
|
||||
}
|
||||
SchemaField sf = h.getCore().getLatestSchema().getField(field);
|
||||
if (!sf.hasDocValues() && !sf.indexed()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
h.query(req("q",field + ":" + BAD_VALUE));
|
||||
|
@ -375,6 +440,16 @@ public class BasicFunctionalityTest extends SolrTestCaseJ4 {
|
|||
assertTrue("(search) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
}
|
||||
try {
|
||||
h.query(req("q",field + ":[10 TO " + BAD_VALUE + "]"));
|
||||
fail("Didn't encounter an error trying to query a non-number: " + field);
|
||||
} catch (SolrException e) {
|
||||
String msg = e.toString();
|
||||
assertTrue("not a (search) client error on field: " + field +" : "+ msg,
|
||||
400 <= e.code() && e.code() < 500);
|
||||
assertTrue("(search) client error does not mention bad value: " + msg,
|
||||
msg.contains(BAD_VALUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,21 @@ public class BadIndexSchemaTest extends AbstractBadConfigTestBase {
|
|||
doTest("bad-schema-unsupported-docValues.xml", "does not support doc values");
|
||||
}
|
||||
|
||||
public void testRootTypeMissmatchWithUniqueKey() throws Exception {
|
||||
doTest("bad-schema-uniquekey-diff-type-root.xml",
|
||||
"using the exact same fieldType as the uniqueKey field (id) uses: string1");
|
||||
}
|
||||
|
||||
public void testRootTypeDynamicMissmatchWithUniqueKey() throws Exception {
|
||||
// in this case, the core should load fine -- but we should get an error adding docs
|
||||
try {
|
||||
initCore("solrconfig.xml","bad-schema-uniquekey-diff-type-dynamic-root.xml");
|
||||
assertFailedU("Unable to index docs with children", adoc(sdocWithChildren("1","-1")));
|
||||
} finally {
|
||||
deleteCore();
|
||||
}
|
||||
}
|
||||
|
||||
public void testSweetSpotSimBadConfig() throws Exception {
|
||||
doTest("bad-schema-sweetspot-both-tf.xml", "Can not mix");
|
||||
doTest("bad-schema-sweetspot-partial-baseline.xml",
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.solr.common.SolrException;
|
|||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.apache.solr.util.AbstractSolrTestCase;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestQueryTypes extends AbstractSolrTestCase {
|
||||
|
||||
|
@ -209,7 +210,6 @@ public class TestQueryTypes extends AbstractSolrTestCase {
|
|||
,"//result[@numFound='2']"
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// test escapes in quoted strings
|
||||
//
|
||||
|
@ -436,5 +436,49 @@ public class TestQueryTypes extends AbstractSolrTestCase {
|
|||
assertQ("Test text field with no analysis doesn't NPE with wildcards (SOLR-4318)",
|
||||
req("q", "text_no_analyzer:should*"), "//result[@numFound='1']");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericBadRequests() {
|
||||
String[] suffixes = new String[50];
|
||||
int fieldNum = 0;
|
||||
for (String type:new String[]{"i", "l", "f", "d", "dt"}) {
|
||||
for (String s:new String[]{"", "s"}) {
|
||||
//Trie
|
||||
suffixes[fieldNum++] = "t" + type + s;
|
||||
suffixes[fieldNum++] = "t" + type + s + "_dv";
|
||||
suffixes[fieldNum++] = "t" + type + s + "_ni_dv";
|
||||
|
||||
//Points
|
||||
suffixes[fieldNum++] = type + s + "_p";
|
||||
suffixes[fieldNum++] = type + s + "_ni_p";
|
||||
}
|
||||
}
|
||||
assertEquals(fieldNum,suffixes.length);
|
||||
|
||||
String badNumber = "NOT_A_NUMBER";
|
||||
for (String suffix:suffixes) {
|
||||
// Numeric bad requests
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber, req("q","{!term f=foo_" + suffix + "}" + badNumber), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber, req("q","{!terms f=foo_" + suffix + "}1 2 3 4 5 " + badNumber), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber, req("q","{!lucene}foo_" + suffix + ":" + badNumber), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber, req("q","{!field f=foo_" + suffix + "}" + badNumber), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber, req("q","{!maxscore}foo_" + suffix + ":" + badNumber), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, badNumber,
|
||||
req("q","{!xmlparser}<PointRangeQuery fieldName=\"foo_"+ suffix + "\" lowerTerm=\"1\" upperTerm=\"" + badNumber + "\"/>"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
if (suffix.contains("_p")) {
|
||||
// prefix queries work in Trie fields
|
||||
assertQEx("Expecting exception for suffix: " + suffix, "Can't run prefix queries on numeric fields",
|
||||
req("q","{!prefix f=foo_" + suffix + "}NOT_A_NUMBER"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
assertQEx("Expecting exception for suffix: " + suffix, "Can't run prefix queries on numeric fields",
|
||||
req("q","{!lucene}foo_" + suffix + ":123*"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Skipping: func, boost, raw, nested, frange, spatial*, join, surround, switch, parent, child, collapsing,
|
||||
// complexphrase, rerank, export, mlt, hash, graph, graphTerms, igain, tlogit, sigificantTerms, payload*
|
||||
// Maybe add: raw, join, parent, child, collapsing, graphTerms, igain, sigificantTerms, simple
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.lucene.search.Query;
|
|||
import org.apache.lucene.search.TermInSetQuery;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.params.MapSolrParams;
|
||||
import org.apache.solr.metrics.MetricsMap;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
|
@ -1038,4 +1039,39 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
|
|||
, "/response/numFound==1"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadRequestInSetQuery() throws SyntaxError {
|
||||
SolrQueryRequest req = req();
|
||||
QParser qParser;
|
||||
String[] fieldSuffix = new String[] {
|
||||
"ti", "tf", "td", "tl",
|
||||
"i", "f", "d", "l",
|
||||
"is", "fs", "ds", "ls",
|
||||
"i_dv", "f_dv", "d_dv", "l_dv",
|
||||
"is_dv", "fs_dv", "ds_dv", "ls_dv",
|
||||
"i_dvo", "f_dvo", "d_dvo", "l_dvo",
|
||||
};
|
||||
|
||||
for (String suffix:fieldSuffix) {
|
||||
//Good queries
|
||||
qParser = QParser.getParser("foo_" + suffix + ":(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 25)", req);
|
||||
qParser.setIsFilter(true);
|
||||
qParser.getQuery();
|
||||
}
|
||||
|
||||
for (String suffix:fieldSuffix) {
|
||||
qParser = QParser.getParser("foo_" + suffix + ":(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 NOT_A_NUMBER)", req);
|
||||
qParser.setIsFilter(true); // this may change in the future
|
||||
try {
|
||||
qParser.getQuery();
|
||||
fail("Expecting exception");
|
||||
} catch (SolrException e) {
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertTrue("Unexpected exception: " + e.getMessage(), e.getMessage().contains("Invalid Number: NOT_A_NUMBER"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue