use of com.hazelcast.sql.impl.exec.scan.index.IndexInFilter 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.IndexInFilter 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.IndexInFilter 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.IndexInFilter 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());
}
use of com.hazelcast.sql.impl.exec.scan.index.IndexInFilter in project hazelcast by hazelcast.
the class IndexIterationPointer method createFromIndexFilterInt.
private static void createFromIndexFilterInt(IndexFilter indexFilter, boolean descending, ExpressionEvalContext evalContext, List<IndexIterationPointer> result) {
if (indexFilter == null) {
result.add(create(null, true, null, true, descending, null));
}
if (indexFilter instanceof IndexRangeFilter) {
IndexRangeFilter rangeFilter = (IndexRangeFilter) indexFilter;
Comparable<?> from = null;
if (rangeFilter.getFrom() != null) {
Comparable<?> fromValue = rangeFilter.getFrom().getValue(evalContext);
// produces UNKNOWN result.
if (fromValue == null) {
return;
}
from = fromValue;
}
Comparable<?> to = null;
if (rangeFilter.getTo() != null) {
Comparable<?> toValue = rangeFilter.getTo().getValue(evalContext);
// Same comment above for expressions like a < NULL.
if (toValue == null) {
return;
}
to = toValue;
}
result.add(create(from, rangeFilter.isFromInclusive(), to, rangeFilter.isToInclusive(), descending, null));
} else if (indexFilter instanceof IndexEqualsFilter) {
IndexEqualsFilter equalsFilter = (IndexEqualsFilter) indexFilter;
Comparable<?> value = equalsFilter.getComparable(evalContext);
result.add(create(value, true, value, true, descending, null));
} else if (indexFilter instanceof IndexInFilter) {
IndexInFilter inFilter = (IndexInFilter) indexFilter;
for (IndexFilter filter : inFilter.getFilters()) {
createFromIndexFilterInt(filter, descending, evalContext, result);
}
}
}
Aggregations