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 static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.nio.ByteBuffer;
026import java.util.regex.Pattern;
027import org.apache.hadoop.hbase.ByteBufferKeyValue;
028import org.apache.hadoop.hbase.Cell;
029import org.apache.hadoop.hbase.CompareOperator;
030import org.apache.hadoop.hbase.KeyValue;
031import org.apache.hadoop.hbase.testclassification.FilterTests;
032import org.apache.hadoop.hbase.testclassification.SmallTests;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.junit.jupiter.api.BeforeEach;
035import org.junit.jupiter.api.Tag;
036import org.junit.jupiter.api.Test;
037
038/**
039 * Tests the value filter
040 */
041@Tag(FilterTests.TAG)
042@Tag(SmallTests.TAG)
043public class TestSingleColumnValueFilter {
044
045  private static final byte[] ROW = Bytes.toBytes("test");
046  private static final byte[] COLUMN_FAMILY = Bytes.toBytes("test");
047  private static final byte[] COLUMN_QUALIFIER = Bytes.toBytes("foo");
048  private static final byte[] VAL_1 = Bytes.toBytes("a");
049  private static final byte[] VAL_2 = Bytes.toBytes("ab");
050  private static final byte[] VAL_3 = Bytes.toBytes("abc");
051  private static final byte[] VAL_4 = Bytes.toBytes("abcd");
052  private static final byte[] FULLSTRING_1 =
053    Bytes.toBytes("The quick brown fox jumps over the lazy dog.");
054  private static final byte[] FULLSTRING_2 =
055    Bytes.toBytes("The slow grey fox trips over the lazy dog.");
056  private static final String QUICK_SUBSTR = "quick";
057  private static final String QUICK_REGEX = ".+quick.+";
058  private static final Pattern QUICK_PATTERN =
059    Pattern.compile("QuIcK", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
060
061  Filter basicFilter;
062  Filter nullFilter;
063  Filter substrFilter;
064  Filter regexFilter;
065  Filter regexPatternFilter;
066
067  @BeforeEach
068  public void setUp() throws Exception {
069    basicFilter = basicFilterNew();
070    nullFilter = nullFilterNew();
071    substrFilter = substrFilterNew();
072    regexFilter = regexFilterNew();
073    regexPatternFilter = regexFilterNew(QUICK_PATTERN);
074  }
075
076  private Filter basicFilterNew() {
077    return new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER,
078      CompareOperator.GREATER_OR_EQUAL, VAL_2);
079  }
080
081  private Filter nullFilterNew() {
082    return new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER, CompareOperator.NOT_EQUAL,
083      new NullComparator());
084  }
085
086  private Filter substrFilterNew() {
087    return new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER, CompareOperator.EQUAL,
088      new SubstringComparator(QUICK_SUBSTR));
089  }
090
091  private Filter regexFilterNew() {
092    return new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER, CompareOperator.EQUAL,
093      new RegexStringComparator(QUICK_REGEX));
094  }
095
096  private Filter regexFilterNew(Pattern pattern) {
097    return new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER, CompareOperator.EQUAL,
098      new RegexStringComparator(pattern.pattern(), pattern.flags()));
099  }
100
101  @Test
102  public void testLongComparator() throws IOException {
103    Filter filter = new SingleColumnValueFilter(COLUMN_FAMILY, COLUMN_QUALIFIER,
104      CompareOperator.GREATER, new LongComparator(100L));
105    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, Bytes.toBytes(1L));
106    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell), "less than");
107    filter.reset();
108    byte[] buffer = cell.getBuffer();
109    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
110    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(c), "less than");
111    filter.reset();
112
113    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, Bytes.toBytes(100L));
114    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell), "Equals 100");
115    filter.reset();
116    buffer = cell.getBuffer();
117    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
118    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(c), "Equals 100");
119    filter.reset();
120
121    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, Bytes.toBytes(120L));
122    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "include 120");
123    filter.reset();
124    buffer = cell.getBuffer();
125    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
126    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "include 120");
127  }
128
129  private void basicFilterTests(SingleColumnValueFilter filter) throws Exception {
130    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_2);
131    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "basicFilter1");
132    byte[] buffer = cell.getBuffer();
133    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
134    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "basicFilter1");
135    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_3);
136    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "basicFilter2");
137    buffer = cell.getBuffer();
138    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
139    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "basicFilter2");
140    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_4);
141    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "basicFilter3");
142    buffer = cell.getBuffer();
143    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
144    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "basicFilter3");
145    assertFalse(filter.filterRow(), "basicFilterNotNull");
146    filter.reset();
147    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_1);
148    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell), "basicFilter4");
149    buffer = cell.getBuffer();
150    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
151    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(c), "basicFilter4");
152    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_2);
153    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(cell), "basicFilter4");
154    buffer = cell.getBuffer();
155    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
156    assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterCell(c), "basicFilter4");
157    assertFalse(filter.filterAllRemaining(), "basicFilterAllRemaining");
158    assertTrue(filter.filterRow(), "basicFilterNotNull");
159    filter.reset();
160    filter.setLatestVersionOnly(false);
161    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_1);
162    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "basicFilter5");
163    buffer = cell.getBuffer();
164    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
165    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "basicFilter5");
166    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, VAL_2);
167    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "basicFilter5");
168    buffer = cell.getBuffer();
169    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
170    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "basicFilter5");
171    assertFalse(filter.filterRow(), "basicFilterNotNull");
172  }
173
174  private void nullFilterTests(Filter filter) throws Exception {
175    ((SingleColumnValueFilter) filter).setFilterIfMissing(true);
176    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_1);
177    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "null1");
178    byte[] buffer = cell.getBuffer();
179    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
180    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "null1");
181    assertFalse(filter.filterRow(), "null1FilterRow");
182    filter.reset();
183    cell = new KeyValue(ROW, COLUMN_FAMILY, Bytes.toBytes("qual2"), FULLSTRING_2);
184    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "null2");
185    buffer = cell.getBuffer();
186    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
187    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "null2");
188    assertTrue(filter.filterRow(), "null2FilterRow");
189  }
190
191  private void substrFilterTests(Filter filter) throws Exception {
192    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_1);
193    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "substrTrue");
194    byte[] buffer = cell.getBuffer();
195    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
196    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "substrTrue");
197    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_2);
198    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "substrFalse");
199    buffer = cell.getBuffer();
200    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
201    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "substrFalse");
202    assertFalse(filter.filterAllRemaining(), "substrFilterAllRemaining");
203    assertFalse(filter.filterRow(), "substrFilterNotNull");
204  }
205
206  private void regexFilterTests(Filter filter) throws Exception {
207    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_1);
208    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "regexTrue");
209    byte[] buffer = cell.getBuffer();
210    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
211    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "regexTrue");
212    cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_2);
213    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "regexFalse");
214    buffer = cell.getBuffer();
215    c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
216    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "regexFalse");
217    assertFalse(filter.filterAllRemaining(), "regexFilterAllRemaining");
218    assertFalse(filter.filterRow(), "regexFilterNotNull");
219  }
220
221  private void regexPatternFilterTests(Filter filter) throws Exception {
222    KeyValue cell = new KeyValue(ROW, COLUMN_FAMILY, COLUMN_QUALIFIER, FULLSTRING_1);
223    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(cell), "regexTrue");
224    byte[] buffer = cell.getBuffer();
225    Cell c = new ByteBufferKeyValue(ByteBuffer.wrap(buffer), 0, buffer.length);
226    assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(c), "regexTrue");
227    assertFalse(filter.filterAllRemaining(), "regexFilterAllRemaining");
228    assertFalse(filter.filterRow(), "regexFilterNotNull");
229  }
230
231  private Filter serializationTest(Filter filter) throws Exception {
232    // Decompose filter to bytes.
233    byte[] buffer = filter.toByteArray();
234
235    // Recompose filter.
236    Filter newFilter = SingleColumnValueFilter.parseFrom(buffer);
237    return newFilter;
238  }
239
240  /**
241   * Tests identification of the stop row
242   */
243  @Test
244  public void testStop() throws Exception {
245    basicFilterTests((SingleColumnValueFilter) basicFilter);
246    nullFilterTests(nullFilter);
247    substrFilterTests(substrFilter);
248    regexFilterTests(regexFilter);
249    regexPatternFilterTests(regexPatternFilter);
250  }
251
252  /**
253   * Tests serialization
254   */
255  @Test
256  public void testSerialization() throws Exception {
257    Filter newFilter = serializationTest(basicFilter);
258    basicFilterTests((SingleColumnValueFilter) newFilter);
259    newFilter = serializationTest(nullFilter);
260    nullFilterTests(newFilter);
261    newFilter = serializationTest(substrFilter);
262    substrFilterTests(newFilter);
263    newFilter = serializationTest(regexFilter);
264    regexFilterTests(newFilter);
265    newFilter = serializationTest(regexPatternFilter);
266    regexPatternFilterTests(newFilter);
267  }
268
269}