PartitionSelection.java
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans.algebra;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Partition selection carried by scan plans.
*/
public abstract class PartitionSelection<P> {
/**
* true means the partition prune rule has processed this scan.
*/
public final boolean partitionPruned;
/**
* true means this scan's selected partitions are constrained by a partition predicate
* or explicit partition/tablet selection.
*/
public final boolean hasPartitionConstraint;
private final Set<P> appliedPartitionSnapshot;
private final List<Slot> appliedPartitionSlots;
private final Set<Expression> appliedPartitionConjuncts;
protected PartitionSelection(boolean partitionPruned, boolean hasPartitionConstraint) {
this.partitionPruned = partitionPruned;
this.hasPartitionConstraint = hasPartitionConstraint;
this.appliedPartitionSnapshot = null;
this.appliedPartitionSlots = null;
this.appliedPartitionConjuncts = null;
}
protected PartitionSelection(boolean partitionPruned, PartitionSelection<P> source) {
PartitionSelection<P> nonNullSource = Objects.requireNonNull(source, "source is null");
this.partitionPruned = partitionPruned;
this.hasPartitionConstraint = nonNullSource.hasPartitionConstraint;
this.appliedPartitionSnapshot = nonNullSource.appliedPartitionSnapshot;
this.appliedPartitionSlots = nonNullSource.appliedPartitionSlots;
this.appliedPartitionConjuncts = nonNullSource.appliedPartitionConjuncts;
}
protected PartitionSelection(boolean partitionPruned, boolean hasPartitionConstraint,
PartitionSelection<P> source) {
PartitionSelection<P> nonNullSource = Objects.requireNonNull(source, "source is null");
this.partitionPruned = partitionPruned;
this.hasPartitionConstraint = hasPartitionConstraint;
this.appliedPartitionSnapshot = nonNullSource.appliedPartitionSnapshot;
this.appliedPartitionSlots = nonNullSource.appliedPartitionSlots;
this.appliedPartitionConjuncts = nonNullSource.appliedPartitionConjuncts;
}
protected PartitionSelection(boolean partitionPruned, boolean hasPartitionConstraint,
Collection<P> partitionSnapshot, List<Slot> partitionSlots, Set<Expression> conjuncts) {
this.partitionPruned = partitionPruned;
this.hasPartitionConstraint = hasPartitionConstraint;
this.appliedPartitionSnapshot = ImmutableSet.copyOf(Objects.requireNonNull(partitionSnapshot,
"partitionSnapshot is null"));
this.appliedPartitionSlots = ImmutableList.copyOf(Objects.requireNonNull(partitionSlots,
"partitionSlots is null"));
this.appliedPartitionConjuncts = ImmutableSet.copyOf(Objects.requireNonNull(conjuncts, "conjuncts is null"));
}
/**
* Returns partition conjuncts that have already been applied, rewritten by the given slot map.
*/
protected Set<Expression> rewriteAppliedPartitionConjuncts(Collection<P> selectedPartitions,
Map<String, Slot> nameToOutputSlot) {
if (!partitionPruned || appliedPartitionConjuncts == null) {
return ImmutableSet.of();
}
if (!appliedPartitionSnapshot.containsAll(selectedPartitions)) {
return ImmutableSet.of();
}
Map<Expression, Expression> slotReplaceMap = buildSlotReplaceMap(nameToOutputSlot);
if (slotReplaceMap == null) {
return ImmutableSet.of();
}
ImmutableSet.Builder<Expression> rewrittenConjuncts =
ImmutableSet.builderWithExpectedSize(appliedPartitionConjuncts.size());
for (Expression conjunct : appliedPartitionConjuncts) {
rewrittenConjuncts.add(slotReplaceMap.isEmpty()
? conjunct : ExpressionUtils.replace(conjunct, slotReplaceMap));
}
return rewrittenConjuncts.build();
}
/**
* Map each recorded partition slot to the current output slot of the same column name.
* Returns null when any recorded partition slot cannot be located.
*/
private Map<Expression, Expression> buildSlotReplaceMap(Map<String, Slot> nameToOutputSlot) {
Map<Expression, Expression> replaceMap = new HashMap<>(appliedPartitionSlots.size());
for (Slot snapshot : appliedPartitionSlots) {
Slot current = nameToOutputSlot.get(snapshot.getName().toLowerCase());
if (current == null) {
return null;
}
if (!snapshot.equals(current)) {
replaceMap.put(snapshot, current);
}
}
return replaceMap;
}
protected boolean partitionSelectionBaseEquals(PartitionSelection<?> that) {
return partitionPruned == that.partitionPruned
&& hasPartitionConstraint == that.hasPartitionConstraint
&& Objects.equals(appliedPartitionSnapshot, that.appliedPartitionSnapshot)
&& Objects.equals(appliedPartitionSlots, that.appliedPartitionSlots)
&& Objects.equals(appliedPartitionConjuncts, that.appliedPartitionConjuncts);
}
protected int partitionSelectionBaseHashCode() {
return Objects.hash(partitionPruned, hasPartitionConstraint, appliedPartitionSnapshot,
appliedPartitionSlots, appliedPartitionConjuncts);
}
}