Search in sources :

Example 1 with IndexInFilter

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);
}
Also used : IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) IndexFilterValue(com.hazelcast.sql.impl.exec.scan.index.IndexFilterValue) RexInputRef(org.apache.calcite.rex.RexInputRef) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter)

Example 2 with IndexInFilter

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);
}
Also used : RangeSet(com.google.common.collect.RangeSet) QueryDataTypeFamily(com.hazelcast.sql.impl.type.QueryDataTypeFamily) OptUtils.getCluster(com.hazelcast.jet.sql.impl.opt.OptUtils.getCluster) QueryParameterMetadata(com.hazelcast.sql.impl.QueryParameterMetadata) Collections.singletonList(java.util.Collections.singletonList) HazelcastTable(com.hazelcast.jet.sql.impl.schema.HazelcastTable) TypeConverters(com.hazelcast.query.impl.TypeConverters) RexUtil(org.apache.calcite.rex.RexUtil) RexNode(org.apache.calcite.rex.RexNode) Map(java.util.Map) IndexRangeFilter(com.hazelcast.sql.impl.exec.scan.index.IndexRangeFilter) QueryDataTypeUtils(com.hazelcast.sql.impl.type.QueryDataTypeUtils) HASH(com.hazelcast.config.IndexType.HASH) IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) RexToExpressionVisitor(com.hazelcast.jet.sql.impl.opt.physical.visitor.RexToExpressionVisitor) PlanNodeFieldTypeProvider(com.hazelcast.sql.impl.plan.node.PlanNodeFieldTypeProvider) RelTraitSet(org.apache.calcite.plan.RelTraitSet) SqlKind(org.apache.calcite.sql.SqlKind) HazelcastTypeUtils(com.hazelcast.jet.sql.impl.validate.types.HazelcastTypeUtils) RexLiteral(org.apache.calcite.rex.RexLiteral) Collection(java.util.Collection) Range(com.google.common.collect.Range) Set(java.util.Set) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) Collectors(java.util.stream.Collectors) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) RexInputRef(org.apache.calcite.rex.RexInputRef) List(java.util.List) FullScanLogicalRel(com.hazelcast.jet.sql.impl.opt.logical.FullScanLogicalRel) BoundType(com.google.common.collect.BoundType) RelCollation(org.apache.calcite.rel.RelCollation) MapTableIndex(com.hazelcast.sql.impl.schema.map.MapTableIndex) TRUE(java.lang.Boolean.TRUE) RexCall(org.apache.calcite.rex.RexCall) OptUtils.createRelTable(com.hazelcast.jet.sql.impl.opt.OptUtils.createRelTable) Iterables(com.google.common.collect.Iterables) IndexFilterValue(com.hazelcast.sql.impl.exec.scan.index.IndexFilterValue) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter) QueryDataType(com.hazelcast.sql.impl.type.QueryDataType) HashMap(java.util.HashMap) POSITIVE_INFINITY(com.hazelcast.query.impl.CompositeValue.POSITIVE_INFINITY) RelOptUtil(org.apache.calcite.plan.RelOptUtil) RelOptTable(org.apache.calcite.plan.RelOptTable) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) IndexType(com.hazelcast.config.IndexType) BiTuple(com.hazelcast.internal.util.BiTuple) Expression(com.hazelcast.sql.impl.expression.Expression) Nonnull(javax.annotation.Nonnull) ComparableIdentifiedDataSerializable(com.hazelcast.query.impl.ComparableIdentifiedDataSerializable) RelCollations(org.apache.calcite.rel.RelCollations) RexToExpression(com.hazelcast.jet.sql.impl.opt.physical.visitor.RexToExpression) RelDataType(org.apache.calcite.rel.type.RelDataType) FALSE(java.lang.Boolean.FALSE) HazelcastRelOptTable(com.hazelcast.jet.sql.impl.schema.HazelcastRelOptTable) RelCollationTraitDef(org.apache.calcite.rel.RelCollationTraitDef) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) SORTED(com.hazelcast.config.IndexType.SORTED) Util.toList(com.hazelcast.jet.impl.util.Util.toList) RexBuilder(org.apache.calcite.rex.RexBuilder) OptUtils(com.hazelcast.jet.sql.impl.opt.OptUtils) IndexScanMapPhysicalRel(com.hazelcast.jet.sql.impl.opt.physical.IndexScanMapPhysicalRel) RelNode(org.apache.calcite.rel.RelNode) Direction(org.apache.calcite.rel.RelFieldCollation.Direction) ASCENDING(org.apache.calcite.rel.RelFieldCollation.Direction.ASCENDING) TreeMap(java.util.TreeMap) NEGATIVE_INFINITY(com.hazelcast.query.impl.CompositeValue.NEGATIVE_INFINITY) ConstantExpression(com.hazelcast.sql.impl.expression.ConstantExpression) DESCENDING(org.apache.calcite.rel.RelFieldCollation.Direction.DESCENDING) Collections(java.util.Collections) RexLiteral(org.apache.calcite.rex.RexLiteral) QueryDataType(com.hazelcast.sql.impl.type.QueryDataType) RexInputRef(org.apache.calcite.rex.RexInputRef) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter)

Example 3 with IndexInFilter

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);
}
Also used : IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) ArrayList(java.util.ArrayList) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter) RexNode(org.apache.calcite.rex.RexNode)

Example 4 with IndexInFilter

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());
}
Also used : IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter) ParallelJVMTest(com.hazelcast.test.annotation.ParallelJVMTest) QuickTest(com.hazelcast.test.annotation.QuickTest) Test(org.junit.Test)

Example 5 with IndexInFilter

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);
        }
    }
}
Also used : IndexRangeFilter(com.hazelcast.sql.impl.exec.scan.index.IndexRangeFilter) IndexEqualsFilter(com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter) IndexInFilter(com.hazelcast.sql.impl.exec.scan.index.IndexInFilter) IndexFilter(com.hazelcast.sql.impl.exec.scan.index.IndexFilter)

Aggregations

IndexEqualsFilter (com.hazelcast.sql.impl.exec.scan.index.IndexEqualsFilter)10 IndexInFilter (com.hazelcast.sql.impl.exec.scan.index.IndexInFilter)10 IndexFilter (com.hazelcast.sql.impl.exec.scan.index.IndexFilter)6 IndexFilterValue (com.hazelcast.sql.impl.exec.scan.index.IndexFilterValue)4 IndexRangeFilter (com.hazelcast.sql.impl.exec.scan.index.IndexRangeFilter)4 ArrayList (java.util.ArrayList)4 RexNode (org.apache.calcite.rex.RexNode)3 QueryDataType (com.hazelcast.sql.impl.type.QueryDataType)2 ParallelJVMTest (com.hazelcast.test.annotation.ParallelJVMTest)2 QuickTest (com.hazelcast.test.annotation.QuickTest)2 RexInputRef (org.apache.calcite.rex.RexInputRef)2 Test (org.junit.Test)2 BoundType (com.google.common.collect.BoundType)1 Iterables (com.google.common.collect.Iterables)1 Range (com.google.common.collect.Range)1 RangeSet (com.google.common.collect.RangeSet)1 IndexType (com.hazelcast.config.IndexType)1 HASH (com.hazelcast.config.IndexType.HASH)1 SORTED (com.hazelcast.config.IndexType.SORTED)1 ArrayDataSerializableFactory (com.hazelcast.internal.serialization.impl.ArrayDataSerializableFactory)1