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