Search in sources :

Example 11 with RecordQueryIndexPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan in project fdb-record-layer by FoundationDB.

the class RecordTypeKeyTest method testIndexScanOnSecondColumn.

@Test
@Disabled
public void testIndexScanOnSecondColumn() throws Exception {
    final Index index = new Index("recno-type", concat(field("num_value_2"), recordType()));
    RecordMetaDataHook hook = metaData -> {
        BASIC_HOOK.apply(metaData);
        metaData.addUniversalIndex(index);
    };
    List<FDBStoredRecord<Message>> recs = saveSomeRecords(hook);
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, hook);
        RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_2").equalsValue(2)).build();
        // RecordQueryPlan plan = planner.plan(query);
        ScanComparisons comparison = new ScanComparisons(Arrays.asList(new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 2), new RecordTypeKeyComparison("MySimpleRecord").getComparison()), Collections.emptySet());
        IndexScanParameters scan = IndexScanComparisons.byValue(comparison);
        RecordQueryPlan plan = new RecordQueryIndexPlan(index.getName(), scan, false);
        assertEquals(recs.subList(1, 2), recordStore.executeQuery(query).map(FDBQueriedRecord::getStoredRecord).asList().join());
        assertThat(plan, indexScan(allOf(indexName(index.getName()), bounds(hasTupleString("[EQUALS 2, IS MySimpleRecord]")))));
    }
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) Arrays(java.util.Arrays) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Disabled(org.junit.jupiter.api.Disabled) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) Expressions.concatenateFields(com.apple.foundationdb.record.metadata.Key.Expressions.concatenateFields) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Tag(org.junit.jupiter.api.Tag) MethodSource(org.junit.jupiter.params.provider.MethodSource) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Matchers.allOf(org.hamcrest.Matchers.allOf) Arguments(org.junit.jupiter.params.provider.Arguments) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) List(java.util.List) Stream(java.util.stream.Stream) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) RecordTypeKeyComparison(com.apple.foundationdb.record.query.expressions.RecordTypeKeyComparison) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Matchers.anyOf(org.hamcrest.Matchers.anyOf) FDBRecordStoreQueryTestBase(com.apple.foundationdb.record.provider.foundationdb.query.FDBRecordStoreQueryTestBase) IntStream(java.util.stream.IntStream) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) ScanProperties(com.apple.foundationdb.record.ScanProperties) Expressions.empty(com.apple.foundationdb.record.metadata.Key.Expressions.empty) PlanMatchers.scan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.scan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) Tags(com.apple.test.Tags) Matchers(org.hamcrest.Matchers) ScanComparisons(com.apple.foundationdb.record.query.plan.ScanComparisons) Expressions.recordType(com.apple.foundationdb.record.metadata.Key.Expressions.recordType) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Index(com.apple.foundationdb.record.metadata.Index) Assumptions(org.junit.jupiter.api.Assumptions) PlanMatchers.unbounded(com.apple.foundationdb.record.query.plan.match.PlanMatchers.unbounded) TestHelpers.assertThrows(com.apple.foundationdb.record.TestHelpers.assertThrows) Message(com.google.protobuf.Message) Collections(java.util.Collections) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) Index(com.apple.foundationdb.record.metadata.Index) RecordTypeKeyComparison(com.apple.foundationdb.record.query.expressions.RecordTypeKeyComparison) ScanComparisons(com.apple.foundationdb.record.query.plan.ScanComparisons) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Disabled(org.junit.jupiter.api.Disabled)

Example 12 with RecordQueryIndexPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan in project fdb-record-layer by FoundationDB.

the class FDBRecordStoreLimitTestBase method plans.

