Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java?rev=1159067&r1=1159066&r2=1159067&view=diff ============================================================================== --- hbase/trunk/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java (original) +++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java Thu Aug 18 07:31:24 2011 @@ -20,31 +20,40 @@ import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.thrift.*; +import org.apache.thrift.async.*; +import org.apache.thrift.meta_data.*; +import org.apache.thrift.transport.*; +import org.apache.thrift.protocol.*; + /** * A Scan object is used to specify scanner parameters when opening a scanner. */ -public class TScan implements org.apache.thrift.TBase<TScan, TScan._Fields>, java.io.Serializable, Cloneable { - private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TScan"); +public class TScan implements TBase<TScan, TScan._Fields>, java.io.Serializable, Cloneable { + private static final TStruct STRUCT_DESC = new TStruct("TScan"); - private static final org.apache.thrift.protocol.TField START_ROW_FIELD_DESC = new org.apache.thrift.protocol.TField("startRow", org.apache.thrift.protocol.TType.STRING, (short)1); - private static final org.apache.thrift.protocol.TField STOP_ROW_FIELD_DESC = new org.apache.thrift.protocol.TField("stopRow", org.apache.thrift.protocol.TType.STRING, (short)2); - private static final org.apache.thrift.protocol.TField TIMESTAMP_FIELD_DESC = new org.apache.thrift.protocol.TField("timestamp", org.apache.thrift.protocol.TType.I64, (short)3); - private static final org.apache.thrift.protocol.TField COLUMNS_FIELD_DESC = new org.apache.thrift.protocol.TField("columns", org.apache.thrift.protocol.TType.LIST, (short)4); - private static final org.apache.thrift.protocol.TField CACHING_FIELD_DESC = new org.apache.thrift.protocol.TField("caching", org.apache.thrift.protocol.TType.I32, (short)5); + private static final TField START_ROW_FIELD_DESC = new TField("startRow", TType.STRING, (short)1); + private static final TField STOP_ROW_FIELD_DESC = new TField("stopRow", TType.STRING, (short)2); + private static final TField TIMESTAMP_FIELD_DESC = new TField("timestamp", TType.I64, (short)3); + private static final TField COLUMNS_FIELD_DESC = new TField("columns", TType.LIST, (short)4); + private static final TField CACHING_FIELD_DESC = new TField("caching", TType.I32, (short)5); + private static final TField FILTER_STRING_FIELD_DESC = new TField("filterString", TType.STRING, (short)6); public ByteBuffer startRow; public ByteBuffer stopRow; public long timestamp; public List<ByteBuffer> columns; public int caching; + public ByteBuffer filterString; /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ - public enum _Fields implements org.apache.thrift.TFieldIdEnum { + public enum _Fields implements TFieldIdEnum { START_ROW((short)1, "startRow"), STOP_ROW((short)2, "stopRow"), TIMESTAMP((short)3, "timestamp"), COLUMNS((short)4, "columns"), - CACHING((short)5, "caching"); + CACHING((short)5, "caching"), + FILTER_STRING((short)6, "filterString"); private static final Map<String, _Fields> byName = new HashMap<String, _Fields>(); @@ -69,6 +78,8 @@ public class TScan implements org.apache return COLUMNS; case 5: // CACHING return CACHING; + case 6: // FILTER_STRING + return FILTER_STRING; default: return null; } @@ -113,22 +124,24 @@ public class TScan implements org.apache private static final int __CACHING_ISSET_ID = 1; private BitSet __isset_bit_vector = new BitSet(2); - public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + public static final Map<_Fields, FieldMetaData> metaDataMap; static { - Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); - tmpMap.put(_Fields.START_ROW, new org.apache.thrift.meta_data.FieldMetaData("startRow", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"))); - tmpMap.put(_Fields.STOP_ROW, new org.apache.thrift.meta_data.FieldMetaData("stopRow", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"))); - tmpMap.put(_Fields.TIMESTAMP, new org.apache.thrift.meta_data.FieldMetaData("timestamp", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); - tmpMap.put(_Fields.COLUMNS, new org.apache.thrift.meta_data.FieldMetaData("columns", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text")))); - tmpMap.put(_Fields.CACHING, new org.apache.thrift.meta_data.FieldMetaData("caching", org.apache.thrift.TFieldRequirementType.OPTIONAL, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); + Map<_Fields, FieldMetaData> tmpMap = new EnumMap<_Fields, FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.START_ROW, new FieldMetaData("startRow", TFieldRequirementType.OPTIONAL, + new FieldValueMetaData(TType.STRING , "Text"))); + tmpMap.put(_Fields.STOP_ROW, new FieldMetaData("stopRow", TFieldRequirementType.OPTIONAL, + new FieldValueMetaData(TType.STRING , "Text"))); + tmpMap.put(_Fields.TIMESTAMP, new FieldMetaData("timestamp", TFieldRequirementType.OPTIONAL, + new FieldValueMetaData(TType.I64))); + tmpMap.put(_Fields.COLUMNS, new FieldMetaData("columns", TFieldRequirementType.OPTIONAL, + new ListMetaData(TType.LIST, + new FieldValueMetaData(TType.STRING , "Text")))); + tmpMap.put(_Fields.CACHING, new FieldMetaData("caching", TFieldRequirementType.OPTIONAL, + new FieldValueMetaData(TType.I32))); + tmpMap.put(_Fields.FILTER_STRING, new FieldMetaData("filterString", TFieldRequirementType.OPTIONAL, + new FieldValueMetaData(TType.STRING , "Text"))); metaDataMap = Collections.unmodifiableMap(tmpMap); - org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TScan.class, metaDataMap); + FieldMetaData.addStructMetaDataMap(TScan.class, metaDataMap); } public TScan() { @@ -155,6 +168,9 @@ public class TScan implements org.apache this.columns = __this__columns; } this.caching = other.caching; + if (other.isSetFilterString()) { + this.filterString = other.filterString; + } } public TScan deepCopy() { @@ -170,19 +186,20 @@ public class TScan implements org.apache this.columns = null; setCachingIsSet(false); this.caching = 0; + this.filterString = null; } public byte[] getStartRow() { - setStartRow(org.apache.thrift.TBaseHelper.rightSize(startRow)); - return startRow == null ? null : startRow.array(); + setStartRow(TBaseHelper.rightSize(startRow)); + return startRow.array(); } - public ByteBuffer bufferForStartRow() { + public ByteBuffer BufferForStartRow() { return startRow; } public TScan setStartRow(byte[] startRow) { - setStartRow(startRow == null ? (ByteBuffer)null : ByteBuffer.wrap(startRow)); + setStartRow(ByteBuffer.wrap(startRow)); return this; } @@ -195,7 +212,7 @@ public class TScan implements org.apache this.startRow = null; } - /** Returns true if field startRow is set (has been assigned a value) and false otherwise */ + /** Returns true if field startRow is set (has been asigned a value) and false otherwise */ public boolean isSetStartRow() { return this.startRow != null; } @@ -207,16 +224,16 @@ public class TScan implements org.apache } public byte[] getStopRow() { - setStopRow(org.apache.thrift.TBaseHelper.rightSize(stopRow)); - return stopRow == null ? null : stopRow.array(); + setStopRow(TBaseHelper.rightSize(stopRow)); + return stopRow.array(); } - public ByteBuffer bufferForStopRow() { + public ByteBuffer BufferForStopRow() { return stopRow; } public TScan setStopRow(byte[] stopRow) { - setStopRow(stopRow == null ? (ByteBuffer)null : ByteBuffer.wrap(stopRow)); + setStopRow(ByteBuffer.wrap(stopRow)); return this; } @@ -229,7 +246,7 @@ public class TScan implements org.apache this.stopRow = null; } - /** Returns true if field stopRow is set (has been assigned a value) and false otherwise */ + /** Returns true if field stopRow is set (has been asigned a value) and false otherwise */ public boolean isSetStopRow() { return this.stopRow != null; } @@ -254,7 +271,7 @@ public class TScan implements org.apache __isset_bit_vector.clear(__TIMESTAMP_ISSET_ID); } - /** Returns true if field timestamp is set (has been assigned a value) and false otherwise */ + /** Returns true if field timestamp is set (has been asigned a value) and false otherwise */ public boolean isSetTimestamp() { return __isset_bit_vector.get(__TIMESTAMP_ISSET_ID); } @@ -291,7 +308,7 @@ public class TScan implements org.apache this.columns = null; } - /** Returns true if field columns is set (has been assigned a value) and false otherwise */ + /** Returns true if field columns is set (has been asigned a value) and false otherwise */ public boolean isSetColumns() { return this.columns != null; } @@ -316,7 +333,7 @@ public class TScan implements org.apache __isset_bit_vector.clear(__CACHING_ISSET_ID); } - /** Returns true if field caching is set (has been assigned a value) and false otherwise */ + /** Returns true if field caching is set (has been asigned a value) and false otherwise */ public boolean isSetCaching() { return __isset_bit_vector.get(__CACHING_ISSET_ID); } @@ -325,6 +342,40 @@ public class TScan implements org.apache __isset_bit_vector.set(__CACHING_ISSET_ID, value); } + public byte[] getFilterString() { + setFilterString(TBaseHelper.rightSize(filterString)); + return filterString.array(); + } + + public ByteBuffer BufferForFilterString() { + return filterString; + } + + public TScan setFilterString(byte[] filterString) { + setFilterString(ByteBuffer.wrap(filterString)); + return this; + } + + public TScan setFilterString(ByteBuffer filterString) { + this.filterString = filterString; + return this; + } + + public void unsetFilterString() { + this.filterString = null; + } + + /** Returns true if field filterString is set (has been asigned a value) and false otherwise */ + public boolean isSetFilterString() { + return this.filterString != null; + } + + public void setFilterStringIsSet(boolean value) { + if (!value) { + this.filterString = null; + } + } + public void setFieldValue(_Fields field, Object value) { switch (field) { case START_ROW: @@ -367,7 +418,15 @@ public class TScan implements org.apache } break; + case FILTER_STRING: + if (value == null) { + unsetFilterString(); + } else { + setFilterString((ByteBuffer)value); } + break; + + } } public Object getFieldValue(_Fields field) { @@ -387,11 +446,14 @@ public class TScan implements org.apache case CACHING: return new Integer(getCaching()); + case FILTER_STRING: + return getFilterString(); + } throw new IllegalStateException(); } - /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + /** Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise */ public boolean isSet(_Fields field) { if (field == null) { throw new IllegalArgumentException(); @@ -408,6 +470,8 @@ public class TScan implements org.apache return isSetColumns(); case CACHING: return isSetCaching(); + case FILTER_STRING: + return isSetFilterString(); } throw new IllegalStateException(); } @@ -470,6 +534,15 @@ public class TScan implements org.apache return false; } + boolean this_present_filterString = true && this.isSetFilterString(); + boolean that_present_filterString = true && that.isSetFilterString(); + if (this_present_filterString || that_present_filterString) { + if (!(this_present_filterString && that_present_filterString)) + return false; + if (!this.filterString.equals(that.filterString)) + return false; + } + return true; } @@ -491,7 +564,7 @@ public class TScan implements org.apache return lastComparison; } if (isSetStartRow()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.startRow, typedOther.startRow); + lastComparison = TBaseHelper.compareTo(this.startRow, typedOther.startRow); if (lastComparison != 0) { return lastComparison; } @@ -501,7 +574,7 @@ public class TScan implements org.apache return lastComparison; } if (isSetStopRow()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.stopRow, typedOther.stopRow); + lastComparison = TBaseHelper.compareTo(this.stopRow, typedOther.stopRow); if (lastComparison != 0) { return lastComparison; } @@ -511,7 +584,7 @@ public class TScan implements org.apache return lastComparison; } if (isSetTimestamp()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.timestamp, typedOther.timestamp); + lastComparison = TBaseHelper.compareTo(this.timestamp, typedOther.timestamp); if (lastComparison != 0) { return lastComparison; } @@ -521,7 +594,7 @@ public class TScan implements org.apache return lastComparison; } if (isSetColumns()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.columns, typedOther.columns); + lastComparison = TBaseHelper.compareTo(this.columns, typedOther.columns); if (lastComparison != 0) { return lastComparison; } @@ -531,7 +604,17 @@ public class TScan implements org.apache return lastComparison; } if (isSetCaching()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.caching, typedOther.caching); + lastComparison = TBaseHelper.compareTo(this.caching, typedOther.caching); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = Boolean.valueOf(isSetFilterString()).compareTo(typedOther.isSetFilterString()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetFilterString()) { + lastComparison = TBaseHelper.compareTo(this.filterString, typedOther.filterString); if (lastComparison != 0) { return lastComparison; } @@ -543,42 +626,42 @@ public class TScan implements org.apache return _Fields.findByThriftId(fieldId); } - public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TField field; + public void read(TProtocol iprot) throws TException { + TField field; iprot.readStructBegin(); while (true) { field = iprot.readFieldBegin(); - if (field.type == org.apache.thrift.protocol.TType.STOP) { + if (field.type == TType.STOP) { break; } switch (field.id) { case 1: // START_ROW - if (field.type == org.apache.thrift.protocol.TType.STRING) { + if (field.type == TType.STRING) { this.startRow = iprot.readBinary(); } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); } break; case 2: // STOP_ROW - if (field.type == org.apache.thrift.protocol.TType.STRING) { + if (field.type == TType.STRING) { this.stopRow = iprot.readBinary(); } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); } break; case 3: // TIMESTAMP - if (field.type == org.apache.thrift.protocol.TType.I64) { + if (field.type == TType.I64) { this.timestamp = iprot.readI64(); setTimestampIsSet(true); } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); } break; case 4: // COLUMNS - if (field.type == org.apache.thrift.protocol.TType.LIST) { + if (field.type == TType.LIST) { { - org.apache.thrift.protocol.TList _list9 = iprot.readListBegin(); + TList _list9 = iprot.readListBegin(); this.columns = new ArrayList<ByteBuffer>(_list9.size); for (int _i10 = 0; _i10 < _list9.size; ++_i10) { @@ -589,19 +672,26 @@ public class TScan implements org.apache iprot.readListEnd(); } } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); } break; case 5: // CACHING - if (field.type == org.apache.thrift.protocol.TType.I32) { + if (field.type == TType.I32) { this.caching = iprot.readI32(); setCachingIsSet(true); } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); + } + break; + case 6: // FILTER_STRING + if (field.type == TType.STRING) { + this.filterString = iprot.readBinary(); + } else { + TProtocolUtil.skip(iprot, field.type); } break; default: - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + TProtocolUtil.skip(iprot, field.type); } iprot.readFieldEnd(); } @@ -611,7 +701,7 @@ public class TScan implements org.apache validate(); } - public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + public void write(TProtocol oprot) throws TException { validate(); oprot.writeStructBegin(STRUCT_DESC); @@ -638,7 +728,7 @@ public class TScan implements org.apache if (isSetColumns()) { oprot.writeFieldBegin(COLUMNS_FIELD_DESC); { - oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, this.columns.size())); + oprot.writeListBegin(new TList(TType.STRING, this.columns.size())); for (ByteBuffer _iter12 : this.columns) { oprot.writeBinary(_iter12); @@ -653,6 +743,13 @@ public class TScan implements org.apache oprot.writeI32(this.caching); oprot.writeFieldEnd(); } + if (this.filterString != null) { + if (isSetFilterString()) { + oprot.writeFieldBegin(FILTER_STRING_FIELD_DESC); + oprot.writeBinary(this.filterString); + oprot.writeFieldEnd(); + } + } oprot.writeFieldStop(); oprot.writeStructEnd(); } @@ -703,31 +800,23 @@ public class TScan implements org.apache sb.append(this.caching); first = false; } + if (isSetFilterString()) { + if (!first) sb.append(", "); + sb.append("filterString:"); + if (this.filterString == null) { + sb.append("null"); + } else { + sb.append(this.filterString); + } + first = false; + } sb.append(")"); return sb.toString(); } - public void validate() throws org.apache.thrift.TException { + public void validate() throws TException { // check for required fields } - private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { - try { - write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); - } - } - - private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { - try { - // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. - __isset_bit_vector = new BitSet(1); - read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); } - } - -}
Modified: hbase/trunk/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift?rev=1159067&r1=1159066&r2=1159067&view=diff ============================================================================== --- hbase/trunk/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift (original) +++ hbase/trunk/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift Thu Aug 18 07:31:24 2011 @@ -124,7 +124,8 @@ struct TScan { 2:optional Text stopRow, 3:optional i64 timestamp, 4:optional list<Text> columns, - 5:optional i32 caching + 5:optional i32 caching, + 6:optional Text filterString } // Modified: hbase/trunk/src/main/ruby/hbase/table.rb URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/ruby/hbase/table.rb?rev=1159067&r1=1159066&r2=1159067&view=diff ============================================================================== --- hbase/trunk/src/main/ruby/hbase/table.rb (original) +++ hbase/trunk/src/main/ruby/hbase/table.rb Thu Aug 18 07:31:24 2011 @@ -236,7 +236,13 @@ module Hbase end columns.each { |c| scan.addColumns(c) } - scan.setFilter(filter) if filter + + unless filter.class == String + scan.setFilter(filter) + else + scan.setFilter(org.apache.hadoop.hbase.filter.ParseFilter.new.parseFilterString(filter)) + end + scan.setTimeStamp(timestamp) if timestamp scan.setCacheBlocks(cache) scan.setMaxVersions(versions) if versions > 1 Modified: hbase/trunk/src/main/ruby/shell/commands/scan.rb URL: http://svn.apache.org/viewvc/hbase/trunk/src/main/ruby/shell/commands/scan.rb?rev=1159067&r1=1159066&r2=1159067&view=diff ============================================================================== --- hbase/trunk/src/main/ruby/shell/commands/scan.rb (original) +++ hbase/trunk/src/main/ruby/shell/commands/scan.rb Thu Aug 18 07:31:24 2011 @@ -26,17 +26,25 @@ module Shell Scan a table; pass table name and optionally a dictionary of scanner specifications. Scanner specifications may include one or more of: TIMERANGE, FILTER, LIMIT, STARTROW, STOPROW, TIMESTAMP, MAXLENGTH, -or COLUMNS. If no columns are specified, all columns will be scanned. +or COLUMNS. + +If no columns are specified, all columns will be scanned. To scan all members of a column family, leave the qualifier empty as in 'col_family:'. +The filter can be specified in two ways: +1. Using a filterString - more information on this is available in the +Filter Language document attached to the HBASE-4176 JIRA +2. Using the entire package name of the filter. + Some examples: hbase> scan '.META.' hbase> scan '.META.', {COLUMNS => 'info:regioninfo'} hbase> scan 't1', {COLUMNS => ['c1', 'c2'], LIMIT => 10, STARTROW => 'xyz'} - hbase> scan 't1', {FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)} hbase> scan 't1', {COLUMNS => 'c1', TIMERANGE => [1303668804, 1303668904]} + hbase> scan 't1', {FILTER => "(PrefixFilter ('row2') AND (QualifierFilter (>=, 'binary:xyz'))) AND (TimestampsFilter ( 123, 456))"} + hbase> scan 't1', {FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)} For experts, there is an additional option -- CACHE_BLOCKS -- which switches block caching for the scanner on (true) or off (false). By Modified: hbase/trunk/src/test/java/org/apache/hadoop/hbase/filter/TestParseFilter.java URL: http://svn.apache.org/viewvc/hbase/trunk/src/test/java/org/apache/hadoop/hbase/filter/TestParseFilter.java?rev=1159067&r1=1159066&r2=1159067&view=diff ============================================================================== --- hbase/trunk/src/test/java/org/apache/hadoop/hbase/filter/TestParseFilter.java (original) +++ hbase/trunk/src/test/java/org/apache/hadoop/hbase/filter/TestParseFilter.java Thu Aug 18 07:31:24 2011 @@ -0,0 +1,663 @@ +/** + * Copyright 2011 The Apache Software Foundation + * + * 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.hadoop.hbase.filter; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.KeyValueTestUtil; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.InternalScanner; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * This class tests ParseFilter.java + * It tests the entire work flow from when a string is given by the user + * and how it is parsed to construct the corresponding Filter object + */ +public class TestParseFilter { + + ParseFilter f; + Filter filter; + + @Before + public void setUp() throws Exception { + f = new ParseFilter(); + } + + @After + public void tearDown() throws Exception { + // Nothing to do. + } + + @Test + public void testKeyOnlyFilter() throws IOException { + String filterString = "KeyOnlyFilter()"; + doTestFilter(filterString, KeyOnlyFilter.class); + + String filterString2 = "KeyOnlyFilter ('') "; + byte [] filterStringAsByteArray2 = Bytes.toBytes(filterString2); + try { + filter = f.parseFilterString(filterStringAsByteArray2); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testFirstKeyOnlyFilter() throws IOException { + String filterString = " FirstKeyOnlyFilter( ) "; + doTestFilter(filterString, FirstKeyOnlyFilter.class); + + String filterString2 = " FirstKeyOnlyFilter ('') "; + byte [] filterStringAsByteArray2 = Bytes.toBytes(filterString2); + try { + filter = f.parseFilterString(filterStringAsByteArray2); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testPrefixFilter() throws IOException { + String filterString = " PrefixFilter('row' ) "; + PrefixFilter prefixFilter = doTestFilter(filterString, PrefixFilter.class); + byte [] prefix = prefixFilter.getPrefix(); + assertEquals(new String(prefix), "row"); + + + filterString = " PrefixFilter(row)"; + try { + doTestFilter(filterString, PrefixFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testColumnPrefixFilter() throws IOException { + String filterString = " ColumnPrefixFilter('qualifier' ) "; + ColumnPrefixFilter columnPrefixFilter = + doTestFilter(filterString, ColumnPrefixFilter.class); + byte [] columnPrefix = columnPrefixFilter.getPrefix(); + assertEquals(new String(columnPrefix), "qualifier"); + } + + @Test + public void testMultipleColumnPrefixFilter() throws IOException { + String filterString = " MultipleColumnPrefixFilter('qualifier1', 'qualifier2' ) "; + MultipleColumnPrefixFilter multipleColumnPrefixFilter = + doTestFilter(filterString, MultipleColumnPrefixFilter.class); + byte [][] prefixes = multipleColumnPrefixFilter.getPrefix(); + assertEquals(new String(prefixes[0]), "qualifier1"); + assertEquals(new String(prefixes[1]), "qualifier2"); + } + + @Test + public void testColumnCountGetFilter() throws IOException { + String filterString = " ColumnCountGetFilter(4)"; + ColumnCountGetFilter columnCountGetFilter = + doTestFilter(filterString, ColumnCountGetFilter.class); + int limit = columnCountGetFilter.getLimit(); + assertEquals(limit, 4); + + filterString = " ColumnCountGetFilter('abc')"; + try { + doTestFilter(filterString, ColumnCountGetFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + + filterString = " ColumnCountGetFilter(2147483648)"; + try { + doTestFilter(filterString, ColumnCountGetFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testPageFilter() throws IOException { + String filterString = " PageFilter(4)"; + PageFilter pageFilter = + doTestFilter(filterString, PageFilter.class); + long pageSize = pageFilter.getPageSize(); + assertEquals(pageSize, 4); + + filterString = " PageFilter('123')"; + try { + doTestFilter(filterString, PageFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("PageFilter needs an int as an argument"); + } + } + + @Test + public void testColumnPaginationFilter() throws IOException { + String filterString = "ColumnPaginationFilter(4, 6)"; + ColumnPaginationFilter columnPaginationFilter = + doTestFilter(filterString, ColumnPaginationFilter.class); + int limit = columnPaginationFilter.getLimit(); + assertEquals(limit, 4); + int offset = columnPaginationFilter.getOffset(); + assertEquals(offset, 6); + + filterString = " ColumnPaginationFilter('124')"; + try { + doTestFilter(filterString, ColumnPaginationFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("ColumnPaginationFilter needs two arguments"); + } + + filterString = " ColumnPaginationFilter('4' , '123a')"; + try { + doTestFilter(filterString, ColumnPaginationFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("ColumnPaginationFilter needs two ints as arguments"); + } + + filterString = " ColumnPaginationFilter('4' , '-123')"; + try { + doTestFilter(filterString, ColumnPaginationFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("ColumnPaginationFilter arguments should not be negative"); + } + } + + @Test + public void testInclusiveStopFilter() throws IOException { + String filterString = "InclusiveStopFilter ('row 3')"; + InclusiveStopFilter inclusiveStopFilter = + doTestFilter(filterString, InclusiveStopFilter.class); + byte [] stopRowKey = inclusiveStopFilter.getStopRowKey(); + assertEquals(new String(stopRowKey), "row 3"); + } + + + @Test + public void testTimestampsFilter() throws IOException { + String filterString = "TimestampsFilter(9223372036854775806, 6)"; + TimestampsFilter timestampsFilter = + doTestFilter(filterString, TimestampsFilter.class); + List<Long> timestamps = timestampsFilter.getTimestamps(); + assertEquals(timestamps.size(), 2); + assertEquals(timestamps.get(0), new Long(6)); + + filterString = "TimestampsFilter()"; + timestampsFilter = doTestFilter(filterString, TimestampsFilter.class); + timestamps = timestampsFilter.getTimestamps(); + assertEquals(timestamps.size(), 0); + + filterString = "TimestampsFilter(9223372036854775808, 6)"; + try { + doTestFilter(filterString, ColumnPaginationFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("Long Argument was too large"); + } + + filterString = "TimestampsFilter(-45, 6)"; + try { + doTestFilter(filterString, ColumnPaginationFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("Timestamp Arguments should not be negative"); + } + } + + @Test + public void testRowFilter() throws IOException { + String filterString = "RowFilter ( =, 'binary:regionse')"; + RowFilter rowFilter = + doTestFilter(filterString, RowFilter.class); + assertEquals(CompareFilter.CompareOp.EQUAL, rowFilter.getOperator()); + assertTrue(rowFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator) rowFilter.getComparator(); + assertEquals("regionse", new String(binaryComparator.getValue())); + } + + @Test + public void testFamilyFilter() throws IOException { + String filterString = "FamilyFilter(>=, 'binaryprefix:pre')"; + FamilyFilter familyFilter = + doTestFilter(filterString, FamilyFilter.class); + assertEquals(CompareFilter.CompareOp.GREATER_OR_EQUAL, familyFilter.getOperator()); + assertTrue(familyFilter.getComparator() instanceof BinaryPrefixComparator); + BinaryPrefixComparator binaryPrefixComparator = + (BinaryPrefixComparator) familyFilter.getComparator(); + assertEquals("pre", new String(binaryPrefixComparator.getValue())); + } + + @Test + public void testQualifierFilter() throws IOException { + String filterString = "QualifierFilter(=, 'regexstring:pre*')"; + QualifierFilter qualifierFilter = + doTestFilter(filterString, QualifierFilter.class); + assertEquals(CompareFilter.CompareOp.EQUAL, qualifierFilter.getOperator()); + assertTrue(qualifierFilter.getComparator() instanceof RegexStringComparator); + RegexStringComparator regexStringComparator = + (RegexStringComparator) qualifierFilter.getComparator(); + assertEquals("pre*", new String(regexStringComparator.getValue())); + } + + @Test + public void testValueFilter() throws IOException { + String filterString = "ValueFilter(!=, 'substring:pre')"; + ValueFilter valueFilter = + doTestFilter(filterString, ValueFilter.class); + assertEquals(CompareFilter.CompareOp.NOT_EQUAL, valueFilter.getOperator()); + assertTrue(valueFilter.getComparator() instanceof SubstringComparator); + SubstringComparator substringComparator = + (SubstringComparator) valueFilter.getComparator(); + assertEquals("pre", new String(substringComparator.getValue())); + } + + @Test + public void testColumnRangeFilter() throws IOException { + String filterString = "ColumnRangeFilter('abc', true, 'xyz', false)"; + ColumnRangeFilter columnRangeFilter = + doTestFilter(filterString, ColumnRangeFilter.class); + assertEquals("abc", new String(columnRangeFilter.getMinColumn())); + assertEquals("xyz", new String(columnRangeFilter.getMaxColumn())); + assertTrue(columnRangeFilter.isMinColumnInclusive()); + assertFalse(columnRangeFilter.isMaxColumnInclusive()); + } + + @Test + public void testDependentColumnFilter() throws IOException { + String filterString = "DependentColumnFilter('family', 'qualifier', true, =, 'binary:abc')"; + DependentColumnFilter dependentColumnFilter = + doTestFilter(filterString, DependentColumnFilter.class); + assertEquals("family", new String(dependentColumnFilter.getFamily())); + assertEquals("qualifier", new String(dependentColumnFilter.getQualifier())); + assertTrue(dependentColumnFilter.getDropDependentColumn()); + assertEquals(CompareFilter.CompareOp.EQUAL, dependentColumnFilter.getOperator()); + assertTrue(dependentColumnFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator)dependentColumnFilter.getComparator(); + assertEquals("abc", new String(binaryComparator.getValue())); + } + + @Test + public void testSingleColumnValueFilter() throws IOException { + String filterString = "SingleColumnValueFilter " + + "('family', 'qualifier', >=, 'binary:a', true, false)"; + SingleColumnValueFilter singleColumnValueFilter = + doTestFilter(filterString, SingleColumnValueFilter.class); + assertEquals("family", new String(singleColumnValueFilter.getFamily())); + assertEquals("qualifier", new String(singleColumnValueFilter.getQualifier())); + assertEquals(singleColumnValueFilter.getOperator(), CompareFilter.CompareOp.GREATER_OR_EQUAL); + assertTrue(singleColumnValueFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator) singleColumnValueFilter.getComparator(); + assertEquals(new String(binaryComparator.getValue()), "a"); + assertTrue(singleColumnValueFilter.getFilterIfMissing()); + assertFalse(singleColumnValueFilter.getLatestVersionOnly()); + + + filterString = "SingleColumnValueFilter ('family', 'qualifier', >, 'binaryprefix:a')"; + singleColumnValueFilter = doTestFilter(filterString, SingleColumnValueFilter.class); + assertEquals("family", new String(singleColumnValueFilter.getFamily())); + assertEquals("qualifier", new String(singleColumnValueFilter.getQualifier())); + assertEquals(singleColumnValueFilter.getOperator(), CompareFilter.CompareOp.GREATER); + assertTrue(singleColumnValueFilter.getComparator() instanceof BinaryPrefixComparator); + BinaryPrefixComparator binaryPrefixComparator = + (BinaryPrefixComparator) singleColumnValueFilter.getComparator(); + assertEquals(new String(binaryPrefixComparator.getValue()), "a"); + assertFalse(singleColumnValueFilter.getFilterIfMissing()); + assertTrue(singleColumnValueFilter.getLatestVersionOnly()); + } + + @Test + public void testSingleColumnValueExcludeFilter() throws IOException { + String filterString = + "SingleColumnValueExcludeFilter ('family', 'qualifier', <, 'binaryprefix:a')"; + SingleColumnValueExcludeFilter singleColumnValueExcludeFilter = + doTestFilter(filterString, SingleColumnValueExcludeFilter.class); + assertEquals(singleColumnValueExcludeFilter.getOperator(), CompareFilter.CompareOp.LESS); + assertEquals("family", new String(singleColumnValueExcludeFilter.getFamily())); + assertEquals("qualifier", new String(singleColumnValueExcludeFilter.getQualifier())); + assertEquals(new String(singleColumnValueExcludeFilter.getComparator().getValue()), "a"); + assertFalse(singleColumnValueExcludeFilter.getFilterIfMissing()); + assertTrue(singleColumnValueExcludeFilter.getLatestVersionOnly()); + + filterString = "SingleColumnValueExcludeFilter " + + "('family', 'qualifier', <=, 'binaryprefix:a', true, false)"; + singleColumnValueExcludeFilter = + doTestFilter(filterString, SingleColumnValueExcludeFilter.class); + assertEquals("family", new String(singleColumnValueExcludeFilter.getFamily())); + assertEquals("qualifier", new String(singleColumnValueExcludeFilter.getQualifier())); + assertEquals(singleColumnValueExcludeFilter.getOperator(), + CompareFilter.CompareOp.LESS_OR_EQUAL); + assertTrue(singleColumnValueExcludeFilter.getComparator() instanceof BinaryPrefixComparator); + BinaryPrefixComparator binaryPrefixComparator = + (BinaryPrefixComparator) singleColumnValueExcludeFilter.getComparator(); + assertEquals(new String(binaryPrefixComparator.getValue()), "a"); + assertTrue(singleColumnValueExcludeFilter.getFilterIfMissing()); + assertFalse(singleColumnValueExcludeFilter.getLatestVersionOnly()); + } + + @Test + public void testSkipFilter() throws IOException { + String filterString = "SKIP ValueFilter( =, 'binary:0')"; + SkipFilter skipFilter = + doTestFilter(filterString, SkipFilter.class); + assertTrue(skipFilter.getFilter() instanceof ValueFilter); + ValueFilter valueFilter = (ValueFilter) skipFilter.getFilter(); + + assertEquals(CompareFilter.CompareOp.EQUAL, valueFilter.getOperator()); + assertTrue(valueFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator) valueFilter.getComparator(); + assertEquals("0", new String(binaryComparator.getValue())); + } + + @Test + public void testWhileFilter() throws IOException { + String filterString = " WHILE RowFilter ( !=, 'binary:row1')"; + WhileMatchFilter whileMatchFilter = + doTestFilter(filterString, WhileMatchFilter.class); + assertTrue(whileMatchFilter.getFilter() instanceof RowFilter); + RowFilter rowFilter = (RowFilter) whileMatchFilter.getFilter(); + + assertEquals(CompareFilter.CompareOp.NOT_EQUAL, rowFilter.getOperator()); + assertTrue(rowFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator) rowFilter.getComparator(); + assertEquals("row1", new String(binaryComparator.getValue())); + } + + @Test + public void testCompoundFilter1() throws IOException { + String filterString = " (PrefixFilter ('realtime')AND FirstKeyOnlyFilter())"; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof PrefixFilter); + assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter); + PrefixFilter PrefixFilter = (PrefixFilter) filters.get(0); + byte [] prefix = PrefixFilter.getPrefix(); + assertEquals(new String(prefix), "realtime"); + FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1); + } + + @Test + public void testCompoundFilter2() throws IOException { + String filterString = "(PrefixFilter('realtime') AND QualifierFilter (>=, 'binary:e'))" + + "OR FamilyFilter (=, 'binary:qualifier') "; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + ArrayList<Filter> filterListFilters = (ArrayList<Filter>) filterList.getFilters(); + assertTrue(filterListFilters.get(0) instanceof FilterList); + assertTrue(filterListFilters.get(1) instanceof FamilyFilter); + assertEquals(filterList.getOperator(), FilterList.Operator.MUST_PASS_ONE); + + filterList = (FilterList) filterListFilters.get(0); + FamilyFilter familyFilter = (FamilyFilter) filterListFilters.get(1); + + filterListFilters = (ArrayList<Filter>)filterList.getFilters(); + assertTrue(filterListFilters.get(0) instanceof PrefixFilter); + assertTrue(filterListFilters.get(1) instanceof QualifierFilter); + assertEquals(filterList.getOperator(), FilterList.Operator.MUST_PASS_ALL); + + assertEquals(CompareFilter.CompareOp.EQUAL, familyFilter.getOperator()); + assertTrue(familyFilter.getComparator() instanceof BinaryComparator); + BinaryComparator binaryComparator = (BinaryComparator) familyFilter.getComparator(); + assertEquals("qualifier", new String(binaryComparator.getValue())); + + PrefixFilter prefixFilter = (PrefixFilter) filterListFilters.get(0); + byte [] prefix = prefixFilter.getPrefix(); + assertEquals(new String(prefix), "realtime"); + + QualifierFilter qualifierFilter = (QualifierFilter) filterListFilters.get(1); + assertEquals(CompareFilter.CompareOp.GREATER_OR_EQUAL, qualifierFilter.getOperator()); + assertTrue(qualifierFilter.getComparator() instanceof BinaryComparator); + binaryComparator = (BinaryComparator) qualifierFilter.getComparator(); + assertEquals("e", new String(binaryComparator.getValue())); + } + + @Test + public void testCompoundFilter3() throws IOException { + String filterString = " ColumnPrefixFilter ('realtime')AND " + + "FirstKeyOnlyFilter() OR SKIP FamilyFilter(=, 'substring:hihi')"; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof FilterList); + assertTrue(filters.get(1) instanceof SkipFilter); + + filterList = (FilterList) filters.get(0); + SkipFilter skipFilter = (SkipFilter) filters.get(1); + + filters = (ArrayList<Filter>) filterList.getFilters(); + assertTrue(filters.get(0) instanceof ColumnPrefixFilter); + assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter); + + ColumnPrefixFilter columnPrefixFilter = (ColumnPrefixFilter) filters.get(0); + byte [] columnPrefix = columnPrefixFilter.getPrefix(); + assertEquals(new String(columnPrefix), "realtime"); + + FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1); + + assertTrue(skipFilter.getFilter() instanceof FamilyFilter); + FamilyFilter familyFilter = (FamilyFilter) skipFilter.getFilter(); + + assertEquals(CompareFilter.CompareOp.EQUAL, familyFilter.getOperator()); + assertTrue(familyFilter.getComparator() instanceof SubstringComparator); + SubstringComparator substringComparator = + (SubstringComparator) familyFilter.getComparator(); + assertEquals("hihi", new String(substringComparator.getValue())); + } + + @Test + public void testCompoundFilter4() throws IOException { + String filterString = " ColumnPrefixFilter ('realtime') OR " + + "FirstKeyOnlyFilter() OR SKIP FamilyFilter(=, 'substring:hihi')"; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof ColumnPrefixFilter); + assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter); + assertTrue(filters.get(2) instanceof SkipFilter); + + ColumnPrefixFilter columnPrefixFilter = (ColumnPrefixFilter) filters.get(0); + FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1); + SkipFilter skipFilter = (SkipFilter) filters.get(2); + + byte [] columnPrefix = columnPrefixFilter.getPrefix(); + assertEquals(new String(columnPrefix), "realtime"); + + assertTrue(skipFilter.getFilter() instanceof FamilyFilter); + FamilyFilter familyFilter = (FamilyFilter) skipFilter.getFilter(); + + assertEquals(CompareFilter.CompareOp.EQUAL, familyFilter.getOperator()); + assertTrue(familyFilter.getComparator() instanceof SubstringComparator); + SubstringComparator substringComparator = + (SubstringComparator) familyFilter.getComparator(); + assertEquals("hihi", new String(substringComparator.getValue())); + } + + @Test + public void testIncorrectCompareOperator() throws IOException { + String filterString = "RowFilter ('>>' , 'binary:region')"; + try { + doTestFilter(filterString, RowFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("Incorrect compare operator >>"); + } + } + + @Test + public void testIncorrectComparatorType () throws IOException { + String filterString = "RowFilter ('>=' , 'binaryoperator:region')"; + try { + doTestFilter(filterString, RowFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("Incorrect comparator type: binaryoperator"); + } + + filterString = "RowFilter ('>=' 'regexstring:pre*')"; + try { + doTestFilter(filterString, RowFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("RegexStringComparator can only be used with EQUAL or NOT_EQUAL"); + } + + filterString = "SingleColumnValueFilter" + + " ('family', 'qualifier', '>=', 'substring:a', 'true', 'false')')"; + try { + doTestFilter(filterString, RowFilter.class); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println("SubtringComparator can only be used with EQUAL or NOT_EQUAL"); + } + } + + @Test + public void testPrecedence1() throws IOException { + String filterString = " (PrefixFilter ('realtime')AND FirstKeyOnlyFilter()" + + " OR KeyOnlyFilter())"; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + + ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof FilterList); + assertTrue(filters.get(1) instanceof KeyOnlyFilter); + + filterList = (FilterList) filters.get(0); + filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof PrefixFilter); + assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter); + + PrefixFilter prefixFilter = (PrefixFilter)filters.get(0); + byte [] prefix = prefixFilter.getPrefix(); + assertEquals(new String(prefix), "realtime"); + } + + @Test + public void testPrecedence2() throws IOException { + String filterString = " PrefixFilter ('realtime')AND SKIP FirstKeyOnlyFilter()" + + "OR KeyOnlyFilter()"; + FilterList filterList = + doTestFilter(filterString, FilterList.class); + ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof FilterList); + assertTrue(filters.get(1) instanceof KeyOnlyFilter); + + filterList = (FilterList) filters.get(0); + filters = (ArrayList<Filter>) filterList.getFilters(); + + assertTrue(filters.get(0) instanceof PrefixFilter); + assertTrue(filters.get(1) instanceof SkipFilter); + + PrefixFilter prefixFilter = (PrefixFilter)filters.get(0); + byte [] prefix = prefixFilter.getPrefix(); + assertEquals(new String(prefix), "realtime"); + + SkipFilter skipFilter = (SkipFilter)filters.get(1); + assertTrue(skipFilter.getFilter() instanceof FirstKeyOnlyFilter); + } + + @Test + public void testUnescapedQuote1 () throws IOException { + String filterString = "InclusiveStopFilter ('row''3')"; + InclusiveStopFilter inclusiveStopFilter = + doTestFilter(filterString, InclusiveStopFilter.class); + byte [] stopRowKey = inclusiveStopFilter.getStopRowKey(); + assertEquals(new String(stopRowKey), "row'3"); + } + + @Test + public void testUnescapedQuote2 () throws IOException { + String filterString = "InclusiveStopFilter ('row''3''')"; + InclusiveStopFilter inclusiveStopFilter = + doTestFilter(filterString, InclusiveStopFilter.class); + byte [] stopRowKey = inclusiveStopFilter.getStopRowKey(); + assertEquals(new String(stopRowKey), "row'3'"); + } + + @Test + public void testUnescapedQuote3 () throws IOException { + String filterString = " InclusiveStopFilter ('''')"; + InclusiveStopFilter inclusiveStopFilter = + doTestFilter(filterString, InclusiveStopFilter.class); + byte [] stopRowKey = inclusiveStopFilter.getStopRowKey(); + assertEquals(new String(stopRowKey), "'"); + } + + @Test + public void testIncorrectFilterString () throws IOException { + String filterString = "()"; + byte [] filterStringAsByteArray = Bytes.toBytes(filterString); + try { + filter = f.parseFilterString(filterStringAsByteArray); + assertTrue(false); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testCorrectFilterString () throws IOException { + String filterString = "(FirstKeyOnlyFilter())"; + FirstKeyOnlyFilter firstKeyOnlyFilter = + doTestFilter(filterString, FirstKeyOnlyFilter.class); + } + + private <T extends Filter> T doTestFilter(String filterString, Class<T> clazz) throws IOException { + byte [] filterStringAsByteArray = Bytes.toBytes(filterString); + filter = f.parseFilterString(filterStringAsByteArray); + assertEquals(clazz, filter.getClass()); + return clazz.cast(filter); + } +}
