001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.filter;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Objects;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.CompareOperator;
025import org.apache.hadoop.hbase.PrivateCellUtil;
026import org.apache.hadoop.hbase.util.Bytes;
027import org.apache.yetus.audience.InterfaceAudience;
028
029import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
030
031import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
032import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
034import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.CompareType;
035
036/**
037 * This is a generic filter to be used to filter by comparison. It takes an operator (equal,
038 * greater, not equal, etc) and a byte [] comparator.
039 * <p>
040 * To filter by row key, use {@link RowFilter}.
041 * <p>
042 * To filter by column family, use {@link FamilyFilter}.
043 * <p>
044 * To filter by column qualifier, use {@link QualifierFilter}.
045 * <p>
046 * To filter by value, use {@link ValueFilter}.
047 * <p>
048 * These filters can be wrapped with {@link SkipFilter} and {@link WhileMatchFilter} to add more
049 * control.
050 * <p>
051 * Multiple filters can be combined using {@link FilterList}.
052 */
053@InterfaceAudience.Public
054public abstract class CompareFilter extends FilterBase {
055  /**
056   * Comparison operators. For filters only! Use {@link CompareOperator} otherwise. It
057   * (intentionally) has at least the below enums with same names.
058   * @deprecated since 2.0.0. Will be removed in 3.0.0. Use {@link CompareOperator} instead.
059   */
060  @Deprecated
061  @InterfaceAudience.Public
062  public enum CompareOp {
063    /** less than */
064    LESS,
065    /** less than or equal to */
066    LESS_OR_EQUAL,
067    /** equals */
068    EQUAL,
069    /** not equal */
070    NOT_EQUAL,
071    /** greater than or equal to */
072    GREATER_OR_EQUAL,
073    /** greater than */
074    GREATER,
075    /** no operation */
076    NO_OP,
077  }
078
079  protected CompareOperator op;
080  protected ByteArrayComparable comparator;
081
082  /**
083   * Constructor.
084   * @param compareOp  the compare op for row matching
085   * @param comparator the comparator for row matching
086   * @deprecated Since 2.0.0. Will be removed in 3.0.0. Use other constructor.
087   */
088  @Deprecated
089  public CompareFilter(final CompareOp compareOp, final ByteArrayComparable comparator) {
090    this(CompareOperator.valueOf(compareOp.name()), comparator);
091  }
092
093  /**
094   * Constructor.
095   * @param op         the compare op for row matching
096   * @param comparator the comparator for row matching
097   */
098  public CompareFilter(final CompareOperator op, final ByteArrayComparable comparator) {
099    this.op = op;
100    this.comparator = comparator;
101  }
102
103  /**
104   * n * @deprecated since 2.0.0. Will be removed in 3.0.0. Use {@link #getCompareOperator()}
105   * instead.
106   */
107  @Deprecated
108  public CompareOp getOperator() {
109    return CompareOp.valueOf(op.name());
110  }
111
112  public CompareOperator getCompareOperator() {
113    return op;
114  }
115
116  /** Returns the comparator */
117  public ByteArrayComparable getComparator() {
118    return comparator;
119  }
120
121  @Override
122  public boolean filterRowKey(Cell cell) throws IOException {
123    // Impl in FilterBase might do unnecessary copy for Off heap backed Cells.
124    return false;
125  }
126
127  /**
128   * @deprecated Since 2.0.0. Will be removed in 3.0.0. Use
129   *             {@link #compareRow(CompareOperator, ByteArrayComparable, Cell)}
130   */
131  @Deprecated
132  protected boolean compareRow(final CompareOp compareOp, final ByteArrayComparable comparator,
133    final Cell cell) {
134    if (compareOp == CompareOp.NO_OP) {
135      return true;
136    }
137    int compareResult = PrivateCellUtil.compareRow(cell, comparator);
138    return compare(compareOp, compareResult);
139  }
140
141  protected boolean compareRow(final CompareOperator op, final ByteArrayComparable comparator,
142    final Cell cell) {
143    if (op == CompareOperator.NO_OP) {
144      return true;
145    }
146    int compareResult = PrivateCellUtil.compareRow(cell, comparator);
147    return compare(op, compareResult);
148  }
149
150  /**
151   * @deprecated Since 2.0.0. Will be removed in 3.0.0. Use
152   *             {@link #compareFamily(CompareOperator, ByteArrayComparable, Cell)}
153   */
154  @Deprecated
155  protected boolean compareFamily(final CompareOp compareOp, final ByteArrayComparable comparator,
156    final Cell cell) {
157    if (compareOp == CompareOp.NO_OP) {
158      return true;
159    }
160    int compareResult = PrivateCellUtil.compareFamily(cell, comparator);
161    return compare(compareOp, compareResult);
162  }
163
164  protected boolean compareFamily(final CompareOperator op, final ByteArrayComparable comparator,
165    final Cell cell) {
166    if (op == CompareOperator.NO_OP) {
167      return true;
168    }
169    int compareResult = PrivateCellUtil.compareFamily(cell, comparator);
170    return compare(op, compareResult);
171  }
172
173  /**
174   * @deprecated Since 2.0.0. Will be removed in 3.0.0. Use
175   *             {@link #compareQualifier(CompareOperator, ByteArrayComparable, Cell)}
176   */
177  @Deprecated
178  protected boolean compareQualifier(final CompareOp compareOp,
179    final ByteArrayComparable comparator, final Cell cell) {
180    // We do not call through to the non-deprecated method for perf reasons.
181    if (compareOp == CompareOp.NO_OP) {
182      return true;
183    }
184    int compareResult = PrivateCellUtil.compareQualifier(cell, comparator);
185    return compare(compareOp, compareResult);
186  }
187
188  protected boolean compareQualifier(final CompareOperator op, final ByteArrayComparable comparator,
189    final Cell cell) {
190    // We do not call through to the non-deprecated method for perf reasons.
191    if (op == CompareOperator.NO_OP) {
192      return true;
193    }
194    int compareResult = PrivateCellUtil.compareQualifier(cell, comparator);
195    return compare(op, compareResult);
196  }
197
198  /**
199   * @deprecated Since 2.0.0. Will be removed in 3.0.0. Use
200   *             {@link #compareValue(CompareOperator, ByteArrayComparable, Cell)}
201   */
202  @Deprecated
203  protected boolean compareValue(final CompareOp compareOp, final ByteArrayComparable comparator,
204    final Cell cell) {
205    // We do not call through to the non-deprecated method for perf reasons.
206    if (compareOp == CompareOp.NO_OP) {
207      return true;
208    }
209    int compareResult = PrivateCellUtil.compareValue(cell, comparator);
210    return compare(compareOp, compareResult);
211  }
212
213  protected boolean compareValue(final CompareOperator op, final ByteArrayComparable comparator,
214    final Cell cell) {
215    if (op == CompareOperator.NO_OP) {
216      return true;
217    }
218    int compareResult = PrivateCellUtil.compareValue(cell, comparator);
219    return compare(op, compareResult);
220  }
221
222  static boolean compare(final CompareOp op, int compareResult) {
223    switch (op) {
224      case LESS:
225        return compareResult <= 0;
226      case LESS_OR_EQUAL:
227        return compareResult < 0;
228      case EQUAL:
229        return compareResult != 0;
230      case NOT_EQUAL:
231        return compareResult == 0;
232      case GREATER_OR_EQUAL:
233        return compareResult > 0;
234      case GREATER:
235        return compareResult >= 0;
236      default:
237        throw new RuntimeException("Unknown Compare op " + op.name());
238    }
239  }
240
241  static boolean compare(final CompareOperator op, int compareResult) {
242    switch (op) {
243      case LESS:
244        return compareResult <= 0;
245      case LESS_OR_EQUAL:
246        return compareResult < 0;
247      case EQUAL:
248        return compareResult != 0;
249      case NOT_EQUAL:
250        return compareResult == 0;
251      case GREATER_OR_EQUAL:
252        return compareResult > 0;
253      case GREATER:
254        return compareResult >= 0;
255      default:
256        throw new RuntimeException("Unknown Compare op " + op.name());
257    }
258  }
259
260  /** Returns an array of heterogeneous objects */
261  public static ArrayList<Object> extractArguments(ArrayList<byte[]> filterArguments) {
262    Preconditions.checkArgument(filterArguments.size() == 2, "Expected 2 but got: %s",
263      filterArguments.size());
264    CompareOperator op = ParseFilter.createCompareOperator(filterArguments.get(0));
265    ByteArrayComparable comparator =
266      ParseFilter.createComparator(ParseFilter.removeQuotesFromByteArray(filterArguments.get(1)));
267
268    if (comparator instanceof RegexStringComparator || comparator instanceof SubstringComparator) {
269      if (op != CompareOperator.EQUAL && op != CompareOperator.NOT_EQUAL) {
270        throw new IllegalArgumentException("A regexstring comparator and substring comparator"
271          + " can only be used with EQUAL and NOT_EQUAL");
272      }
273    }
274    ArrayList<Object> arguments = new ArrayList<>(2);
275    arguments.add(op);
276    arguments.add(comparator);
277    return arguments;
278  }
279
280  /** Returns A pb instance to represent this instance. */
281  FilterProtos.CompareFilter convert() {
282    FilterProtos.CompareFilter.Builder builder = FilterProtos.CompareFilter.newBuilder();
283    HBaseProtos.CompareType compareOp = CompareType.valueOf(this.op.name());
284    builder.setCompareOp(compareOp);
285    if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator));
286    return builder.build();
287  }
288
289  /**
290   * Returns true if and only if the fields of the filter that are serialized are equal to the
291   * corresponding fields in other. Used for testing.
292   */
293  @Override
294  boolean areSerializedFieldsEqual(Filter o) {
295    if (o == this) {
296      return true;
297    }
298    if (!(o instanceof CompareFilter)) {
299      return false;
300    }
301    CompareFilter other = (CompareFilter) o;
302    return this.getCompareOperator().equals(other.getCompareOperator())
303      && (this.getComparator() == other.getComparator()
304        || this.getComparator().areSerializedFieldsEqual(other.getComparator()));
305  }
306
307  @Override
308  public String toString() {
309    return String.format("%s (%s, %s)", this.getClass().getSimpleName(), this.op.name(),
310      Bytes.toStringBinary(this.comparator.getValue()));
311  }
312
313  @Override
314  public boolean equals(Object obj) {
315    return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
316  }
317
318  @Override
319  public int hashCode() {
320    return Objects.hash(this.getComparator(), this.getCompareOperator());
321  }
322}