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]")))));
}
}
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())));
}
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);
}
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);
}
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());
}
Aggregations