View Javadoc

1   /*
2    * Copyright (c) 2010.  The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.expreval.expr.betweenstmt;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.expreval.client.NullColumnValueException;
26  import org.apache.expreval.client.ResultMissingColumnException;
27  import org.apache.expreval.expr.ExpressionType;
28  import org.apache.expreval.expr.node.GenericValue;
29  import org.apache.expreval.expr.var.DelegateColumn;
30  import org.apache.expreval.expr.var.GenericColumn;
31  import org.apache.hadoop.hbase.filter.CompareFilter;
32  import org.apache.hadoop.hbase.filter.Filter;
33  import org.apache.hadoop.hbase.filter.WritableByteArrayComparable;
34  import org.apache.hadoop.hbase.hbql.client.HBqlException;
35  import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
36  import org.apache.hadoop.hbase.hbql.impl.Utils;
37  import org.apache.hadoop.hbase.hbql.io.IO;
38  import org.apache.hadoop.hbase.hbql.mapping.FieldType;
39  
40  import java.io.DataInput;
41  import java.io.DataOutput;
42  import java.io.IOException;
43  
44  public class NumberBetweenStmt extends GenericBetweenStmt {
45  
46      private static final Log LOG = LogFactory.getLog(NumberBetweenStmt.class);
47  
48      public NumberBetweenStmt(final GenericValue arg0,
49                               final boolean not,
50                               final GenericValue arg1,
51                               final GenericValue arg2) {
52          super(ExpressionType.NUMBERBETWEEN, not, arg0, arg1, arg2);
53      }
54  
55      public Boolean getValue(final HConnectionImpl conn, final Object object) throws HBqlException,
56                                                                                      ResultMissingColumnException,
57                                                                                      NullColumnValueException {
58          final Object obj0 = this.getExprArg(0).getValue(conn, object);
59          final Object obj1 = this.getExprArg(1).getValue(conn, object);
60          final Object obj2 = this.getExprArg(2).getValue(conn, object);
61  
62          this.validateNumericArgTypes(obj0, obj1, obj2);
63  
64          final boolean retval;
65  
66          if (!this.useDecimal()) {
67              final long val0 = ((Number)obj0).longValue();
68              final long val1 = ((Number)obj1).longValue();
69              final long val2 = ((Number)obj2).longValue();
70  
71              retval = val0 >= val1 && val0 <= val2;
72          }
73          else {
74              final double val0 = ((Number)obj0).doubleValue();
75              final double val1 = ((Number)obj1).doubleValue();
76              final double val2 = ((Number)obj2).doubleValue();
77  
78              retval = val0 >= val1 && val0 <= val2;
79          }
80  
81          return (this.isNot()) ? !retval : retval;
82      }
83  
84      public Filter getFilter() throws HBqlException {
85  
86          this.validateArgsForBetweenFilter();
87  
88          final GenericColumn<? extends GenericValue> column = ((DelegateColumn)this.getExprArg(0)).getTypedColumn();
89          final Object lowerConstant = this.getConstantValue(1);
90          final Object upperConstant = this.getConstantValue(2);
91          final WritableByteArrayComparable comparator;
92  
93          this.validateNumericArgTypes(lowerConstant, upperConstant);
94  
95          if (!this.useDecimal()) {
96              final long lowerVal = ((Number)lowerConstant).longValue();
97              final long upperVal = ((Number)upperConstant).longValue();
98              comparator = new LongBetweenComparable(column.getColumnAttrib().getFieldType(), lowerVal, upperVal);
99          }
100         else {
101             final double lowerVal = ((Number)lowerConstant).doubleValue();
102             final double upperVal = ((Number)upperConstant).doubleValue();
103             comparator = new DoubleBetweenComparable(column.getColumnAttrib().getFieldType(), lowerVal, upperVal);
104         }
105 
106         return this.newSingleColumnValueFilter(column.getColumnAttrib(), CompareFilter.CompareOp.EQUAL, comparator);
107     }
108 
109     private static abstract class NumberBetweenComparable<T> extends GenericBetweenComparable<T> {
110 
111         private FieldType fieldType;
112 
113         protected void setFieldType(final FieldType fieldType) {
114             this.fieldType = fieldType;
115         }
116 
117         protected FieldType getFieldType() {
118             return this.fieldType;
119         }
120     }
121 
122     private static class LongBetweenComparable extends NumberBetweenComparable<Long> {
123 
124         public LongBetweenComparable() {
125         }
126 
127         public LongBetweenComparable(final FieldType fieldType, final long lowerValue, final long upperValue) {
128             this.setFieldType(fieldType);
129             this.setLowerValue(lowerValue);
130             this.setUpperValue(upperValue);
131         }
132 
133         public int compareTo(final byte[] bytes) {
134 
135             try {
136                 long val = IO.getSerialization().getNumberFromBytes(this.getFieldType(), bytes).longValue();
137                 final double lowerVal = this.getLowerValue();
138                 final double upperVal = this.getUpperValue();
139                 return (val >= lowerVal && val <= upperVal) ? 0 : 1;
140             }
141             catch (HBqlException e) {
142                 e.printStackTrace();
143                 Utils.logException(LOG, e);
144                 return 1;
145             }
146         }
147 
148         public void write(final DataOutput dataOutput) throws IOException {
149             dataOutput.writeUTF(this.getFieldType().name());
150             dataOutput.writeLong(this.getLowerValue());
151             dataOutput.writeLong(this.getUpperValue());
152         }
153 
154         public void readFields(final DataInput dataInput) throws IOException {
155             this.setFieldType(FieldType.valueOf(dataInput.readUTF()));
156             this.setLowerValue(dataInput.readLong());
157             this.setUpperValue(dataInput.readLong());
158         }
159     }
160 
161     private static class DoubleBetweenComparable extends NumberBetweenComparable<Double> {
162 
163         public DoubleBetweenComparable() {
164         }
165 
166         public DoubleBetweenComparable(final FieldType fieldType, final double lowerValue, final double upperValue) {
167             this.setFieldType(fieldType);
168             this.setLowerValue(lowerValue);
169             this.setUpperValue(upperValue);
170         }
171 
172         public int compareTo(final byte[] bytes) {
173 
174             try {
175                 double val = IO.getSerialization().getNumberFromBytes(this.getFieldType(), bytes).doubleValue();
176                 final double lowerVal = this.getLowerValue();
177                 final double upperVal = this.getUpperValue();
178                 return (val >= lowerVal && val <= upperVal) ? 0 : 1;
179             }
180             catch (HBqlException e) {
181                 e.printStackTrace();
182                 Utils.logException(LOG, e);
183                 return 1;
184             }
185         }
186 
187         public void write(final DataOutput dataOutput) throws IOException {
188             dataOutput.writeUTF(this.getFieldType().name());
189             dataOutput.writeDouble(this.getLowerValue());
190             dataOutput.writeDouble(this.getUpperValue());
191         }
192 
193         public void readFields(final DataInput dataInput) throws IOException {
194             this.setFieldType(FieldType.valueOf(dataInput.readUTF()));
195             this.setLowerValue(dataInput.readDouble());
196             this.setUpperValue(dataInput.readDouble());
197         }
198     }
199 }