1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.tikv.common.predicates;
19
20 import static java.util.Objects.requireNonNull;
21 import static org.tikv.common.predicates.PredicateUtils.mergeCNFExpressions;
22
23 import com.google.common.collect.ImmutableList;
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.IdentityHashMap;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.Set;
30 import org.tikv.common.exception.TiExpressionException;
31 import org.tikv.common.expression.Expression;
32 import org.tikv.common.meta.TiColumnInfo;
33 import org.tikv.common.meta.TiIndexColumn;
34 import org.tikv.common.meta.TiIndexInfo;
35 import org.tikv.common.meta.TiTableInfo;
36 import org.tikv.common.types.DataType;
37
38 public class ScanSpec {
39 private final List<Expression> pointPredicates;
40 private final Optional<Expression> rangePredicate;
41 private final Set<Expression> residualPredicates;
42
43 private ScanSpec(
44 List<Expression> pointPredicates,
45 Optional<Expression> rangePredicate,
46 Set<Expression> residualPredicates) {
47 this.pointPredicates = pointPredicates;
48 this.rangePredicate = rangePredicate;
49 this.residualPredicates = residualPredicates;
50 }
51
52 public List<Expression> getPointPredicates() {
53 return pointPredicates;
54 }
55
56 public Optional<Expression> getRangePredicate() {
57 return rangePredicate;
58 }
59
60 public Set<Expression> getResidualPredicates() {
61 return residualPredicates;
62 }
63
64 public static class Builder {
65 private final IdentityHashMap<TiIndexColumn, List<Expression>> pointPredicates =
66 new IdentityHashMap<>();
67 private final TiTableInfo table;
68 private final TiIndexInfo index;
69 private final List<Expression> rangePredicates = new ArrayList<>();
70 private final List<Expression> residualPredicates = new ArrayList<>();
71 private final Set<Expression> residualCandidates = new HashSet<>();
72 private TiIndexColumn rangeColumn;
73
74 public Builder(TiTableInfo table, TiIndexInfo index) {
75 this.table = table;
76 this.index = index;
77 }
78
79 void addResidualPredicate(Expression predicate) {
80 residualPredicates.add(predicate);
81 }
82
83 void addAllPredicates(List<Expression> predicates) {
84 residualCandidates.addAll(predicates);
85 }
86
87 void addPointPredicate(TiIndexColumn col, Expression predicate) {
88 requireNonNull(col, "index column is null");
89 requireNonNull(predicate, "predicate is null");
90 if (pointPredicates.containsKey(col)) {
91 List<Expression> predicates = pointPredicates.get(col);
92 predicates.add(predicate);
93 } else {
94 List<Expression> predicates = new ArrayList<>();
95 predicates.add(predicate);
96 pointPredicates.put(col, predicates);
97 }
98 }
99
100 void addRangePredicate(TiIndexColumn col, Expression predicate) {
101 requireNonNull(col, "col is null");
102 if (rangeColumn == null) {
103 rangeColumn = col;
104 } else if (!rangeColumn.equals(col)) {
105 throw new TiExpressionException("Cannot reset range predicates");
106 }
107 rangePredicates.add(predicate);
108 }
109
110 public ScanSpec build() {
111 List<Expression> points = new ArrayList<>();
112 List<DataType> pointTypes = new ArrayList<>();
113 Set<Expression> pushedPredicates = new HashSet<>();
114 if (index != null) {
115 for (TiIndexColumn indexColumn : index.getIndexColumns()) {
116 List<Expression> predicates = pointPredicates.get(indexColumn);
117 if (predicates == null) {
118 break;
119 }
120 pushedPredicates.addAll(predicates);
121 TiColumnInfo tiColumnInfo = table.getColumn(indexColumn.getOffset());
122 DataType type = tiColumnInfo.getType();
123 points.add(mergeCNFExpressions(predicates));
124 pointTypes.add(type);
125 }
126 }
127 Optional<Expression> newRangePred =
128 rangePredicates.isEmpty()
129 ? Optional.empty()
130 : Optional.ofNullable(mergeCNFExpressions(rangePredicates));
131 pushedPredicates.addAll(rangePredicates);
132
133 Set<Expression> newResidualPredicates = new HashSet<>(residualPredicates);
134 for (Expression pred : residualCandidates) {
135 if (!pushedPredicates.contains(pred)) {
136 newResidualPredicates.add(pred);
137 }
138 }
139
140 return new ScanSpec(ImmutableList.copyOf(points), newRangePred, newResidualPredicates);
141 }
142 }
143 }