use of com.hazelcast.sql.impl.exec.scan.index.IndexFilter in project hazelcast by hazelcast.
the class IndexResolver method prepareSingleColumnCandidateBooleanIsTrueFalse.
/**
* Prepare a candidate for {@code IS (NOT) TRUE/FALSE} expression.
* <p>
* The fundamental observation is that boolean column may have only three values - TRUE/FALSE/NULL. Therefore, every
* such expression could be converted to equivalent equals or IN predicate:
* - IS TRUE -> EQUALS(TRUE)
* - IS FALSE -> EQUALS(FALSE)
* - IS NOT TRUE -> IN(EQUALS(FALSE), EQUALS(NULL))
* - IS NOT FALSE -> IN(EQUALS(TRUE), EQUALS(NULL))
*
* @param exp original expression, e.g. {col IS TRUE}
* @param operand operand, e.g. {col}; CAST must be unwrapped before the method is invoked
* @param kind expression type
* @return candidate or {@code null}
*/
private static IndexComponentCandidate prepareSingleColumnCandidateBooleanIsTrueFalse(RexNode exp, RexNode operand, SqlKind kind) {
if (operand.getKind() != SqlKind.INPUT_REF) {
// The operand is not a column, e.g. {'true' IS TRUE}, index cannot be used
return null;
}
if (operand.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
// The column is not of BOOLEAN type. We should never hit this branch normally. Added here only for safety.
return null;
}
int columnIndex = ((RexInputRef) operand).getIndex();
IndexFilter filter;
switch(kind) {
case IS_TRUE:
filter = new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(true, QueryDataType.BOOLEAN)), singletonList(false)));
break;
case IS_FALSE:
filter = new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(false, QueryDataType.BOOLEAN)), singletonList(false)));
break;
case IS_NOT_TRUE:
filter = new IndexInFilter(new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(false, QueryDataType.BOOLEAN)), singletonList(false))), new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(null, QueryDataType.BOOLEAN)), singletonList(true))));
break;
default:
assert kind == SqlKind.IS_NOT_FALSE;
filter = new IndexInFilter(new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(true, QueryDataType.BOOLEAN)), singletonList(false))), new IndexEqualsFilter(new IndexFilterValue(singletonList(ConstantExpression.create(null, QueryDataType.BOOLEAN)), singletonList(true))));
}
return new IndexComponentCandidate(exp, columnIndex, filter);
}
use of com.hazelcast.sql.impl.exec.scan.index.IndexFilter in project hazelcast by hazelcast.
the class IndexResolver method prepareSingleColumnCandidateComparison.
/**
* Try creating a candidate filter for comparison operator.
*
* @param exp the original expression
* @param kind expression kine (=, >, <, >=, <=)
* @param operand1 the first operand (CAST must be unwrapped before the method is invoked)
* @param operand2 the second operand (CAST must be unwrapped before the method is invoked)
* @param parameterMetadata parameter metadata for expressions like {a>?}
* @return candidate or {@code null}
*/
private static IndexComponentCandidate prepareSingleColumnCandidateComparison(RexNode exp, SqlKind kind, RexNode operand1, RexNode operand2, QueryParameterMetadata parameterMetadata) {
// The condition (kind) is changed accordingly (e.g. ">" to "<").
if (operand1.getKind() != SqlKind.INPUT_REF && operand2.getKind() == SqlKind.INPUT_REF) {
kind = inverseIndexConditionKind(kind);
RexNode tmp = operand1;
operand1 = operand2;
operand2 = tmp;
}
if (operand1.getKind() != SqlKind.INPUT_REF) {
// No columns in the expression, index cannot be used. E.g. {'a' > 'b'}
return null;
}
int columnIndex = ((RexInputRef) operand1).getIndex();
if (!IndexRexVisitor.isValid(operand2)) {
// E.g. {column_a > column_b}.
return null;
}
// Convert the second operand into Hazelcast expression. The expression will be evaluated once before index scan is
// initiated, to construct the proper filter for index lookup.
Expression<?> filterValue = convertToExpression(operand2, parameterMetadata);
if (filterValue == null) {
// tree to Hazelcast plan.
return null;
}
// Create the value that will be passed to filters. Not that "allowNulls=false" here, because any NULL in the comparison
// operator never returns "TRUE" and hence always returns an empty result set.
IndexFilterValue filterValue0 = new IndexFilterValue(singletonList(filterValue), singletonList(false));
IndexFilter filter;
switch(kind) {
case EQUALS:
filter = new IndexEqualsFilter(filterValue0);
break;
case GREATER_THAN:
filter = new IndexRangeFilter(filterValue0, false, null, false);
break;
case GREATER_THAN_OR_EQUAL:
filter = new IndexRangeFilter(filterValue0, true, null, false);
break;
case LESS_THAN:
filter = new IndexRangeFilter(null, false, filterValue0, false);
break;
default:
assert kind == SqlKind.LESS_THAN_OR_EQUAL;
filter = new IndexRangeFilter(null, false, filterValue0, true);
}
return new IndexComponentCandidate(exp, columnIndex, filter);
}
use of com.hazelcast.sql.impl.exec.scan.index.IndexFilter in project hazelcast by hazelcast.
the class IndexResolver method prepareSingleColumnSearchCandidateComparison.
@SuppressWarnings({ "ConstantConditions", "UnstableApiUsage" })
private static IndexComponentCandidate prepareSingleColumnSearchCandidateComparison(RexNode exp, RexNode operand1, RexNode operand2) {
// SARG is supported only for literals, not for dynamic parameters
if (operand1.getKind() != SqlKind.INPUT_REF || operand2.getKind() != SqlKind.LITERAL) {
return null;
}
int columnIndex = ((RexInputRef) operand1).getIndex();
RexLiteral literal = (RexLiteral) operand2;
QueryDataType hazelcastType = HazelcastTypeUtils.toHazelcastType(literal.getType());
RangeSet<?> rangeSet = RexToExpression.extractRangeFromSearch(literal);
if (rangeSet == null) {
return null;
}
Set<? extends Range<?>> ranges = rangeSet.asRanges();
IndexFilter indexFilter;
if (ranges.size() == 1) {
indexFilter = createIndexFilterForSingleRange(Iterables.getFirst(ranges, null), hazelcastType);
} else if (ranges.stream().allMatch(IndexResolver::isSingletonRange)) {
indexFilter = new IndexInFilter(toList(ranges, range -> createIndexFilterForSingleRange(range, hazelcastType)));
} else {
// No support for IndexInFilter with multiple IndexFilterForSingleRanges
return null;
}
return new IndexComponentCandidate(exp, columnIndex, indexFilter);
}
use of com.hazelcast.sql.impl.exec.scan.index.IndexFilter in project hazelcast by hazelcast.
the class IndexResolver method prepareSingleColumnCandidateOr.
/**
* Prepare candidate for OR expression if possible.
* <p>
* We support only equality conditions on the same columns. Ranges and conditions on different columns (aka "index joins")
* are not supported.
*
* @param exp the OR expression
* @param nodes components of the OR expression
* @param parameterMetadata parameter metadata
* @return candidate or {code null}
*/
private static IndexComponentCandidate prepareSingleColumnCandidateOr(RexNode exp, List<RexNode> nodes, QueryParameterMetadata parameterMetadata) {
Integer columnIndex = null;
List<IndexFilter> filters = new ArrayList<>();
for (RexNode node : nodes) {
IndexComponentCandidate candidate = prepareSingleColumnCandidate(node, parameterMetadata);
if (candidate == null) {
// The component of the OR expression cannot be used by any index implementation
return null;
}
IndexFilter candidateFilter = candidate.getFilter();
if (!(candidateFilter instanceof IndexEqualsFilter || candidateFilter instanceof IndexInFilter)) {
// Support only equality for ORs
return null;
}
// Make sure that all '=' expressions relate to a single column
if (columnIndex == null) {
columnIndex = candidate.getColumnIndex();
} else if (columnIndex != candidate.getColumnIndex()) {
return null;
}
// Flatten. E.g. ((a=1 OR a=2) OR a=3) is parsed into IN(1, 2) and OR(3), that is then flatten into IN(1, 2, 3)
if (candidateFilter instanceof IndexEqualsFilter) {
filters.add(candidateFilter);
} else {
filters.addAll(((IndexInFilter) candidateFilter).getFilters());
}
}
assert columnIndex != null;
IndexInFilter inFilter = new IndexInFilter(filters);
return new IndexComponentCandidate(exp, columnIndex, inFilter);
}
use of com.hazelcast.sql.impl.exec.scan.index.IndexFilter in project hazelcast by hazelcast.
the class IndexInFilterTest method testContent.
@Test
public void testContent() {
List<IndexFilter> filters = Collections.singletonList(new IndexEqualsFilter(intValue(1)));
IndexInFilter filter = new IndexInFilter(filters);
assertSame(filters, filter.getFilters());
}
Aggregations