use of com.apple.foundationdb.record.query.predicates.Value in project fdb-record-layer by FoundationDB.
the class ImplementInJoinRule method onMatch.
@SuppressWarnings("java:S135")
@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
final var context = call.getContext();
final var bindings = call.getBindings();
final var requestedOrderingsOptional = call.getInterestingProperty(OrderingAttribute.ORDERING);
if (requestedOrderingsOptional.isEmpty()) {
return;
}
final var requestedOrderings = requestedOrderingsOptional.get();
final var selectExpression = bindings.get(root);
if (!selectExpression.getPredicates().isEmpty()) {
return;
}
final var explodeQuantifiers = bindings.get(explodeQuantifiersMatcher);
if (explodeQuantifiers.isEmpty()) {
return;
}
final var explodeAliasToQuantifierMap = Quantifiers.aliasToQuantifierMap(explodeQuantifiers);
final var explodeAliases = explodeAliasToQuantifierMap.keySet();
final var innerQuantifierOptional = findInnerQuantifier(selectExpression, explodeQuantifiers, explodeAliases);
if (innerQuantifierOptional.isEmpty()) {
return;
}
final var innerQuantifier = innerQuantifierOptional.get();
final List<? extends Value> resultValues = selectExpression.getResultValues();
if (resultValues.stream().anyMatch(resultValue -> !(resultValue instanceof QuantifiedColumnValue) || !((QuantifiedColumnValue) resultValue).getAlias().equals(innerQuantifier.getAlias()))) {
return;
}
final var explodeExpressions = bindings.getAll(explodeExpressionMatcher);
final var quantifierToExplodeBiMap = computeQuantifierToExplodeMap(explodeQuantifiers, explodeExpressions.stream().collect(LinkedIdentitySet.toLinkedIdentitySet()));
final Map<Ordering, ImmutableList<RecordQueryPlan>> groupedByOrdering = innerQuantifier.getRangesOver().getMembers().stream().flatMap(relationalExpression -> relationalExpression.narrowMaybe(RecordQueryPlan.class).stream()).flatMap(plan -> {
final Optional<Ordering> orderingForLegOptional = OrderingProperty.evaluate(plan, context);
return orderingForLegOptional.stream().map(ordering -> Pair.of(ordering, plan));
}).collect(Collectors.groupingBy(Pair::getLeft, Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList())));
for (final Map.Entry<Ordering, ImmutableList<RecordQueryPlan>> providedOrderingEntry : groupedByOrdering.entrySet()) {
final var providedOrdering = providedOrderingEntry.getKey();
for (final RequestedOrdering requestedOrdering : requestedOrderings) {
final ImmutableList<InSource> sources = getInSourcesForRequestedOrdering(explodeAliasToQuantifierMap, explodeAliases, quantifierToExplodeBiMap, providedOrdering, requestedOrdering);
if (sources.isEmpty()) {
continue;
}
final var reverseSources = Lists.reverse(sources);
GroupExpressionRef<RecordQueryPlan> newInnerPlanReference = GroupExpressionRef.from(providedOrderingEntry.getValue());
for (final InSource inSource : reverseSources) {
final var inJoinPlan = inSource.toInJoinPlan(Quantifier.physical(newInnerPlanReference));
newInnerPlanReference = GroupExpressionRef.of(inJoinPlan);
}
call.yield(newInnerPlanReference);
}
}
}
use of com.apple.foundationdb.record.query.predicates.Value in project fdb-record-layer by FoundationDB.
the class FDBSelectorPlanTest method testPlanValues.
@DualPlannerTest
void testPlanValues() throws Throwable {
complexQuerySetup(NO_HOOK);
RecordQuery query1 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").build();
RecordQuery query2 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_2").equalsValue(1)).build();
RecordQueryPlan plan = RecordQuerySelectorPlan.from(plan(query1, query2), List.of(50, 50));
List<? extends Value> resultValues = plan.getResultValues();
assertThat(resultValues.size(), is(1));
ValuePickerValue value = (ValuePickerValue) resultValues.get(0);
List<Value> subValues = ImmutableList.copyOf(value.getChildren());
assertThat(subValues.size(), is(2));
assertThat(subValues.get(0), is(plan.getQuantifiers().get(0).getFlowedValues().get(0)));
assertThat(subValues.get(1), is(plan.getQuantifiers().get(1).getFlowedValues().get(0)));
}
use of com.apple.foundationdb.record.query.predicates.Value in project fdb-record-layer by FoundationDB.
the class FDBSelectorPlanTest method testTwoInnerPlansWithContinuation.
@DualPlannerTest
void testTwoInnerPlansWithContinuation() throws Throwable {
complexQuerySetup(NO_HOOK);
RecordQuery query1 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").build();
RecordQuery query2 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_2").equalsValue(1)).build();
// This will select plan 1 for the first execution and later some illegal value. The idea is that after the
// first iteration, the continuation should determine the selected plan and not the relative priorities
RecordQueryPlan planUnderTest = RecordQuerySelectorPlan.from(plan(query1, query2), mockSelector());
// Iteration 1, start with empty continuation
RecordCursorResult<FDBQueriedRecord<Message>> result = querySimpleRecordStoreWithContinuation(NO_HOOK, planUnderTest, EvaluationContext::empty, null, ExecuteProperties.newBuilder().setReturnedRowLimit(15).build(), count -> assertThat(count, is(15)), record -> assertThat(record.getNumValue2(), is(1)), context -> assertDiscardedAtMost(30, context));
assertThat(result.getNoNextReason(), is(RecordCursor.NoNextReason.RETURN_LIMIT_REACHED));
// Iteration 2, start with previous continuation
byte[] continuation = result.getContinuation().toBytes();
result = querySimpleRecordStoreWithContinuation(NO_HOOK, planUnderTest, EvaluationContext::empty, continuation, ExecuteProperties.newBuilder().setReturnedRowLimit(15).build(), count -> assertThat(count, is(15)), record -> assertThat(record.getNumValue2(), is(1)), context -> assertDiscardedAtMost(30, context));
assertThat(result.getNoNextReason(), is(RecordCursor.NoNextReason.RETURN_LIMIT_REACHED));
// Iteration 3, start with previous continuation, reach end
continuation = result.getContinuation().toBytes();
result = querySimpleRecordStoreWithContinuation(NO_HOOK, planUnderTest, EvaluationContext::empty, continuation, ExecuteProperties.newBuilder().setReturnedRowLimit(15).build(), count -> assertThat(count, is(3)), record -> assertThat(record.getNumValue2(), is(1)), context -> assertDiscardedAtMost(8, context));
assertThat(result.hasNext(), is(false));
assertThat(result.getNoNextReason(), is(RecordCursor.NoNextReason.SOURCE_EXHAUSTED));
}
use of com.apple.foundationdb.record.query.predicates.Value in project fdb-record-layer by FoundationDB.
the class RecordQueryChooserPlanBase method calculateChildrenValues.
/**
* This utility calculates the list of values that are returned by the plan. The plan returns a list of
* {@link ValuePickerValue} that each represent the values returned by one of the child plans.
* Each {@link ValuePickerValue} holds a "selected index" that determines which of the sub-values it references, so
* that, in all, when the same "selected index" is chosen for all picker value, one would get back a consistent set
* of values, representing one of the child plans for this plan.
*
* @return list of {@link ValuePickerValue} representing all the values from all the sub plans
*/
private List<? extends Value> calculateChildrenValues() {
// Store all values in a multimap, indexed by the ordinal of the value in the returned list
// Each list represents all the i'th Value from each of the sub plans
ImmutableListMultimap.Builder<Integer, Value> mapBuilder = ImmutableListMultimap.builder();
quantifiers.forEach(quantifier -> {
List<? extends Value> values = quantifier.getFlowedValues();
for (int i = 0; i < values.size(); i++) {
mapBuilder.put(i, values.get(i));
}
});
ImmutableListMultimap<Integer, ? extends Value> valuesMap = mapBuilder.build();
ImmutableList.Builder<ValuePickerValue> resultBuilder = ImmutableList.builder();
for (int i = 0; i < valuesMap.keySet().size(); i++) {
ImmutableList<? extends Value> subValues = valuesMap.get(i);
// For now, fix all the picker values to return the first sub value
resultBuilder.add(new ValuePickerValue(0, subValues));
}
return resultBuilder.build();
}
use of com.apple.foundationdb.record.query.predicates.Value in project fdb-record-layer by FoundationDB.
the class ValueIndexExpansionVisitor method expand.
@Nonnull
@Override
public MatchCandidate expand(@Nonnull final Quantifier.ForEach baseQuantifier, @Nullable final KeyExpression primaryKey, final boolean isReverse) {
Debugger.updateIndex(ValueComparisonRangePredicate.Placeholder.class, old -> 0);
final ImmutableList.Builder<GraphExpansion> allExpansionsBuilder = ImmutableList.builder();
// add the value for the flow of records
final QuantifiedColumnValue recordValue = QuantifiedColumnValue.of(baseQuantifier.getAlias(), 0);
allExpansionsBuilder.add(GraphExpansion.ofResultValueAndQuantifier(recordValue, baseQuantifier));
KeyExpression rootExpression = index.getRootExpression();
final int keyValueSplitPoint;
if (rootExpression instanceof KeyWithValueExpression) {
final KeyWithValueExpression keyWithValueExpression = (KeyWithValueExpression) rootExpression;
keyValueSplitPoint = keyWithValueExpression.getSplitPoint();
rootExpression = keyWithValueExpression.getInnerKey();
} else {
keyValueSplitPoint = -1;
}
final List<Value> keyValues = Lists.newArrayList();
final List<Value> valueValues = Lists.newArrayList();
final VisitorState initialState = VisitorState.of(keyValues, valueValues, baseQuantifier.getAlias(), ImmutableList.of(), keyValueSplitPoint, 0);
final GraphExpansion keyValueExpansion = pop(rootExpression.expand(push(initialState)));
allExpansionsBuilder.add(keyValueExpansion);
final int keySize = keyValues.size();
if (primaryKey != null) {
// unfortunately we must copy as the returned list is not guaranteed to be mutable which is needed for the
// trimPrimaryKey() function as it is causing a side-effect
final List<KeyExpression> trimmedPrimaryKeys = Lists.newArrayList(primaryKey.normalizeKeyForPositions());
index.trimPrimaryKey(trimmedPrimaryKeys);
for (int i = 0; i < trimmedPrimaryKeys.size(); i++) {
final KeyExpression primaryKeyPart = trimmedPrimaryKeys.get(i);
final VisitorState initialStateForKeyPart = VisitorState.of(keyValues, Lists.newArrayList(), baseQuantifier.getAlias(), ImmutableList.of(), -1, keySize + i);
final GraphExpansion primaryKeyPartExpansion = pop(primaryKeyPart.expand(push(initialStateForKeyPart)));
allExpansionsBuilder.add(primaryKeyPartExpansion);
}
}
final GraphExpansion completeExpansion = GraphExpansion.ofOthers(allExpansionsBuilder.build());
final List<CorrelationIdentifier> parameters = completeExpansion.getPlaceholderAliases();
final MatchableSortExpression matchableSortExpression = new MatchableSortExpression(parameters, isReverse, completeExpansion.buildSelect());
return new ValueIndexScanMatchCandidate(index, recordTypes, ExpressionRefTraversal.withRoot(GroupExpressionRef.of(matchableSortExpression)), parameters, recordValue, keyValues, valueValues, fullKey(index, primaryKey));
}
Aggregations