1 13 14 package mondrian.olap; 15 import mondrian.olap.type.*; 16 import mondrian.resource.MondrianResource; 17 import mondrian.mdx.MemberExpr; 18 import mondrian.mdx.MdxVisitor; 19 import mondrian.mdx.MdxVisitorImpl; 20 21 import java.io.PrintWriter ; 22 import java.util.Arrays ; 23 import java.util.List ; 24 25 29 public class Formula extends QueryPart { 30 31 32 private final String [] names; 33 34 private Exp exp; 35 private final MemberProperty[] memberProperties; 37 41 private final boolean isMember; 42 43 private Member mdxMember; 44 private NamedSet mdxSet; 45 46 49 public Formula(String [] names, Exp exp) { 50 this(false, names, exp, new MemberProperty[0], null, null); 51 createElement(null); 52 } 53 54 57 public Formula(String [] names, Exp exp, MemberProperty[] memberProperties) { 58 this(true, names, exp, memberProperties, null, null); 59 } 60 61 private Formula( 62 boolean isMember, 63 String [] names, 64 Exp exp, 65 MemberProperty[] memberProperties, 66 Member mdxMember, 67 NamedSet mdxSet) { 68 this.isMember = isMember; 69 this.names = names; 70 this.exp = exp; 71 this.memberProperties = memberProperties; 72 this.mdxMember = mdxMember; 73 this.mdxSet = mdxSet; 74 assert !(!isMember && mdxMember != null); 75 assert !(isMember && mdxSet != null); 76 } 77 78 public Object clone() { 79 return new Formula( 80 isMember, 81 names, 82 (Exp) exp.clone(), 83 MemberProperty.cloneArray(memberProperties), 84 mdxMember, 85 mdxSet); 86 } 87 88 static Formula[] cloneArray(Formula[] x) { 89 Formula[] x2 = new Formula[x.length]; 90 for (int i = 0; i < x.length; i++) { 91 x2[i] = (Formula) x[i].clone(); 92 } 93 return x2; 94 } 95 96 102 void accept(Validator validator) { 103 final boolean scalar = isMember; 104 exp = validator.validate(exp, scalar); 105 String id = Util.quoteMdxIdentifier(names); 106 final Type type = exp.getType(); 107 if (isMember) { 108 if (!TypeUtil.canEvaluate(type)) { 109 throw MondrianResource.instance().MdxMemberExpIsSet.ex(exp.toString()); 110 } 111 } else { 112 if (!TypeUtil.isSet(type)) { 113 throw MondrianResource.instance().MdxSetExpNotSet.ex(id); 114 } 115 } 116 for (int i = 0; i < memberProperties.length; i++) { 117 validator.validate(memberProperties[i]); 118 } 119 if (isMember) { 122 Exp formatExp = getFormatExp(); 123 if (formatExp != null) { 124 mdxMember.setProperty(Property.FORMAT_EXP.name, formatExp); 125 } 126 127 final List formatPropertyList = 130 Arrays.asList(Property.FORMAT_PROPERTIES); 131 for (MemberProperty memberProperty : memberProperties) { 132 if (formatPropertyList.contains(memberProperty.getName())) { 133 continue; } 135 final Exp exp = memberProperty.getExp(); 136 if (exp instanceof Literal) { 137 String value = String.valueOf(((Literal) exp).getValue()); 138 mdxMember.setProperty(memberProperty.getName(), value); 139 } 140 } 141 } 142 } 143 144 148 void createElement(Query q) { 149 if (isMember) { 151 if (mdxMember != null) { 152 return; 153 } 154 OlapElement mdxElement = q.getCube(); 155 final SchemaReader schemaReader = q.getSchemaReader(true); 156 for (int i = 0; i < names.length; i++) { 157 OlapElement parent = mdxElement; 158 mdxElement = schemaReader.getElementChild(parent, names[i]); 159 if (mdxElement == null || i == names.length - 1) { 164 Level level; 166 Member parentMember = null; 167 if (parent instanceof Member) { 168 parentMember = (Member) parent; 169 level = parentMember.getLevel().getChildLevel(); 170 } else { 171 Hierarchy hierarchy = parent.getHierarchy(); 172 if (hierarchy == null) { 173 throw MondrianResource.instance().MdxCalculatedHierarchyError.ex( 174 Util.quoteMdxIdentifier(names)); 175 } 176 level = hierarchy.getLevels()[0]; 177 } 178 Member mdxMember = level.getHierarchy().createMember( 179 parentMember, level, names[i], this); 180 mdxElement = mdxMember; 181 } 182 } 183 this.mdxMember = (Member) mdxElement; 184 } else { 185 Util.assertTrue( 187 names.length == 1, "set names must not be compound"); 188 mdxSet = new SetBase(names[0], exp); 189 } 190 } 191 192 public Object [] getChildren() { 193 Object [] children = new Object [1 + memberProperties.length]; 194 children[0] = exp; 195 System.arraycopy(memberProperties, 0, 196 children, 1, memberProperties.length); 197 return children; 198 } 199 200 201 public void unparse(PrintWriter pw) 202 { 203 if (isMember) { 204 pw.print("member "); 205 if (mdxMember != null) { 206 pw.print(mdxMember.getUniqueName()); 207 } else { 208 pw.print(Util.quoteMdxIdentifier(names)); 209 } 210 } else { 211 pw.print("set "); 212 pw.print(Util.quoteMdxIdentifier(names)); 213 } 214 pw.print(" as '"); 215 exp.unparse(pw); 216 pw.print("'"); 217 if (memberProperties != null) { 218 for (MemberProperty memberProperty : memberProperties) { 219 pw.print(", "); 220 memberProperty.unparse(pw); 221 } 222 } 223 } 224 225 public boolean isMember() { 226 return isMember; 227 } 228 229 public NamedSet getNamedSet() { 230 return mdxSet; 231 } 232 233 String [] getNames() { 234 return names; 235 } 236 237 238 public String getName() { 239 return (isMember) 240 ? mdxMember.getName() 241 : mdxSet.getName(); 242 } 243 244 245 public String getCaption() { 246 return (isMember) 247 ? mdxMember.getCaption() 248 : mdxSet.getName(); 249 } 250 251 257 void rename(String newName) 258 { 259 String oldName = getElement().getName(); 260 Util.assertTrue( 261 this.names[this.names.length - 1].equalsIgnoreCase(oldName)); 262 this.names[this.names.length - 1] = newName; 263 if (isMember) { 264 mdxMember.setName(newName); 265 } else { 266 mdxSet.setName(newName); 267 } 268 } 269 270 271 String getUniqueName() { 272 return (isMember) 273 ? mdxMember.getUniqueName() 274 : mdxSet.getUniqueName(); 275 } 276 277 OlapElement getElement() { 278 return (isMember) 279 ? (OlapElement) mdxMember 280 : (OlapElement) mdxSet; 281 } 282 283 public Exp getExpression() { 284 return exp; 285 } 286 287 private Exp getMemberProperty(String name) { 288 return MemberProperty.get(memberProperties, name); 289 } 290 291 297 public Member getMdxMember() { 298 return mdxMember; 299 } 300 301 308 public Number getSolveOrder() { 309 return getIntegerMemberProperty(Property.SOLVE_ORDER.name); 310 } 311 312 322 private Number getIntegerMemberProperty(String name) { 323 Exp exp = getMemberProperty(name); 324 if (exp != null && exp.getType() instanceof NumericType) { 325 return quickEval(exp); 326 } 327 return null; 328 } 329 330 336 private static Number quickEval(Exp exp) { 337 if (exp instanceof Literal) { 338 Literal literal = (Literal) exp; 339 final Object value = literal.getValue(); 340 if (value instanceof Number ) { 341 return (Number ) value; 342 } else { 343 return null; 344 } 345 } 346 if (exp instanceof FunCall) { 347 FunCall call = (FunCall) exp; 348 if (call.getFunName().equals("=") && 349 call.getSyntax() == Syntax.Prefix) { 350 final Number number = quickEval(call.getArg(0)); 351 if (number == null) { 352 return null; 353 } else if (number instanceof Integer ) { 354 return -number.intValue(); 355 } else { 356 return -number.doubleValue(); 357 } 358 } 359 } 360 return null; 361 } 362 363 369 private Exp getFormatExp() { 370 for (String prop : Property.FORMAT_PROPERTIES) { 373 Exp formatExp = getMemberProperty(prop); 374 if (formatExp != null) { 375 return formatExp; 376 } 377 } 378 379 final Type type = exp.getType(); 382 if (type instanceof DecimalType) { 383 int scale = ((DecimalType) type).getScale(); 384 String formatString = "#,##0"; 385 if (scale > 0) { 386 formatString = formatString + "."; 387 while (scale-- > 0) { 388 formatString = formatString + "0"; 389 } 390 } 391 return Literal.createString(formatString); 392 } 393 394 if (!mdxMember.isMeasure()) { 395 return null; 400 } 401 402 try { 405 exp.accept( 406 new MdxVisitorImpl() { 407 public Object visit(MemberExpr memberExpr) { 408 Exp formatExp = (Exp) memberExpr.getMember(). 409 getPropertyValue(Property.FORMAT_EXP.name); 410 if (formatExp != null) { 411 throw new FoundOne(formatExp); 412 } 413 return super.visit(memberExpr); 414 } 415 } 416 ); 417 return null; 418 } catch (FoundOne foundOne) { 419 return foundOne.exp; 420 } 421 } 422 423 public void compile() { 424 } 426 427 434 public Object accept(MdxVisitor visitor) { 435 final Object o = visitor.visit(this); 436 437 exp.accept(visitor); 439 440 return o; 441 } 442 443 private static class FoundOne extends RuntimeException { 444 private final Exp exp; 445 446 public FoundOne(Exp exp) { 447 super(); 448 this.exp = exp; 449 } 450 } 451 } 452 453 | Popular Tags |