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.node.GenericValue;
27 import org.apache.expreval.expr.node.NumberValue;
28 import org.apache.expreval.expr.node.ObjectValue;
29 import org.apache.expreval.expr.var.GenericColumn;
30 import org.apache.expreval.expr.var.NamedParameter;
31 import org.apache.hadoop.hbase.hbql.client.HBqlException;
32 import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
33 import org.apache.hadoop.hbase.hbql.impl.InvalidTypeException;
34 import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
35 import org.apache.hadoop.hbase.hbql.mapping.HRecordResultAccessor;
36 import org.apache.hadoop.hbase.hbql.mapping.Mapping;
37 import org.apache.hadoop.hbase.hbql.mapping.MappingContext;
38 import org.apache.hadoop.hbase.hbql.mapping.ResultAccessor;
39 import org.apache.hadoop.hbase.hbql.mapping.TableMapping;
40 import org.apache.hadoop.hbase.hbql.util.Lists;
41 import org.apache.hadoop.hbase.hbql.util.Maps;
42
43 import java.io.Serializable;
44 import java.util.List;
45 import java.util.Map;
46
47 public abstract class MultipleExpressionContext implements Serializable {
48
49 private static final long serialVersionUID = 1L;
50
51 private boolean needsTypeValidation = true;
52 private boolean needsOptimization = true;
53 private boolean needsContextSetting = true;
54
55 private final List<GenericValue> expressions = Lists.newArrayList();
56 private final List<GenericColumn> columnsUsedInExprs = Lists.newArrayList();
57 private final List<ColumnAttrib> attribsUsedInExprs = Lists.newArrayList();
58 private final List<NamedParameter> namedParamList = Lists.newArrayList();
59 private final Map<String, List<NamedParameter>> namedParamMap = Maps.newHashMap();
60
61 private MappingContext mappingContext = null;
62 private TypeSignature typeSignature = null;
63
64 protected MultipleExpressionContext() {
65 }
66
67 protected MultipleExpressionContext(final TypeSignature typeSignature, final GenericValue... vals) {
68 this.typeSignature = typeSignature;
69 if (vals != null) {
70 for (final GenericValue val : vals)
71 this.addExpression(val);
72 }
73 }
74
75 public abstract String asString();
76
77 public abstract boolean useResultData();
78
79 public abstract boolean allowColumns();
80
81 public List<GenericColumn> getColumnsUsedInExpr() {
82 return this.columnsUsedInExprs;
83 }
84
85 public List<ColumnAttrib> getAttribsUsedInExpr() {
86 return this.attribsUsedInExprs;
87 }
88
89 public void addExpression(final GenericValue genericValue) {
90 this.getExpressionList().add(genericValue);
91 }
92
93 public Map<String, List<NamedParameter>> getNamedParamMap() {
94 return this.namedParamMap;
95 }
96
97 protected List<GenericValue> getExpressionList() {
98 return this.expressions;
99 }
100
101 private TypeSignature getTypeSignature() {
102 return this.typeSignature;
103 }
104
105 public MappingContext getMappingContext() {
106 return this.mappingContext;
107 }
108
109 public Mapping getMapping() throws HBqlException {
110 return this.getMappingContext().getMapping();
111 }
112
113 public TableMapping getTableMapping() {
114 return this.getMappingContext().getTableMapping();
115 }
116
117 public ResultAccessor getResultAccessor() throws HBqlException {
118 return this.getMappingContext().getResultAccessor();
119 }
120
121 public void setMappingContext(final MappingContext mappingContext) throws HBqlException {
122 this.mappingContext = mappingContext;
123
124 if (this.getMappingContext() != null && this.getMappingContext().getResultAccessor() == null)
125 this.getMappingContext().setResultAccessor(new HRecordResultAccessor(mappingContext));
126
127 this.setExpressionListContext();
128 }
129
130 private synchronized void setExpressionListContext() throws HBqlException {
131 if (this.needsContextSetting()) {
132 for (final GenericValue val : this.getExpressionList())
133 val.setExpressionContext(this);
134 this.setNeedsContextSetting(false);
135 }
136 }
137
138 protected GenericValue getGenericValue(final int i) {
139 return this.getExpressionList().get(i);
140 }
141
142 public Object evaluate(final HConnectionImpl conn,
143 final int i,
144 final boolean allowColumns,
145 final boolean allowCollections,
146 final Object object) throws HBqlException, ResultMissingColumnException, NullColumnValueException {
147 this.validateTypes(allowColumns, allowCollections);
148 this.optimize();
149 final GenericValue genericValue = this.getGenericValue(i);
150 return genericValue.getValue(conn, object);
151 }
152
153 public Object evaluateConstant(final int i, final boolean allowCollections) throws HBqlException {
154 try {
155 return this.evaluate(null, i, false, allowCollections, null);
156 }
157 catch (ResultMissingColumnException e) {
158 throw new InternalErrorException("Missing column: " + e.getMessage());
159 }
160 catch (NullColumnValueException e) {
161 throw new InternalErrorException("Null value: " + e.getMessage());
162 }
163 }
164
165 public void reset() {
166
167 this.setNeedsTypeValidation(true);
168 this.setNeedsOptimization(true);
169
170 for (final GenericValue val : this.getExpressionList())
171 val.reset();
172 }
173
174 protected void setGenericValue(final int i, final GenericValue treeRoot) {
175 this.getExpressionList().set(i, treeRoot);
176 }
177
178 public void optimize() throws HBqlException {
179 if (this.needsOptimization()) {
180 for (int i = 0; i < this.getExpressionList().size(); i++)
181 this.setGenericValue(i, this.getGenericValue(i).getOptimizedValue());
182 this.setNeedsOptimization(false);
183 }
184 }
185
186 public void validateTypes(final boolean allowColumns, final boolean allowCollections) throws HBqlException {
187
188 if (this.needsTypeValidation()) {
189
190 if (!allowColumns && this.getColumnsUsedInExpr().size() > 0)
191 throw new InvalidTypeException("Invalid column reference"
192 + (this.getColumnsUsedInExpr().size() > 1 ? "s" : "")
193 + " in " + this.asString());
194
195
196
197 final List<Class<? extends GenericValue>> clazzList = Lists.newArrayList();
198 for (final GenericValue val : this.getExpressionList()) {
199 final Class<? extends GenericValue> returnType = val.validateTypes(val, allowCollections);
200 clazzList.add(returnType);
201 }
202
203
204 if (this.getTypeSignature() != null) {
205
206 if (this.getExpressionList().size() != this.getTypeSignature().getArgCount())
207 throw new InvalidTypeException("Incorrect number of variables in " + this.asString());
208
209 for (int i = 0; i < this.getTypeSignature().getArgCount(); i++) {
210
211 final Class<? extends GenericValue> parentClazz = this.getTypeSignature().getArg(i);
212 final Class<? extends GenericValue> clazz = clazzList.get(i);
213
214
215 if (TypeSupport.isParentClass(NumberValue.class, parentClazz, clazz)) {
216 final int parentRank = NumericType.getTypeRanking(parentClazz);
217 final int clazzRank = NumericType.getTypeRanking(clazz);
218 if (clazzRank > parentRank)
219 throw new InvalidTypeException("Cannot assign a " + clazz.getSimpleName()
220 + " value to a " + parentClazz.getSimpleName()
221 + " value in " + this.asString());
222 }
223 else if (parentClazz == ObjectValue.class) {
224
225 }
226 else {
227 if (!parentClazz.isAssignableFrom(clazz))
228 throw new InvalidTypeException("Expecting type " + parentClazz.getSimpleName()
229 + " but found type " + clazz.getSimpleName()
230 + " in " + this.asString());
231 }
232 }
233 }
234
235 this.setNeedsTypeValidation(false);
236 }
237 }
238
239 public List<NamedParameter> getParameterList() {
240 return this.namedParamList;
241 }
242
243 public void addNamedParameter(final NamedParameter param) {
244
245 this.getParameterList().add(param);
246
247 final String name = param.getParamName();
248 final List<NamedParameter> paramList;
249
250 if (!this.getNamedParamMap().containsKey(name)) {
251 paramList = Lists.newArrayList();
252 this.getNamedParamMap().put(name, paramList);
253 }
254 else {
255 paramList = this.getNamedParamMap().get(name);
256 }
257
258 paramList.add(param);
259 }
260
261 public int setParameter(final String name, final Object val) throws HBqlException {
262
263 final String fullname = name.startsWith(":") ? name : (":" + name);
264
265 if (!this.getNamedParamMap().containsKey(fullname))
266 return 0;
267
268
269 final List<NamedParameter> paramList = this.getNamedParamMap().get(fullname);
270 for (final NamedParameter param : paramList)
271 param.setParameter(val);
272
273 this.setNeedsTypeValidation(true);
274
275 return paramList.size();
276 }
277
278 public void addColumnToUsedList(final GenericColumn column) {
279 this.getColumnsUsedInExpr().add(column);
280 this.getAttribsUsedInExpr().add(column.getColumnAttrib());
281 }
282
283 private boolean needsTypeValidation() {
284 return needsTypeValidation;
285 }
286
287 private void setNeedsTypeValidation(final boolean inNeedOfTypeValidation) {
288 this.needsTypeValidation = inNeedOfTypeValidation;
289 }
290
291 private boolean needsOptimization() {
292 return needsOptimization;
293 }
294
295 private void setNeedsOptimization(final boolean inNeedOfOptimization) {
296 this.needsOptimization = inNeedOfOptimization;
297 }
298
299 private boolean needsContextSetting() {
300 return needsContextSetting;
301 }
302
303 private void setNeedsContextSetting(final boolean needsContextSetting) {
304 this.needsContextSetting = needsContextSetting;
305 }
306 }