public Stream<Arguments> plans(boolean fail) {
    RecordQueryPlan scanPlan = new RecordQueryScanPlan(ScanComparisons.EMPTY, false);
    IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
    RecordQueryPlan indexPlan = new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, false);
    QueryComponent filter = Query.field("str_value_indexed").equalsValue("odd");
    QueryComponent middleFilter = Query.and(Query.field("rec_no").greaterThan(24L), Query.field("rec_no").lessThan(60L));
    RecordQueryPlan firstChild = indexPlanEquals("MySimpleRecord$str_value_indexed", "even");
    RecordQueryPlan secondChild = indexPlanEquals("MySimpleRecord$num_value_3_indexed", 0);
    return Stream.of(Arguments.of("full record scan", fail, scanPlan), Arguments.of("simple index scan", fail, indexPlan), Arguments.of("reverse index scan", fail, new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, true)), Arguments.of("filter on scan plan", fail, new RecordQueryFilterPlan(scanPlan, filter)), Arguments.of("filter on index plan", fail, new RecordQueryFilterPlan(indexPlan, filter)), Arguments.of("type filter on scan plan", fail, new RecordQueryTypeFilterPlan(scanPlan, Collections.singletonList("MySimpleRecord"))), Arguments.of("type filter on index plan", fail, new RecordQueryTypeFilterPlan(indexPlan, Collections.singletonList("MySimpleRecord"))), Arguments.of("disjoint union", fail, RecordQueryUnionPlan.from(indexPlanEquals("MySimpleRecord$str_value_indexed", "odd"), indexPlanEquals("MySimpleRecord$str_value_indexed", "even"), primaryKey(), false)), Arguments.of("overlapping union", fail, RecordQueryUnionPlan.from(firstChild, secondChild, primaryKey(), false)), Arguments.of("overlapping union (swapped args)", fail, RecordQueryUnionPlan.from(secondChild, firstChild, primaryKey(), false)), Arguments.of("overlapping intersection", fail, RecordQueryIntersectionPlan.from(firstChild, secondChild, primaryKey())), Arguments.of("overlapping intersection", fail, RecordQueryIntersectionPlan.from(secondChild, firstChild, primaryKey())), Arguments.of("union with inner filter", fail, RecordQueryUnionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), secondChild, primaryKey(), false)), Arguments.of("union with two inner filters", fail, RecordQueryUnionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), new RecordQueryFilterPlan(secondChild, Query.field("rec_no").lessThan(55L)), primaryKey(), false)), Arguments.of("intersection with inner filter", fail, RecordQueryIntersectionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), secondChild, primaryKey())), Arguments.of("intersection with two inner filters", fail, RecordQueryIntersectionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), new RecordQueryFilterPlan(secondChild, Query.field("rec_no").lessThan(55L)), primaryKey())));
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryScanPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordQueryTypeFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTypeFilterPlan)

Example 13 with RecordQueryIndexPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan in project fdb-record-layer by FoundationDB.

the class FDBOrQueryToUnionTest method unionVisitorOnComplexComparisonKey.

/**
 * Verify that a union visitor won't defer a record fetch if the comparison key has fields that the index
 * entry doesn't.
 * This sort of plan is never produced by the {@link com.apple.foundationdb.record.query.plan.RecordQueryPlanner},
 * so we have to test the visitor directly.
 */
@Test
void unionVisitorOnComplexComparisonKey() throws Exception {
    complexQuerySetup(null);
    final IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
    RecordQueryPlan originalPlan1 = RecordQueryUnionPlan.from(new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, false), new RecordQueryIndexPlan("MySimpleRecord$num_value_3_indexed", fullValueScan, false), primaryKey("MySimpleRecord"), true);
    RecordQueryPlan modifiedPlan1 = RecordQueryPlannerSubstitutionVisitor.applyVisitors(originalPlan1, recordStore.getRecordMetaData(), PlannableIndexTypes.DEFAULT, primaryKey("MySimpleRecord"));
    final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed"))))));
    assertMatchesExactly(modifiedPlan1, planMatcher);
    RecordQueryPlan originalPlan2 = RecordQueryUnionPlan.from(new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, false), new RecordQueryIndexPlan("MySimpleRecord$num_value_3_indexed", fullValueScan, false), concat(field("num_value_2"), primaryKey("MySimpleRecord")), true);
    RecordQueryPlan modifiedPlan2 = RecordQueryPlannerSubstitutionVisitor.applyVisitors(originalPlan2, recordStore.getRecordMetaData(), PlannableIndexTypes.DEFAULT, primaryKey("MySimpleRecord"));
    // Visitor should not perform transformation because of comparison key on num_value_unique
    assertEquals(originalPlan2, modifiedPlan2);
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 14 with RecordQueryIndexPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan in project fdb-record-layer by FoundationDB.

the class ExpressionMatcherTest method singleTypeMatcher.

@Test
public void singleTypeMatcher() {
    // we already have a different RecordQueryIndexPlan matcher, but this should still work
    BindingMatcher<RecordQueryIndexPlan> matcher = RecordQueryPlanMatchers.indexPlan();
    final IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
    final ExpressionRef<RelationalExpression> root = GroupExpressionRef.of(new RecordQueryIndexPlan("an_index", fullValueScan, true));
    Optional<PlannerBindings> newBindings = matcher.bindMatches(PlannerBindings.empty(), root.get()).findFirst();
    // check the the bindings are what we expect, and that none of the existing ones were clobbered
    assertTrue(newBindings.isPresent());
    PlannerBindings allBindings = newBindings.get().mergedWith(getExistingBindings());
    assertExistingBindingsSurvived(allBindings);
    assertTrue(newBindings.get().containsKey(matcher));
    assertTrue(allBindings.containsKey(matcher));
    RecordQueryIndexPlan matched = allBindings.get(matcher);
    assertEquals(root.get(), matched);
}
Also used : IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) RelationalExpression(com.apple.foundationdb.record.query.plan.temp.RelationalExpression) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) Test(org.junit.jupiter.api.Test)

