1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.expreval.expr;
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.literal.DoubleLiteral;
27 import org.apache.expreval.expr.literal.FloatLiteral;
28 import org.apache.expreval.expr.literal.IntegerLiteral;
29 import org.apache.expreval.expr.literal.LongLiteral;
30 import org.apache.expreval.expr.literal.ShortLiteral;
31 import org.apache.expreval.expr.node.BooleanValue;
32 import org.apache.expreval.expr.node.DateValue;
33 import org.apache.expreval.expr.node.GenericValue;
34 import org.apache.expreval.expr.node.NumberValue;
35 import org.apache.expreval.expr.node.ObjectValue;
36 import org.apache.expreval.expr.node.StringValue;
37 import org.apache.hadoop.hbase.client.Result;
38 import org.apache.hadoop.hbase.filter.CompareFilter;
39 import org.apache.hadoop.hbase.filter.Filter;
40 import org.apache.hadoop.hbase.filter.WritableByteArrayComparable;
41 import org.apache.hadoop.hbase.hbql.client.HBqlException;
42 import org.apache.hadoop.hbase.hbql.filter.SingleColumnValueFilter;
43 import org.apache.hadoop.hbase.hbql.impl.AggregateValue;
44 import org.apache.hadoop.hbase.hbql.impl.InvalidServerFilterException;
45 import org.apache.hadoop.hbase.hbql.impl.InvalidTypeException;
46 import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
47 import org.apache.hadoop.hbase.hbql.util.Lists;
48
49 import java.util.Arrays;
50 import java.util.List;
51 import java.util.concurrent.atomic.AtomicBoolean;
52
53 public abstract class GenericExpression implements GenericValue {
54
55
56 private Class<? extends GenericValue> highestRankingNumericArgFoundInValidate = NumberValue.class;
57 private Class rankingClass = null;
58 private boolean useDecimal = false;
59 private boolean useByte = false;
60 private boolean useShort = false;
61 private boolean useInteger = false;
62 private boolean useLong = false;
63 private boolean useFloat = false;
64 private boolean useDouble = false;
65
66 private final ExpressionType type;
67 private final List<GenericValue> genericValueList = Lists.newArrayList();
68 private final AtomicBoolean allArgsOptimized = new AtomicBoolean(false);
69
70 private MultipleExpressionContext expressionContext = null;
71
72 private Class getRankingClass() {
73 return this.rankingClass;
74 }
75
76 protected GenericExpression(final ExpressionType type, final GenericValue... exprs) {
77 this(type, Arrays.asList(exprs));
78 }
79
80 protected GenericExpression(final ExpressionType type, final List<GenericValue> genericValueList) {
81 this.type = type;
82 if (genericValueList != null)
83 this.getGenericValueList().addAll(genericValueList);
84 }
85
86 protected GenericExpression(final ExpressionType type,
87 final GenericValue expr,
88 final List<GenericValue> genericValueList) {
89 this.type = type;
90 this.getGenericValueList().add(expr);
91 if (genericValueList != null)
92 this.getGenericValueList().addAll(genericValueList);
93 }
94
95 protected FunctionTypeSignature getTypeSignature() {
96 return this.type.getTypeSignature();
97 }
98
99 public List<GenericValue> getGenericValueList() {
100 return this.genericValueList;
101 }
102
103 protected List<GenericValue> getSubArgs(final int i) {
104 return this.getGenericValueList().subList(i, this.getGenericValueList().size());
105 }
106
107 private Class<? extends GenericValue> getHighestRankingNumericArgFoundInValidate() {
108 return this.highestRankingNumericArgFoundInValidate;
109 }
110
111
112 protected boolean useDecimal() {
113 return this.useDecimal;
114 }
115
116 protected Number getValueWithCast(final long result) throws HBqlException {
117 if (this.useByte)
118 return (byte)result;
119 else if (this.useShort)
120 return (short)result;
121 else if (this.useInteger)
122 return (int)result;
123 else if (this.useLong)
124 return result;
125 else
126 throw new HBqlException("Invalid class: " + this.getRankingClass().getName());
127 }
128
129 protected Number getValueWithCast(final double result) throws HBqlException {
130 if (this.useFloat)
131 return (float)result;
132 else if (this.useDouble)
133 return result;
134 else
135 throw new HBqlException("Invalid class: " + this.getRankingClass().getName());
136 }
137
138 protected Class validateNumericArgTypes(final Object... objs) {
139
140 if (this.getRankingClass() == null) {
141
142
143 if (this.getHighestRankingNumericArgFoundInValidate() == NumberValue.class)
144 this.rankingClass = NumericType.getHighestRankingNumericArg(objs);
145 else
146 this.rankingClass = this.getHighestRankingNumericArgFoundInValidate();
147
148 this.useDecimal = NumericType.useDecimalNumericArgs(this.getRankingClass());
149
150 this.useByte = NumericType.isAByte(this.getRankingClass());
151 this.useShort = NumericType.isAShort(this.getRankingClass());
152 this.useInteger = NumericType.isAnInteger(this.getRankingClass());
153 this.useLong = NumericType.isALong(this.getRankingClass());
154 this.useFloat = NumericType.isAFloat(this.getRankingClass());
155 this.useDouble = NumericType.isADouble(this.getRankingClass());
156 }
157
158 return this.getRankingClass();
159 }
160
161 public boolean isAConstant() {
162
163 if (this.getGenericValueList().size() == 0)
164 return false;
165
166 for (final GenericValue val : this.getGenericValueList())
167 if (!val.isAConstant())
168 return false;
169
170 return true;
171 }
172
173 public boolean isDefaultKeyword() {
174 return false;
175 }
176
177 public boolean isAnAggregateValue() {
178 return false;
179 }
180
181 public void initAggregateValue(final AggregateValue aggregateValue) throws HBqlException {
182 throw new InternalErrorException("Not applicable");
183 }
184
185 public void applyResultToAggregateValue(final AggregateValue aggregateValue, final Result result) throws HBqlException, ResultMissingColumnException, NullColumnValueException {
186 throw new InternalErrorException("Not applicable");
187 }
188
189 public boolean hasAColumnReference() {
190 for (final GenericValue val : this.getGenericValueList())
191 if (val.hasAColumnReference())
192 return true;
193 return false;
194 }
195
196 public boolean isAColumnReference() {
197 return false;
198 }
199
200 public void reset() {
201 for (final GenericValue val : this.getGenericValueList())
202 val.reset();
203 }
204
205 public void setExpressionContext(final MultipleExpressionContext expressionContext) throws HBqlException {
206
207 this.expressionContext = expressionContext;
208
209 for (final GenericValue val : this.getGenericValueList())
210 val.setExpressionContext(expressionContext);
211 }
212
213 protected MultipleExpressionContext getExpressionContext() {
214 return this.expressionContext;
215 }
216
217 private AtomicBoolean getAllArgsOptimized() {
218 return this.allArgsOptimized;
219 }
220
221 protected void optimizeAllArgs() throws HBqlException {
222 if (!this.getAllArgsOptimized().get())
223 synchronized (this) {
224 if (!this.getAllArgsOptimized().get()) {
225 for (int i = 0; i < this.getGenericValueList().size(); i++)
226 this.setArg(i, this.getExprArg(i).getOptimizedValue());
227 this.getAllArgsOptimized().set(true);
228 }
229 }
230 }
231
232 protected Filter newSingleColumnValueFilter(final ColumnAttrib attrib,
233 final CompareFilter.CompareOp compareOp,
234 final WritableByteArrayComparable comparator) throws HBqlException {
235
236
237 if (attrib.isAKeyAttrib())
238 throw new InvalidServerFilterException("Cannot use a key attribute");
239
240 final SingleColumnValueFilter filter = new SingleColumnValueFilter(attrib.getFamilyNameAsBytes(),
241 attrib.getColumnNameAsBytes(),
242 compareOp,
243 comparator);
244 filter.setFilterIfMissing(true);
245 return filter;
246 }
247
248 protected Object getConstantValue(final int pos) throws HBqlException {
249 try {
250 return this.getExprArg(pos).getValue(null, null);
251 }
252 catch (ResultMissingColumnException e) {
253 throw new InternalErrorException("Missing column: " + e.getMessage());
254 }
255 catch (NullColumnValueException e) {
256 throw new InternalErrorException("Null value: " + e.getMessage());
257 }
258 }
259
260 public GenericValue getExprArg(final int i) {
261 return this.getGenericValueList().get(i);
262 }
263
264 public void setArg(final int i, final GenericValue val) {
265 this.getGenericValueList().set(i, val);
266 }
267
268 public Class<? extends GenericValue> validateTypes(final GenericValue parentExpr,
269 final boolean allowCollections) throws HBqlException {
270
271 if (this.getGenericValueList().size() != this.getTypeSignature().getArgCount())
272 throw new InvalidTypeException("Incorrect number of arguments in " + this.asString());
273
274 final FunctionTypeSignature typeSignature = this.getTypeSignature();
275
276 for (int i = 0; i < typeSignature.getArgCount(); i++)
277 this.validateParentClass(typeSignature.getArg(i), this.getExprArg(i).validateTypes(this, false));
278
279 return typeSignature.getReturnType();
280 }
281
282 protected Class<? extends GenericValue> validateNumericTypes() throws HBqlException {
283
284 if (this.getGenericValueList().size() != this.getTypeSignature().getArgCount())
285 throw new InvalidTypeException("Incorrect number of arguments in " + this.asString());
286
287
288 int highestRank = -1;
289 for (int i = 0; i < this.getTypeSignature().getArgCount(); i++) {
290
291 final Class<? extends GenericValue> clazz = this.getExprArg(i).validateTypes(this, false);
292 this.validateParentClass(this.getTypeSignature().getArg(i), clazz);
293
294 final int rank = NumericType.getTypeRanking(clazz);
295 if (rank > highestRank) {
296 highestRank = rank;
297 this.highestRankingNumericArgFoundInValidate = clazz;
298 }
299 }
300
301 return this.getHighestRankingNumericArgFoundInValidate();
302 }
303
304 public GenericValue getOptimizedValue() throws HBqlException {
305
306 this.optimizeAllArgs();
307
308 if (!this.isAConstant())
309 return this;
310
311 try {
312 final Object obj = this.getValue(null, null);
313
314 if (this.getTypeSignature().getReturnType() == BooleanValue.class
315 || this.getTypeSignature().getReturnType() == StringValue.class
316 || this.getTypeSignature().getReturnType() == DateValue.class)
317 return this.getTypeSignature().newLiteral(obj);
318
319 if (TypeSupport.isParentClass(NumberValue.class, this.getTypeSignature().getReturnType())) {
320
321 if (obj instanceof Short)
322 return new ShortLiteral((Short)obj);
323
324 if (obj instanceof Integer)
325 return new IntegerLiteral((Integer)obj);
326
327 if (obj instanceof Long)
328 return new LongLiteral((Long)obj);
329
330 if (obj instanceof Float)
331 return new FloatLiteral((Float)obj);
332
333 if (obj instanceof Double)
334 return new DoubleLiteral((Double)obj);
335 }
336 throw new InternalErrorException(this.getTypeSignature().getReturnType().getSimpleName());
337 }
338 catch (ResultMissingColumnException e) {
339 throw new InternalErrorException("Missing column: " + e.getMessage());
340 }
341 catch (NullColumnValueException e) {
342 throw new InternalErrorException("Null value: " + e.getMessage());
343 }
344 }
345
346 public String asString() {
347
348 final StringBuilder sbuf = new StringBuilder("(");
349
350 boolean first = true;
351 for (final GenericValue val : this.getGenericValueList()) {
352 if (!first)
353 sbuf.append(", ");
354 sbuf.append(val.asString());
355 first = false;
356 }
357
358 sbuf.append(")");
359
360 return sbuf.toString();
361 }
362
363 public void validateParentClass(final Class<? extends GenericValue> parentClass,
364 final Class<? extends GenericValue>... childrenClasses) throws InvalidTypeException {
365
366 final List<Class<? extends GenericValue>> classList = Lists.newArrayList();
367
368 for (final Class<? extends GenericValue> childClass : childrenClasses) {
369
370 if (childClass != null) {
371 if (TypeSupport.isParentClass(NumberValue.class, parentClass)) {
372 if (!TypeSupport.isParentClass(NumberValue.class, childClass)) {
373 classList.add(childClass);
374 }
375 else {
376 if (!NumericType.isAssignable(parentClass, childClass))
377 classList.add(childClass);
378 }
379 }
380 else {
381 if (!parentClass.isAssignableFrom(childClass))
382 classList.add(childClass);
383 }
384 }
385 }
386
387 if (classList.size() > 0) {
388 final StringBuilder sbuf = new StringBuilder("Expecting type " + parentClass.getSimpleName()
389 + " but encountered type"
390 + ((classList.size() > 1) ? "s" : "") + " ");
391 boolean first = true;
392 for (final Class clazz : classList) {
393 if (!first)
394 sbuf.append(", ");
395 sbuf.append(clazz.getSimpleName());
396 first = false;
397 }
398
399 sbuf.append(" in expression: " + this.asString());
400
401 throw new InvalidTypeException(sbuf.toString());
402 }
403 }
404
405 public void throwInvalidTypeException(final Class<? extends GenericValue>... clazzes) throws InvalidTypeException {
406
407 final List<Class> classList = Lists.newArrayList();
408
409 for (final Class clazz : clazzes)
410 if (clazz != null)
411 classList.add(clazz);
412
413 final StringBuilder sbuf = new StringBuilder("Invalid type");
414 sbuf.append(((classList.size() > 1) ? "s " : " "));
415
416 boolean first = true;
417 for (final Class<? extends GenericValue> clazz : clazzes) {
418 if (!first)
419 sbuf.append(", ");
420 sbuf.append(clazz.getSimpleName());
421 first = false;
422 }
423 sbuf.append(" in expression " + this.asString());
424
425 throw new InvalidTypeException(sbuf.toString());
426 }
427
428 final List<Class<? extends GenericValue>> types = Arrays.asList(StringValue.class,
429 NumberValue.class,
430 DateValue.class,
431 BooleanValue.class,
432 ObjectValue.class);
433
434 protected Class<? extends GenericValue> getGenericValueClass(final Class<? extends GenericValue> clazz) throws InvalidTypeException {
435
436 for (final Class<? extends GenericValue> type : types)
437 if (TypeSupport.isParentClass(type, clazz))
438 return type;
439
440 this.throwInvalidTypeException(clazz);
441
442 return null;
443 }
444
445 public Filter getFilter() throws HBqlException {
446 throw new InvalidServerFilterException();
447 }
448 }