001 /* 002 // $Id: //open/mondrian/src/main/mondrian/calc/impl/AbstractExpCompiler.java#25 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2006-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.calc.impl; 011 012 import mondrian.olap.*; 013 import mondrian.olap.fun.*; 014 import mondrian.olap.type.*; 015 import mondrian.olap.type.DimensionType; 016 import mondrian.olap.type.LevelType; 017 import mondrian.resource.MondrianResource; 018 import mondrian.calc.*; 019 020 import java.util.HashMap; 021 import java.util.Map; 022 import java.util.List; 023 import java.util.ArrayList; 024 025 /** 026 * Abstract implementation of the {@link mondrian.calc.ExpCompiler} interface. 027 * 028 * @author jhyde 029 * @version $Id: //open/mondrian/src/main/mondrian/calc/impl/AbstractExpCompiler.java#25 $ 030 * @since Sep 29, 2005 031 */ 032 public class AbstractExpCompiler implements ExpCompiler { 033 private final Evaluator evaluator; 034 private final Validator validator; 035 private final Map<Parameter, ParameterSlotImpl> parameterSlots = 036 new HashMap<Parameter, ParameterSlotImpl>(); 037 private List<ResultStyle> resultStyles; 038 039 /** 040 * Creates an AbstractExpCompiler 041 * 042 * @param evaluator Evaluator 043 * @param validator Validator 044 */ 045 public AbstractExpCompiler(Evaluator evaluator, Validator validator) { 046 this(evaluator, validator, ResultStyle.ANY_LIST); 047 } 048 049 /** 050 * Creates an AbstractExpCompiler which is constrained to produce one of 051 * a set of result styles. 052 * 053 * @param evaluator Evaluator 054 * @param validator Validator 055 * @param resultStyles List of result styles, preferred first, must not be 056 */ 057 public AbstractExpCompiler( 058 Evaluator evaluator, 059 Validator validator, 060 List<ResultStyle> resultStyles) 061 { 062 this.evaluator = evaluator; 063 this.validator = validator; 064 this.resultStyles = (resultStyles == null) 065 ? ResultStyle.ANY_LIST : resultStyles; 066 } 067 068 public Evaluator getEvaluator() { 069 return evaluator; 070 } 071 072 public Validator getValidator() { 073 return validator; 074 } 075 076 /** 077 * {@inheritDoc} 078 * 079 * Uses the current ResultStyle to compile the expression. 080 */ 081 public Calc compile(Exp exp) { 082 return exp.accept(this); 083 } 084 085 /** 086 * {@inheritDoc} 087 * 088 * Uses a new ResultStyle to compile the expression. 089 */ 090 public Calc compileAs( 091 Exp exp, 092 Type resultType, 093 List<ResultStyle> preferredResultTypes) 094 { 095 assert preferredResultTypes != null; 096 if (Util.Retrowoven) { 097 // Copy and replace ITERABLE 098 // A number of functions declare that they can accept 099 // ITERABLEs so here is where that those are converted to innocent 100 // LISTs for jdk1.4 and other retrowoven code. 101 List<ResultStyle> tmp = 102 new ArrayList<ResultStyle>(preferredResultTypes.size()); 103 for (ResultStyle preferredResultType : preferredResultTypes) { 104 tmp.add( 105 (preferredResultType == ResultStyle.ITERABLE) 106 ? ResultStyle.LIST 107 : preferredResultType); 108 } 109 preferredResultTypes = tmp; 110 } 111 List<ResultStyle> save = this.resultStyles; 112 try { 113 this.resultStyles = preferredResultTypes; 114 if (resultType != null && resultType != exp.getType()) { 115 if (resultType instanceof MemberType) { 116 return compileMember(exp); 117 } else if (resultType instanceof LevelType) { 118 return compileLevel(exp); 119 } else if (resultType instanceof HierarchyType) { 120 return compileHierarchy(exp); 121 } else if (resultType instanceof DimensionType) { 122 return compileDimension(exp); 123 } 124 } 125 return compile(exp); 126 } finally { 127 this.resultStyles = save; 128 } 129 } 130 131 public MemberCalc compileMember(Exp exp) { 132 final Type type = exp.getType(); 133 if (type instanceof DimensionType) { 134 final DimensionCalc dimensionCalc = compileDimension(exp); 135 return new DimensionCurrentMemberFunDef.CalcImpl( 136 new DummyExp(TypeUtil.toMemberType(type)), dimensionCalc); 137 } else if (type instanceof HierarchyType) { 138 final HierarchyCalc hierarchyCalc = compileHierarchy(exp); 139 return new HierarchyCurrentMemberFunDef.CalcImpl( 140 new DummyExp(TypeUtil.toMemberType(type)), hierarchyCalc); 141 } else if (type instanceof NullType) { 142 throw MondrianResource.instance().NullNotSupported.ex(); 143 } 144 assert type instanceof MemberType; 145 return (MemberCalc) compile(exp); 146 } 147 148 public LevelCalc compileLevel(Exp exp) { 149 final Type type = exp.getType(); 150 if (type instanceof MemberType) { 151 // <Member> --> <Member>.Level 152 final MemberCalc memberCalc = compileMember(exp); 153 return new MemberLevelFunDef.CalcImpl( 154 new DummyExp(LevelType.forType(type)), 155 memberCalc); 156 } 157 assert type instanceof LevelType; 158 return (LevelCalc) compile(exp); 159 } 160 161 public DimensionCalc compileDimension(Exp exp) { 162 final Type type = exp.getType(); 163 if (type instanceof HierarchyType) { 164 final HierarchyCalc hierarchyCalc = compileHierarchy(exp); 165 return new HierarchyDimensionFunDef.CalcImpl( 166 new DummyExp(new DimensionType(type.getDimension())), 167 hierarchyCalc); 168 } 169 assert type instanceof DimensionType : type; 170 return (DimensionCalc) compile(exp); 171 } 172 173 public HierarchyCalc compileHierarchy(Exp exp) { 174 final Type type = exp.getType(); 175 if (type instanceof DimensionType || 176 type instanceof MemberType) { 177 // <Dimension> --> <Dimension>.CurrentMember.Hierarchy 178 final MemberCalc memberCalc = compileMember(exp); 179 return new MemberHierarchyFunDef.CalcImpl( 180 new DummyExp(HierarchyType.forType(type)), 181 memberCalc); 182 } 183 if (type instanceof LevelType) { 184 // <Level> --> <Level>.Hierarchy 185 final LevelCalc levelCalc = compileLevel(exp); 186 return new LevelHierarchyFunDef.CalcImpl( 187 new DummyExp(HierarchyType.forType(type)), 188 levelCalc); 189 } 190 assert type instanceof HierarchyType; 191 return (HierarchyCalc) compile(exp); 192 } 193 194 public IntegerCalc compileInteger(Exp exp) { 195 final Calc calc = compileScalar(exp, false); 196 final Type type = calc.getType(); 197 if (type instanceof DecimalType 198 && ((DecimalType) type).getScale() == 0) { 199 return (IntegerCalc) calc; 200 } else if (type instanceof NumericType) { 201 if (calc instanceof ConstantCalc) { 202 ConstantCalc constantCalc = (ConstantCalc) calc; 203 return new ConstantCalc( 204 new DecimalType(Integer.MAX_VALUE, 0), 205 constantCalc.evaluateInteger(null)); 206 } else if (calc instanceof DoubleCalc) { 207 final DoubleCalc doubleCalc = (DoubleCalc) calc; 208 return new AbstractIntegerCalc(exp, new Calc[] {doubleCalc}) { 209 public int evaluateInteger(Evaluator evaluator) { 210 return (int) doubleCalc.evaluateDouble(evaluator); 211 } 212 }; 213 } 214 } 215 return (IntegerCalc) calc; 216 } 217 218 public StringCalc compileString(Exp exp) { 219 return (StringCalc) compile(exp); 220 } 221 222 public DateTimeCalc compileDateTime(Exp exp) { 223 return (DateTimeCalc) compile(exp); 224 } 225 226 public ListCalc compileList(Exp exp) { 227 return compileList(exp, false); 228 } 229 230 public ListCalc compileList(Exp exp, boolean mutable) { 231 if (mutable) { 232 return (ListCalc) compileAs(exp, null, ResultStyle.MUTABLELIST_ONLY); 233 } else { 234 return (ListCalc) compileAs(exp, null, ResultStyle.LIST_ONLY); 235 } 236 } 237 238 public IterCalc compileIter(Exp exp) { 239 return (IterCalc) compileAs(exp, null, ResultStyle.ITERABLE_ONLY); 240 } 241 242 public BooleanCalc compileBoolean(Exp exp) { 243 final Calc calc = compileScalar(exp, false); 244 if (calc instanceof BooleanCalc) { 245 if (calc instanceof ConstantCalc) { 246 final Object o = calc.evaluate(null); 247 if (!(o instanceof Boolean)) { 248 return ConstantCalc.constantBoolean( 249 CastFunDef.toBoolean(o, new BooleanType())); 250 } 251 } 252 return (BooleanCalc) calc; 253 } else if (calc instanceof DoubleCalc) { 254 final DoubleCalc doubleCalc = (DoubleCalc) calc; 255 return new AbstractBooleanCalc(exp, new Calc[] {doubleCalc}) { 256 public boolean evaluateBoolean(Evaluator evaluator) { 257 return doubleCalc.evaluateDouble(evaluator) != 0; 258 } 259 }; 260 } else if (calc instanceof IntegerCalc) { 261 final IntegerCalc integerCalc = (IntegerCalc) calc; 262 return new AbstractBooleanCalc(exp, new Calc[] {integerCalc}) { 263 public boolean evaluateBoolean(Evaluator evaluator) { 264 return integerCalc.evaluateInteger(evaluator) != 0; 265 } 266 }; 267 } else { 268 return (BooleanCalc) calc; 269 } 270 } 271 272 public DoubleCalc compileDouble(Exp exp) { 273 final DoubleCalc calc = (DoubleCalc) compileScalar(exp, false); 274 if (calc instanceof ConstantCalc 275 && !(calc.evaluate(null) instanceof Double)) { 276 return ConstantCalc.constantDouble( 277 calc.evaluateDouble(null)); 278 } 279 return calc; 280 } 281 282 public TupleCalc compileTuple(Exp exp) { 283 return (TupleCalc) compile(exp); 284 } 285 286 public Calc compileScalar(Exp exp, boolean specific) { 287 final Type type = exp.getType(); 288 if (type instanceof MemberType) { 289 MemberType memberType = (MemberType) type; 290 MemberCalc calc = compileMember(exp); 291 return new MemberValueCalc( 292 new DummyExp(memberType.getValueType()), 293 new MemberCalc[] {calc}); 294 } else if (type instanceof DimensionType) { 295 final DimensionCalc dimensionCalc = compileDimension(exp); 296 MemberType memberType = MemberType.forType(type); 297 final MemberCalc dimensionCurrentMemberCalc = 298 new DimensionCurrentMemberFunDef.CalcImpl( 299 new DummyExp(memberType), 300 dimensionCalc); 301 return new MemberValueCalc( 302 new DummyExp(memberType.getValueType()), 303 new MemberCalc[] {dimensionCurrentMemberCalc}); 304 } else if (type instanceof HierarchyType) { 305 HierarchyType hierarchyType = (HierarchyType) type; 306 MemberType memberType = 307 MemberType.forHierarchy(hierarchyType.getHierarchy()); 308 final HierarchyCalc hierarchyCalc = compileHierarchy(exp); 309 final MemberCalc hierarchyCurrentMemberCalc = 310 new HierarchyCurrentMemberFunDef.CalcImpl( 311 new DummyExp(memberType), hierarchyCalc); 312 return new MemberValueCalc( 313 new DummyExp(memberType.getValueType()), 314 new MemberCalc[] {hierarchyCurrentMemberCalc}); 315 } else if (type instanceof TupleType) { 316 TupleType tupleType = (TupleType) type; 317 TupleCalc tupleCalc = compileTuple(exp); 318 final TupleValueCalc scalarCalc = new TupleValueCalc( 319 new DummyExp(tupleType.getValueType()), tupleCalc); 320 return scalarCalc.optimize(); 321 } else if (type instanceof ScalarType) { 322 if (specific) { 323 if (type instanceof BooleanType) { 324 return compileBoolean(exp); 325 } else if (type instanceof NumericType) { 326 return compileDouble(exp); 327 } else if (type instanceof StringType) { 328 return compileString(exp); 329 } else { 330 return compile(exp); 331 } 332 } else { 333 return compile(exp); 334 } 335 } else { 336 return compile(exp); 337 } 338 } 339 340 public ParameterSlot registerParameter(Parameter parameter) { 341 ParameterSlot slot = parameterSlots.get(parameter); 342 if (slot != null) { 343 return slot; 344 } 345 int index = parameterSlots.size(); 346 ParameterSlotImpl slot2 = new ParameterSlotImpl(parameter, index); 347 parameterSlots.put(parameter, slot2); 348 slot2.value = parameter.getValue(); 349 350 // Compile the expression only AFTER the parameter has been 351 // registered with a slot. Otherwise a cycle is possible. 352 Calc calc = parameter.getDefaultExp().accept(this); 353 slot2.setDefaultValueCalc(calc); 354 return slot2; 355 } 356 357 public List<ResultStyle> getAcceptableResultStyles() { 358 return resultStyles; 359 } 360 361 /** 362 * Implementation of {@link ParameterSlot}. 363 */ 364 private static class ParameterSlotImpl implements ParameterSlot { 365 private final Parameter parameter; 366 private final int index; 367 private Calc defaultValueCalc; 368 private Object value; 369 private Object cachedDefaultValue; 370 371 /** 372 * Creates a ParameterSlotImpl. 373 * 374 * @param parameter Parameter 375 * @param index Unique index of the slot 376 */ 377 public ParameterSlotImpl( 378 Parameter parameter, int index) 379 { 380 this.parameter = parameter; 381 this.index = index; 382 } 383 384 public int getIndex() { 385 return index; 386 } 387 388 public Calc getDefaultValueCalc() { 389 return defaultValueCalc; 390 } 391 392 public Parameter getParameter() { 393 return parameter; 394 } 395 396 /** 397 * Sets a compiled expression to compute the default value of the 398 * parameter. 399 * 400 * @param calc Compiled expression to compute default value of 401 * parameter 402 * 403 * @see #getDefaultValueCalc() 404 */ 405 private void setDefaultValueCalc(Calc calc) { 406 this.defaultValueCalc = calc; 407 } 408 409 public void setParameterValue(Object value) { 410 this.value = value; 411 } 412 413 public Object getParameterValue() { 414 return value; 415 } 416 417 public void setCachedDefaultValue(Object value) { 418 this.cachedDefaultValue = value; 419 } 420 421 public Object getCachedDefaultValue() { 422 return cachedDefaultValue; 423 } 424 } 425 } 426 427 // End AbstractExpCompiler.java