Between between = (Between)constraint;
final StaticOperand lower = between.getLowerBound();
final StaticOperand upper = between.getUpperBound();
final boolean includeLower = between.isLowerBoundIncluded();
final boolean includeUpper = between.isUpperBoundIncluded();
DynamicOperand dynamicOperand = between.getOperand();
final TypeFactory<?> defaultType = determineType(dynamicOperand, context, columns);
final ExtractFromRow operation = createExtractFromRow(dynamicOperand, context, columns, sources, defaultType, true,
false);
// Determine the literal value in the static operand ...
return new RowFilterSupplier() {
@Override
protected RowFilter createFilter() {
// Evaluate the operand, which may have variables ...
final Object lowerLiteralValue = literalValue(lower, context, defaultType);
final Object upperLiteralValue = literalValue(upper, context, defaultType);
// Create the correct operation ...
final TypeFactory<?> expectedType = operation.getType();
final Object lowerValue = expectedType.create(lowerLiteralValue);
final Object upperValue = expectedType.create(upperLiteralValue);
@SuppressWarnings( "unchecked" )
final Comparator<Object> comparator = (Comparator<Object>)expectedType.getComparator();
if (includeLower) {
if (includeUpper) {
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, lowerValue) >= 0
&& comparator.compare(leftHandValue, upperValue) <= 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
// Don't include upper ...
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, lowerValue) >= 0
&& comparator.compare(leftHandValue, upperValue) < 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
assert !includeLower;
// Don't include lower
if (includeUpper) {
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, lowerValue) > 0
&& comparator.compare(leftHandValue, upperValue) <= 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
// Don't include upper or lower ...
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, lowerValue) > 0
&& comparator.compare(leftHandValue, upperValue) < 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
};
}
if (constraint instanceof Comparison) {
Comparison comparison = (Comparison)constraint;
// Create the correct dynamic operation ...
final DynamicOperand dynamicOperand = comparison.getOperand1();
final Operator operator = comparison.operator();
final StaticOperand staticOperand = comparison.getOperand2();
final TypeFactory<?> actualType = determineType(dynamicOperand, context, columns);
TypeFactory<?> expectedType = null;
ExtractFromRow op = null;
if (operator == Operator.LIKE) {
expectedType = context.getTypeSystem().getStringFactory();
op = createExtractFromRow(dynamicOperand, context, columns, sources, expectedType, true, true);
if (op.getType() != expectedType) {
// Need to convert the extracted value(s) to strings because this is a LIKE operation ...
op = RowExtractors.convert(op, expectedType);
}
} else {
expectedType = actualType;
op = createExtractFromRow(dynamicOperand, context, columns, sources, expectedType, true, false);
}
final TypeFactory<?> defaultType = expectedType;
final ExtractFromRow operation = op;
// Determine the literal value in the static operand ...
return new RowFilterSupplier() {
@Override
protected RowFilter createFilter() {
// Evaluate the operand, which may have variables ...
final Object literalValue = literalValue(staticOperand, context, defaultType);
// Create the correct operation ...
final TypeFactory<?> expectedType = operation.getType();
final Object rhs = expectedType.create(literalValue);
@SuppressWarnings( "unchecked" )
final Comparator<Object> comparator = (Comparator<Object>)expectedType.getComparator();
switch (operator) {
case EQUAL_TO:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) == 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case NOT_EQUAL_TO:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) != 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case GREATER_THAN:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) > 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case GREATER_THAN_OR_EQUAL_TO:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) >= 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case LESS_THAN:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) < 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case LESS_THAN_OR_EQUAL_TO:
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
return comparator.compare(leftHandValue, rhs) <= 0;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
case LIKE:
// Convert the LIKE expression to a regular expression
final TypeSystem types = context.getTypeSystem();
String expression = types.asString(rhs).trim();
if ("%".equals(expression)) {
// We'll accept any non-null value ...
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
return leftHandValue != null;
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
if (Path.class.isAssignableFrom(actualType.getType())) {
// This LIKE is dealing with paths and SNS wildcards, so we have to extract path values that
// have SNS indexes in all segments ...
final PathFactory paths = context.getExecutionContext().getValueFactories().getPathFactory();
expression = QueryUtil.addSnsIndexesToLikeExpression(expression);
String regex = QueryUtil.toRegularExpression(expression);
final Pattern pattern = Pattern.compile(regex);
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
// Get the value as a path and construct a string representation with SNS indexes
// in the correct spot ...
Path path = paths.create(leftHandValue);
String strValue = null;
if (path.isRoot()) {
strValue = "/";
} else {
StringBuilder sb = new StringBuilder();
for (Path.Segment segment : path) {
sb.append('/').append(types.asString(segment.getName()));
sb.append('[').append(segment.getIndex()).append(']');
}
strValue = sb.toString();
}
return pattern.matcher(strValue).matches();
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
String regex = QueryUtil.toRegularExpression(expression);
final Pattern pattern = Pattern.compile(regex);
return new DynamicOperandFilter(operation) {
@Override
protected boolean evaluate( Object leftHandValue ) {
if (leftHandValue == null) return false; // null values never match
String value = types.asString(leftHandValue);
return pattern.matcher(value).matches();
}
@Override
public String toString() {
return "(filter " + Visitors.readable(constraint) + ")";
}
};
}
assert false : "Should not get here";
return null;
}
};
}
if (constraint instanceof SetCriteria) {
final SetCriteria setCriteria = (SetCriteria)constraint;
DynamicOperand operand = setCriteria.getOperand();
final TypeFactory<?> defaultType = determineType(operand, context, columns);
// If the set criteria contains a bind variable, then the operand filter should lazily evaluate the bind variable ...
final ExtractFromRow operation = createExtractFromRow(operand, context, columns, sources, defaultType, true, false);
final boolean trace = LOGGER.isTraceEnabled() && !defaultType.getTypeName().equals("NAME");
return new RowFilterSupplier() {