Example 15 with RecordQueryIndexPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan in project fdb-record-layer by FoundationDB.

the class ExpressionMatcherTest method treeDescentWithMixedBindings.

@Test
public void treeDescentWithMixedBindings() {
    // build a relatively complicated matcher
    BindingMatcher<? extends ExpressionRef<? extends RelationalExpression>> filterLeafMatcher = ReferenceMatchers.anyRef();
    BindingMatcher<QueryPredicate> predicateMatcher = QueryPredicateMatchers.anyPredicate();
    final BindingMatcher<LogicalFilterExpression> filterPlanMatcher = RelationalExpressionMatchers.logicalFilterExpression(MultiMatcher.AllMatcher.all(predicateMatcher), AnyMatcher.any(QuantifierMatchers.forEachQuantifierOverRef(filterLeafMatcher)));
    BindingMatcher<RecordQueryScanPlan> scanMatcher = RecordQueryPlanMatchers.scanPlan();
    BindingMatcher<LogicalUnionExpression> matcher = RelationalExpressionMatchers.logicalUnionExpression(ListMatcher.exactly(QuantifierMatchers.forEachQuantifier(filterPlanMatcher), QuantifierMatchers.forEachQuantifier(scanMatcher)));
    // build a relatively complicated expression
    QueryComponent andBranch1 = Query.field("field1").greaterThan(6);
    QueryComponent andBranch2 = Query.field("field2").equalsParameter("param");
    IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
    final Quantifier.ForEach quantifier = Quantifier.forEach(GroupExpressionRef.of(new RecordQueryIndexPlan("an_index", fullValueScan, true)));
    LogicalFilterExpression filterPlan = new LogicalFilterExpression(Query.and(andBranch1, andBranch2).expand(quantifier.getAlias()).getPredicates(), quantifier);
    RecordQueryScanPlan scanPlan = new RecordQueryScanPlan(ScanComparisons.EMPTY, true);
    RelationalExpression root = new LogicalUnionExpression(Quantifiers.forEachQuantifiers(ImmutableList.of(GroupExpressionRef.of(filterPlan), GroupExpressionRef.of(scanPlan))));
    assertTrue(filterPlanMatcher.bindMatches(PlannerBindings.empty(), filterPlan).findFirst().isPresent());
    // try to bind
    Optional<PlannerBindings> possibleBindings = matcher.bindMatches(PlannerBindings.empty(), root).findFirst();
    // check that all the bindings match what we expect
    assertTrue(possibleBindings.isPresent());
    PlannerBindings bindings = possibleBindings.get().mergedWith(getExistingBindings());
    assertEquals(root, bindings.get(matcher));
    assertEquals(filterPlan, bindings.get(filterPlanMatcher));
    assertEquals(scanPlan, bindings.get(scanMatcher));
    assertEquals(filterPlan.getPredicates(), bindings.getAll(predicateMatcher));
    // dereference
    assertEquals(filterPlan.getInner().getRangesOver().get(), bindings.get(filterLeafMatcher).get());
}
Also used : QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) RelationalExpression(com.apple.foundationdb.record.query.plan.temp.RelationalExpression) QueryPredicate(com.apple.foundationdb.record.query.predicates.QueryPredicate) RecordQueryScanPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) LogicalUnionExpression(com.apple.foundationdb.record.query.plan.temp.expressions.LogicalUnionExpression) LogicalFilterExpression(com.apple.foundationdb.record.query.plan.temp.expressions.LogicalFilterExpression) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) Test(org.junit.jupiter.api.Test)

Aggregations

RecordQueryIndexPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan)24 IndexScanParameters (com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters)14 Test (org.junit.jupiter.api.Test)13 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)12 Comparisons (com.apple.foundationdb.record.query.expressions.Comparisons)7 RecordQueryScanPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan)7 Index (com.apple.foundationdb.record.metadata.Index)5 IndexScanComparisons (com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons)5 ScanComparisons (com.apple.foundationdb.record.query.plan.ScanComparisons)5 RelationalExpression (com.apple.foundationdb.record.query.plan.temp.RelationalExpression)5 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)5 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)4 RecordQueryCoveringIndexPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan)4 RecordQueryUnionPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionPlan)4 RecordType (com.apple.foundationdb.record.metadata.RecordType)3 ThenKeyExpression (com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression)3 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)3 Nonnull (javax.annotation.Nonnull)3 Nullable (javax.annotation.Nullable)3 IndexScanType (com.apple.foundationdb.record.IndexScanType)2