View Javadoc

1   /*
2    * Copyright (c) 2011.  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.function;
22  
23  import org.apache.expreval.client.InternalErrorException;
24  import org.apache.expreval.client.NullColumnValueException;
25  import org.apache.expreval.client.ResultMissingColumnException;
26  import org.apache.expreval.expr.FunctionTypeSignature;
27  import org.apache.expreval.expr.GenericExpression;
28  import org.apache.expreval.expr.TypeSupport;
29  import org.apache.expreval.expr.node.BooleanValue;
30  import org.apache.expreval.expr.node.DateValue;
31  import org.apache.expreval.expr.node.DoubleValue;
32  import org.apache.expreval.expr.node.FloatValue;
33  import org.apache.expreval.expr.node.GenericValue;
34  import org.apache.expreval.expr.node.IntegerValue;
35  import org.apache.expreval.expr.node.LongValue;
36  import org.apache.expreval.expr.node.NumberValue;
37  import org.apache.expreval.expr.node.ShortValue;
38  import org.apache.expreval.expr.node.StringValue;
39  import org.apache.hadoop.hbase.hbql.client.HBqlException;
40  import org.apache.hadoop.hbase.hbql.impl.InvalidTypeException;
41  
42  import java.util.List;
43  import java.util.Random;
44  
45  public abstract class GenericFunction extends GenericExpression {
46  
47      final static Random randomVal = new Random();
48  
49      public static enum FunctionType {
50  
51          // Dealt with in DateFunction
52          DATEINTERVAL(new FunctionTypeSignature(DateValue.class, LongValue.class), false, true),
53          DATECONSTANT(new FunctionTypeSignature(DateValue.class), false, true),
54  
55          // Date functions
56          DATE(new FunctionTypeSignature(DateValue.class, StringValue.class, StringValue.class), false, true),
57          LONGTODATE(new FunctionTypeSignature(DateValue.class, LongValue.class), false, true),
58          RANDOMDATE(new FunctionTypeSignature(DateValue.class), false, true),
59  
60          // String functions
61          TRIM(new FunctionTypeSignature(StringValue.class, StringValue.class), false, true),
62          LOWER(new FunctionTypeSignature(StringValue.class, StringValue.class), false, true),
63          UPPER(new FunctionTypeSignature(StringValue.class, StringValue.class), false, true),
64          CONCAT(new FunctionTypeSignature(StringValue.class, StringValue.class, StringValue.class), false, true),
65          REPLACE(new FunctionTypeSignature(StringValue.class, StringValue.class, StringValue.class, StringValue.class), false, true),
66          SUBSTRING(new FunctionTypeSignature(StringValue.class, StringValue.class, IntegerValue.class, IntegerValue.class), false, true),
67          ZEROPAD(new FunctionTypeSignature(StringValue.class, LongValue.class, IntegerValue.class), false, true),
68          REPEAT(new FunctionTypeSignature(StringValue.class, StringValue.class, IntegerValue.class), false, true),
69  
70          // Number functions
71          LENGTH(new FunctionTypeSignature(IntegerValue.class, StringValue.class), false, true),
72          INDEXOF(new FunctionTypeSignature(IntegerValue.class, StringValue.class, StringValue.class), false, true),
73  
74          DATETOLONG(new FunctionTypeSignature(LongValue.class, DateValue.class), false, true),
75  
76          SHORT(new FunctionTypeSignature(ShortValue.class, StringValue.class), false, true),
77          INTEGER(new FunctionTypeSignature(IntegerValue.class, StringValue.class), false, true),
78          LONG(new FunctionTypeSignature(LongValue.class, StringValue.class), false, true),
79          FLOAT(new FunctionTypeSignature(FloatValue.class, StringValue.class), false, true),
80          DOUBLE(new FunctionTypeSignature(DoubleValue.class, StringValue.class), false, true),
81  
82          COUNT(new FunctionTypeSignature(LongValue.class), true, false),
83          MIN(new FunctionTypeSignature(NumberValue.class, NumberValue.class), true, false),
84          MAX(new FunctionTypeSignature(NumberValue.class, NumberValue.class), true, false),
85  
86          ABS(new FunctionTypeSignature(NumberValue.class, NumberValue.class), false, true),
87          LESSER(new FunctionTypeSignature(NumberValue.class, NumberValue.class, NumberValue.class), false, true),
88          GREATER(new FunctionTypeSignature(NumberValue.class, NumberValue.class, NumberValue.class), false, true),
89  
90          RANDOMINTEGER(new FunctionTypeSignature(IntegerValue.class), false, false),
91          RANDOMLONG(new FunctionTypeSignature(LongValue.class), false, false),
92          RANDOMFLOAT(new FunctionTypeSignature(FloatValue.class), false, false),
93          RANDOMDOUBLE(new FunctionTypeSignature(DoubleValue.class), false, false),
94  
95          // Boolean functions
96          RANDOMBOOLEAN(new FunctionTypeSignature(BooleanValue.class), false, false),
97          DEFINEDINROW(new FunctionTypeSignature(BooleanValue.class, GenericValue.class), false, false),
98          EVAL(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
99  
100         MAPPINGEXISTS(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
101         FAMILYEXISTSFORTABLE(new FunctionTypeSignature(BooleanValue.class, StringValue.class, StringValue.class), false, false),
102         FAMILYEXISTSFORMAPPING(new FunctionTypeSignature(BooleanValue.class, StringValue.class, StringValue.class), false, false),
103         TABLEEXISTS(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
104         TABLEENABLED(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
105         TABLEAVAILABLE(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
106         INDEXEXISTSFORTABLE(new FunctionTypeSignature(BooleanValue.class, StringValue.class, StringValue.class), false, false),
107         INDEXEXISTSFORMAPPING(new FunctionTypeSignature(BooleanValue.class, StringValue.class, StringValue.class), false, false),
108         ASYNCEXECUTOREXISTS(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false),
109         QUERYEXECUTORPOOLEXISTS(new FunctionTypeSignature(BooleanValue.class, StringValue.class), false, false);
110 
111         private final FunctionTypeSignature typeSignature;
112         private final boolean               anAggregateValue;
113         private final boolean               optimiziable;
114 
115         private FunctionType(final FunctionTypeSignature typeSignature,
116                              final boolean anAggregateValue,
117                              final boolean optimiziable) {
118             this.typeSignature = typeSignature;
119             this.anAggregateValue = anAggregateValue;
120             this.optimiziable = optimiziable;
121         }
122 
123         private FunctionTypeSignature getTypeSignature() {
124             return this.typeSignature;
125         }
126 
127         public boolean isAnAggregateValue() {
128             return this.anAggregateValue;
129         }
130 
131         public boolean isOptimiziable() {
132             return this.optimiziable;
133         }
134 
135         public static GenericFunction getFunction(final String functionName, final List<GenericValue> exprList) {
136 
137             final FunctionType type;
138 
139             try {
140                 type = FunctionType.valueOf(functionName.toUpperCase());
141             }
142             catch (IllegalArgumentException e) {
143                 return null;
144             }
145 
146             final Class<? extends GenericValue> returnType = type.getTypeSignature().getReturnType();
147 
148             if (TypeSupport.isParentClass(BooleanValue.class, returnType))
149                 return new BooleanFunction(type, exprList);
150             else if (TypeSupport.isParentClass(StringValue.class, returnType))
151                 return new StringFunction(type, exprList);
152             else if (TypeSupport.isParentClass(NumberValue.class, returnType))
153                 return new NumberFunction(type, exprList);
154             else if (TypeSupport.isParentClass(DateValue.class, returnType))
155                 return new DateFunction(type, exprList);
156             else
157                 return null;
158         }
159     }
160 
161     private final FunctionType functionType;
162 
163     public GenericFunction(final FunctionType functionType, final List<GenericValue> exprs) {
164         super(null, exprs);
165         this.functionType = functionType;
166     }
167 
168     protected FunctionType getFunctionType() {
169         return this.functionType;
170     }
171 
172     protected FunctionTypeSignature getTypeSignature() {
173         return this.getFunctionType().getTypeSignature();
174     }
175 
176     protected boolean isIntervalDate() {
177         return this.getFunctionType() == FunctionType.DATEINTERVAL;
178     }
179 
180     public boolean isAnAggregateValue() {
181         return this.getFunctionType().isAnAggregateValue();
182     }
183 
184     protected boolean isConstantDate() {
185         return this.getFunctionType() == FunctionType.DATECONSTANT;
186     }
187 
188     public boolean isAConstant() {
189         if (!this.getFunctionType().isOptimiziable())
190             return false;
191 
192         return super.isAConstant();
193     }
194 
195     public Class<? extends GenericValue> validateTypes(final GenericValue parentExpr,
196                                                        final boolean allowCollections) throws HBqlException {
197 
198         int i = 0;
199         if (this.getGenericValueList().size() != this.getTypeSignature().getArgCount())
200             throw new InvalidTypeException("Incorrect number of arguments in function " + this.getFunctionType().name()
201                                            + " in " + this.asString());
202 
203         for (final Class<? extends GenericValue> clazz : this.getTypeSignature().getArgTypeList()) {
204             final Class<? extends GenericValue> type = this.getExprArg(i).validateTypes(this, false);
205             try {
206                 this.validateParentClass(clazz, type);
207             }
208             catch (InvalidTypeException e) {
209                 // Catch the exception and improve message
210                 throw new InvalidTypeException("Invalid type " + type.getSimpleName() + " for arg " + i + " in function "
211                                                + this.getFunctionName() + " in "
212                                                + this.asString() + ".  Expecting type " + clazz.getSimpleName() + ".");
213             }
214             i++;
215         }
216 
217         return this.getTypeSignature().getReturnType();
218     }
219 
220     protected String getFunctionName() {
221         return this.getFunctionType().name();
222     }
223 
224     public GenericValue getOptimizedValue() throws HBqlException {
225         this.optimizeAllArgs();
226         if (!this.isAConstant())
227             return this;
228         else
229             try {
230                 return this.getFunctionType().getTypeSignature().newLiteral(this.getValue(null, null));
231             }
232             catch (ResultMissingColumnException e) {
233                 throw new InternalErrorException("Missing column: " + e.getMessage());
234             }
235             catch (NullColumnValueException e) {
236                 throw new InternalErrorException("Null value: " + e.getMessage());
237             }
238     }
239 
240     public String asString() {
241         return this.getFunctionName() + super.asString();
242     }
243 }