ColumnRange.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.planner;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import java.util.List;
import java.util.Optional;
/**
* There are two kinds of predicates for a column: `is null` predicate and other predicates that
* the value of a column is not null, e.g., col=1, col>2, col in (1,2,3), etc.
*
* This can represent both conjunctive and disjunctive predicates for a column.
*
* The meaning of the predicates is: `conjunctiveIsNull` AND (`rangeSet` OR `disjunctiveIsNull`)
*
* Notes about internal state:
* 1. If `conjunctiveIsNull` and `disjunctiveIsNull` are both false and `rangeSet` is null,
* it means that there is no filter for the column. See {@link ColumnRange#hasFilter()}.
* 2. If `rangeSet` is empty, it means that the `not null` predicates are folded to false literal,
* i.e., col=1 and col=2.
*/
public class ColumnRange {
private boolean hasConjunctiveIsNull;
private boolean hasDisjunctiveIsNull;
private RangeSet<ColumnBound> rangeSet;
private ColumnRange() {
}
public void intersect(List<Range<ColumnBound>> disjunctiveRanges) {
if (disjunctiveRanges != null && !disjunctiveRanges.isEmpty()) {
if (rangeSet == null) {
rangeSet = TreeRangeSet.create();
disjunctiveRanges.forEach(rangeSet::add);
} else {
RangeSet<ColumnBound> merged = TreeRangeSet.create();
disjunctiveRanges.forEach(range -> merged.addAll(rangeSet.subRangeSet(range)));
rangeSet = merged;
}
}
}
public Optional<RangeSet<ColumnBound>> getRangeSet() {
if (rangeSet == null) {
return Optional.empty();
} else {
return Optional.of(rangeSet);
}
}
public static ColumnRange create() {
return new ColumnRange();
}
public boolean hasConjunctiveIsNull() {
return hasConjunctiveIsNull;
}
public ColumnRange setHasConjunctiveIsNull(boolean hasConjunctiveIsNull) {
this.hasConjunctiveIsNull = hasConjunctiveIsNull;
return this;
}
public boolean hasDisjunctiveIsNull() {
return hasDisjunctiveIsNull;
}
public ColumnRange setHasDisjunctiveIsNull(boolean hasDisjunctiveIsNull) {
this.hasDisjunctiveIsNull = hasDisjunctiveIsNull;
return this;
}
public boolean hasFilter() {
return hasConjunctiveIsNull || hasDisjunctiveIsNull || rangeSet != null;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("hasConjunctiveIsNull", hasConjunctiveIsNull)
.add("hasDisjunctiveIsNull", hasDisjunctiveIsNull)
.add("rangeSet", rangeSet)
.toString();
}
}