use of com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan in project fdb-record-layer by FoundationDB.
the class ExpressionMatcherTest method nestedTypeMatchers.
@Test
public void nestedTypeMatchers() {
BindingMatcher<RecordQueryIndexPlan> childMatcher1 = RecordQueryPlanMatchers.indexPlan();
BindingMatcher<RecordQueryScanPlan> childMatcher2 = RecordQueryPlanMatchers.scanPlan();
BindingMatcher<RecordQueryUnionPlan> parentMatcher = RecordQueryPlanMatchers.union(ListMatcher.exactly(QuantifierMatchers.physicalQuantifier(childMatcher1), QuantifierMatchers.physicalQuantifier(childMatcher2)));
IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
RecordQueryIndexPlan child1 = new RecordQueryIndexPlan("an_index", fullValueScan, true);
RecordQueryScanPlan child2 = new RecordQueryScanPlan(ScanComparisons.EMPTY, true);
// check matches if the children are in the right order
RelationalExpression root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child1, child2, EmptyKeyExpression.EMPTY, false);
Optional<PlannerBindings> possibleBindings = parentMatcher.bindMatches(PlannerBindings.empty(), root).findFirst();
assertTrue(possibleBindings.isPresent());
PlannerBindings allBindings = possibleBindings.get().mergedWith(getExistingBindings());
assertExistingBindingsSurvived(allBindings);
assertEquals(root, allBindings.get(parentMatcher));
assertEquals(child1, allBindings.get(childMatcher1));
assertEquals(child2, allBindings.get(childMatcher2));
// check that we fail to match if the children are in the wrong order
root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child2, child1, EmptyKeyExpression.EMPTY, false);
assertFalse(parentMatcher.bindMatches(PlannerBindings.empty(), root).findFirst().isPresent());
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan in project fdb-record-layer by FoundationDB.
the class ExpressionMatcherTest method matchChildOrder.
@Test
public void matchChildOrder() {
BindingMatcher<RecordQueryUnionPlan> parentMatcher = RecordQueryPlanMatchers.union(ListMatcher.exactly(QuantifierMatchers.physicalQuantifier(RecordQueryPlanMatchers.indexPlan()), QuantifierMatchers.physicalQuantifier(RecordQueryPlanMatchers.scanPlan())));
IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
RecordQueryIndexPlan child1 = new RecordQueryIndexPlan("an_index", fullValueScan, true);
RecordQueryScanPlan child2 = new RecordQueryScanPlan(ScanComparisons.EMPTY, true);
RelationalExpression root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child1, child2, EmptyKeyExpression.EMPTY, false);
assertTrue(parentMatcher.bindMatches(PlannerBindings.empty(), root).findFirst().isPresent());
root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child2, child1, EmptyKeyExpression.EMPTY, false);
assertFalse(parentMatcher.bindMatches(PlannerBindings.empty(), root).findFirst().isPresent());
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan in project fdb-record-layer by FoundationDB.
the class ExpressionMatcherTest method matchChildrenAsReferences.
@Test
public void matchChildrenAsReferences() {
BindingMatcher<? extends ExpressionRef<? extends RelationalExpression>> childMatcher1 = ReferenceMatchers.anyRef();
BindingMatcher<? extends ExpressionRef<? extends RelationalExpression>> childMatcher2 = ReferenceMatchers.anyRef();
BindingMatcher<RecordQueryUnionPlan> matcher = RecordQueryPlanMatchers.union(ListMatcher.exactly(QuantifierMatchers.physicalQuantifierOverRef(childMatcher1), QuantifierMatchers.physicalQuantifierOverRef(childMatcher2)));
IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
RecordQueryIndexPlan child1 = new RecordQueryIndexPlan("an_index", fullValueScan, true);
RecordQueryScanPlan child2 = new RecordQueryScanPlan(ScanComparisons.EMPTY, true);
RelationalExpression root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child1, child2, EmptyKeyExpression.EMPTY, false);
Optional<PlannerBindings> possibleBindings = matcher.bindMatches(PlannerBindings.empty(), root).findFirst();
assertTrue(possibleBindings.isPresent());
PlannerBindings newBindings = possibleBindings.get().mergedWith(getExistingBindings());
assertExistingBindingsSurvived(newBindings);
// check that root matches
assertEquals(root, newBindings.get(matcher));
// check that children are behind references
assertEquals(child1, newBindings.get(childMatcher1).get());
assertEquals(child2, newBindings.get(childMatcher2).get());
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planScan.
@Nonnull
private RecordQueryPlan planScan(@Nonnull CandidateScan candidateScan, @Nonnull IndexScanComparisons indexScanComparisons, boolean strictlySorted) {
RecordQueryPlan plan;
Set<String> possibleTypes;
if (candidateScan.index == null) {
final ScanComparisons scanComparisons = indexScanComparisons.getComparisons();
if (primaryKeyHasRecordTypePrefix && RecordTypeKeyComparison.hasRecordTypeKeyComparison(scanComparisons)) {
possibleTypes = RecordTypeKeyComparison.recordTypeKeyComparisonTypes(scanComparisons);
} else {
possibleTypes = metaData.getRecordTypes().keySet();
}
plan = new RecordQueryScanPlan(possibleTypes, scanComparisons, candidateScan.reverse, strictlySorted);
} else {
plan = new RecordQueryIndexPlan(candidateScan.index.getName(), indexScanComparisons, candidateScan.reverse, strictlySorted);
possibleTypes = getPossibleTypes(candidateScan.index);
}
// Add a type filter if the query plan might return records of more types than the query specified
plan = addTypeFilterIfNeeded(candidateScan, plan, possibleTypes);
return plan;
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan in project fdb-record-layer by FoundationDB.
the class PlanOrderingKey method forPlan.
@Nullable
public static PlanOrderingKey forPlan(@Nonnull RecordMetaData metaData, @Nonnull RecordQueryPlan queryPlan, @Nullable KeyExpression primaryKey) {
if (primaryKey == null) {
return null;
}
while (queryPlan instanceof RecordQueryFilterPlan) {
queryPlan = ((RecordQueryFilterPlan) queryPlan).getInnerPlan();
}
if (queryPlan instanceof RecordQueryPlanWithIndex) {
final RecordQueryPlanWithIndex indexPlan = (RecordQueryPlanWithIndex) queryPlan;
final Index index = metaData.getIndex(indexPlan.getIndexName());
final List<KeyExpression> keys = new ArrayList<>(index.getRootExpression().normalizeKeyForPositions());
int pkeyStart = keys.size();
int pKeyTail = pkeyStart;
// Primary keys come after index value keys, unless they were already part of it.
for (KeyExpression pkey : primaryKey.normalizeKeyForPositions()) {
int pos = keys.indexOf(pkey);
if (pos < 0) {
keys.add(pkey);
} else if (pkeyStart > pos) {
pkeyStart = pos;
}
}
final int prefixSize;
if (indexPlan instanceof RecordQueryIndexPlan) {
prefixSize = ((RecordQueryIndexPlan) indexPlan).getComparisons().getEqualitySize();
} else if (indexPlan instanceof RecordQueryTextIndexPlan) {
final TextScan textScan = ((RecordQueryTextIndexPlan) indexPlan).getTextScan();
int groupingSize = textScan.getGroupingComparisons() != null ? textScan.getGroupingComparisons().getEqualitySize() : 0;
int suffixSize = textScan.getSuffixComparisons() != null ? textScan.getSuffixComparisons().getEqualitySize() : 0;
if (textScan.getTextComparison().getType().isEquality()) {
// Can use the equality comparisons in the grouping columns and any columns after the text index
// plus the text column itself.
prefixSize = groupingSize + suffixSize + 1;
} else {
// by the token that the prefix scan just so happened to hit.
return null;
}
} else {
// Some unknown index plan. Maybe this should throw an error?
return null;
}
return new PlanOrderingKey(keys, prefixSize, pkeyStart, pKeyTail);
} else if (queryPlan instanceof RecordQueryScanPlan) {
final RecordQueryScanPlan scanPlan = (RecordQueryScanPlan) queryPlan;
return new PlanOrderingKey(primaryKey.normalizeKeyForPositions(), scanPlan.getComparisons().getEqualitySize(), 0, 0);
} else if (queryPlan instanceof RecordQueryIntersectionPlan) {
return forComparisonKey(((RecordQueryIntersectionPlan) queryPlan).getComparisonKey(), primaryKey);
} else if (queryPlan instanceof RecordQueryUnionPlan) {
return forComparisonKey(((RecordQueryUnionPlan) queryPlan).getComparisonKey(), primaryKey);
} else {
return null;
}
}
Aggregations