1 13 14 package mondrian.rolap; 15 import mondrian.olap.*; 16 import mondrian.rolap.agg.AggregationManager; 17 import mondrian.rolap.aggmatcher.ExplicitRules; 18 import mondrian.resource.MondrianResource; 19 import mondrian.mdx.*; 20 21 import org.apache.log4j.Logger; 22 import org.eigenbase.xom.*; 23 import org.eigenbase.xom.Parser; 24 25 import java.lang.reflect.Constructor ; 26 import java.util.*; 27 import java.util.Set ; 28 29 36 public class RolapCube extends CubeBase { 37 38 private static final Logger LOGGER = Logger.getLogger(RolapCube.class); 39 40 private final RolapSchema schema; 41 private final RolapHierarchy measuresHierarchy; 42 43 final MondrianDef.Relation fact; 44 45 46 private final CellReader cellReader; 47 48 54 private int[] localDimensionOrdinals; 55 56 57 private SchemaReader schemaReader; 58 59 62 private Formula[] calculatedMembers; 63 64 67 private Formula[] namedSets; 68 69 70 private final List<HierarchyUsage> hierarchyUsages; 71 72 private RolapStar star; 73 private ExplicitRules.Group aggGroup; 74 75 78 private boolean load; 79 80 private final Map<Hierarchy, HierarchyUsage> firstUsageMap = 81 new HashMap<Hierarchy, HierarchyUsage>(); 82 83 90 private RolapCube(RolapSchema schema, 91 MondrianDef.Schema xmlSchema, 92 String name, 93 boolean isCache, 94 MondrianDef.Relation fact, 95 MondrianDef.CubeDimension[] dimensions, 96 boolean load) { 97 super(name, new RolapDimension[dimensions.length + 1]); 98 99 this.schema = schema; 100 this.fact = fact; 101 this.hierarchyUsages = new ArrayList<HierarchyUsage>(); 102 this.cellReader = AggregationManager.instance(); 103 this.calculatedMembers = new Formula[0]; 104 this.namedSets = new Formula[0]; 105 this.load = load; 106 107 if (! isVirtual()) { 108 this.star = schema.getRolapStarRegistry().getOrCreateStar(fact); 109 if (! isCache) { 113 star.setCacheAggregations(isCache); 114 } 115 } 116 117 if (getLogger().isDebugEnabled()) { 118 if (isVirtual()) { 119 getLogger().debug("RolapCube<init>: virtual cube=" +this.name); 120 } else { 121 getLogger().debug("RolapCube<init>: cube=" +this.name); 122 } 123 } 124 125 RolapDimension measuresDimension = new RolapDimension( 126 schema, 127 Dimension.MEASURES_NAME, 128 0, 129 DimensionType.StandardDimension); 130 131 this.dimensions[0] = measuresDimension; 132 133 this.measuresHierarchy = measuresDimension.newHierarchy(null, false); 134 135 if (!Util.isEmpty(xmlSchema.measuresCaption)) { 136 measuresDimension.setCaption(xmlSchema.measuresCaption); 137 this.measuresHierarchy.setCaption(xmlSchema.measuresCaption); 138 } 139 140 for (int i = 0; i < dimensions.length; i++) { 141 MondrianDef.CubeDimension xmlCubeDimension = dimensions[i]; 142 RolapDimension dimension = 145 getOrCreateDimension(xmlCubeDimension, schema, xmlSchema); 146 if (getLogger().isDebugEnabled()) { 147 getLogger().debug("RolapCube<init>: dimension=" 148 +dimension.getName()); 149 } 150 this.dimensions[i + 1] = dimension; 151 152 if (! isVirtual()) { 153 createUsages(dimension, xmlCubeDimension); 154 } 155 156 } 157 158 schema.addCube(this); 159 } 160 161 164 RolapCube(RolapSchema schema, 165 MondrianDef.Schema xmlSchema, 166 MondrianDef.Cube xmlCube, 167 boolean load) { 168 this(schema, xmlSchema, xmlCube.name, xmlCube.cache, 169 xmlCube.fact, xmlCube.dimensions, load); 170 171 if (fact.getAlias() == null) { 172 throw Util.newError( 173 "Must specify alias for fact table of cube " + 174 getUniqueName()); 175 } 176 177 178 RolapLevel measuresLevel = 182 this.measuresHierarchy.newLevel("MeasuresLevel", 0); 183 184 RolapMember measures[] = new RolapMember[xmlCube.measures.length]; 185 for (int i = 0; i < xmlCube.measures.length; i++) { 186 MondrianDef.Measure xmlMeasure = xmlCube.measures[i]; 187 MondrianDef.Expression measureExp; 188 if (xmlMeasure.column != null) { 189 if (xmlMeasure.measureExp != null) { 190 throw MondrianResource.instance(). 191 BadMeasureSource.ex( 192 xmlCube.name, xmlMeasure.name); 193 } 194 measureExp = new MondrianDef.Column( 195 fact.getAlias(), xmlMeasure.column); 196 } else if (xmlMeasure.measureExp != null) { 197 measureExp = xmlMeasure.measureExp; 198 } else { 199 throw MondrianResource.instance(). 200 BadMeasureSource.ex( 201 xmlCube.name, xmlMeasure.name); 202 } 203 204 String aggregator = xmlMeasure.aggregator; 207 if (aggregator.equals("distinct count")) { 208 aggregator = RolapAggregator.DistinctCount.getName(); 209 } 210 final RolapBaseCubeMeasure measure = new RolapBaseCubeMeasure( 211 this, null, measuresLevel, xmlMeasure.name, 212 xmlMeasure.formatString, measureExp, 213 aggregator, xmlMeasure.datatype); 214 measures[i] = measure; 215 216 if (!Util.isEmpty(xmlMeasure.formatter)) { 217 try { 219 Class <CellFormatter> clazz = 220 (Class <CellFormatter>) 221 Class.forName(xmlMeasure.formatter); 222 Constructor <CellFormatter> ctor = clazz.getConstructor(); 223 CellFormatter cellFormatter = ctor.newInstance(); 224 measure.setFormatter(cellFormatter); 225 } catch (Exception e) { 226 e.printStackTrace(); 227 } 228 } 229 230 if (!Util.isEmpty(xmlMeasure.caption)) { 232 measure.setProperty( 234 Property.CAPTION.name, 235 xmlMeasure.caption); 236 } 237 238 Boolean visible = xmlMeasure.visible; 240 if (visible == null) { 241 visible = Boolean.TRUE; 242 } 243 measure.setProperty(Property.VISIBLE.name, visible); 244 245 List<String > propNames = new ArrayList<String >(); 246 List<String > propExprs = new ArrayList<String >(); 247 validateMemberProps(xmlMeasure.memberProperties, propNames, 248 propExprs, xmlMeasure.name); 249 for (int j = 0; j < propNames.size(); j++) { 250 String propName = propNames.get(j); 251 final Object propExpr = propExprs.get(j); 252 measure.setProperty(propName, propExpr); 253 } 254 } 255 256 this.measuresHierarchy.setMemberReader(new CacheMemberReader( 257 new MeasureMemberSource(this.measuresHierarchy, measures))); 258 init(xmlCube.dimensions); 259 init(xmlCube); 260 261 checkOrdinals(xmlCube.name, measures, xmlCube.calculatedMembers); 262 loadAggGroup(xmlCube); 263 } 264 265 268 RolapCube(RolapSchema schema, 269 MondrianDef.Schema xmlSchema, 270 MondrianDef.VirtualCube xmlVirtualCube, 271 boolean load) { 272 this(schema, xmlSchema, xmlVirtualCube.name, true, 273 null, xmlVirtualCube.dimensions, load); 274 275 276 RolapLevel measuresLevel = 280 this.measuresHierarchy.newLevel("MeasuresLevel", 0); 281 282 List<RolapVirtualCubeMeasure> origMeasureList = 285 new ArrayList<RolapVirtualCubeMeasure>(); 286 List<MondrianDef.CalculatedMember> origCalcMeasureList = 287 new ArrayList<MondrianDef.CalculatedMember>(); 288 CubeComparator cubeComparator = new CubeComparator(); 289 Map<RolapCube, List<MondrianDef.CalculatedMember>> calculatedMembersMap = 290 new TreeMap<RolapCube, List<MondrianDef.CalculatedMember>>( 291 cubeComparator); 292 for (MondrianDef.VirtualCubeMeasure xmlMeasure : xmlVirtualCube.measures) { 293 RolapCube cube = schema.lookupCube(xmlMeasure.cubeName); 295 Member[] cubeMeasures = cube.getMeasures(); 296 boolean found = false; 297 for (Member cubeMeasure : cubeMeasures) { 298 if (cubeMeasure.getUniqueName().equals(xmlMeasure.name)) { 299 found = true; 300 if (cubeMeasure instanceof RolapCalculatedMember) { 301 MondrianDef.CalculatedMember calcMember = 308 schema.lookupXmlCalculatedMember( 309 xmlMeasure.name, xmlMeasure.cubeName); 310 if (calcMember == null) { 311 throw Util.newInternal( 312 "Could not find XML Calculated Member '" + 313 xmlMeasure.name + "' in XML cube '" + 314 xmlMeasure.cubeName + "'"); 315 } 316 List<MondrianDef.CalculatedMember> memberList = 317 calculatedMembersMap.get(cube); 318 if (memberList == null) { 319 memberList = 320 new ArrayList<MondrianDef.CalculatedMember>(); 321 } 322 memberList.add(calcMember); 323 origCalcMeasureList.add(calcMember); 324 calculatedMembersMap.put(cube, memberList); 325 } else { 326 RolapVirtualCubeMeasure virtualCubeMeasure = 330 new RolapVirtualCubeMeasure( 331 null, 332 measuresLevel, 333 (RolapStoredMeasure) cubeMeasure); 334 335 Boolean visible = xmlMeasure.visible; 337 if (visible == null) { 338 visible = Boolean.TRUE; 339 } 340 virtualCubeMeasure.setProperty(Property.VISIBLE.name, 341 visible); 342 origMeasureList.add(virtualCubeMeasure); 343 } 344 break; 345 } 346 } 347 if (!found) { 348 throw Util.newInternal( 349 "could not find measure '" + xmlMeasure.name + 350 "' in cube '" + xmlMeasure.cubeName + "'"); 351 } 352 } 353 354 init(xmlVirtualCube.dimensions); 356 357 List<RolapVirtualCubeMeasure> modifiedMeasureList = new ArrayList<RolapVirtualCubeMeasure>(origMeasureList); 362 for (Object o : calculatedMembersMap.keySet()) { 363 RolapCube baseCube = (RolapCube) o; 364 List<MondrianDef.CalculatedMember> calculatedMemberList = 365 calculatedMembersMap.get(baseCube); 366 Query queryExp = resolveCalcMembers( 367 calculatedMemberList.toArray( 368 new MondrianDef.CalculatedMember[ 369 calculatedMemberList.size()]), 370 new MondrianDef.NamedSet[0], 371 baseCube, 372 false); 373 MeasureFinder measureFinder = 374 new MeasureFinder(this, baseCube, measuresLevel); 375 queryExp.accept(measureFinder); 376 modifiedMeasureList.addAll(measureFinder.getMeasuresFound()); 377 } 378 379 List<MondrianDef.CalculatedMember> calculatedMemberList = new ArrayList<MondrianDef.CalculatedMember>(); 382 for (Object o : calculatedMembersMap.keySet()) { 383 RolapCube baseCube = (RolapCube) o; 384 calculatedMemberList.addAll( 385 calculatedMembersMap.get(baseCube)); 386 } 387 calculatedMemberList.addAll( 388 Arrays.asList(xmlVirtualCube.calculatedMembers)); 389 390 RolapMember[] measures = 394 modifiedMeasureList.toArray( 395 new RolapMember[modifiedMeasureList.size()]); 396 this.measuresHierarchy.setMemberReader( 397 new CacheMemberReader( 398 new MeasureMemberSource(this.measuresHierarchy, measures))); 399 createCalcMembersAndNamedSets( 400 calculatedMemberList.toArray( 401 new MondrianDef.CalculatedMember[ 402 calculatedMemberList.size()]), 403 new MondrianDef.NamedSet[0], 404 new ArrayList<Member>(), 405 new ArrayList<Formula>(), 406 this, 407 false); 408 409 measures = 412 origMeasureList.toArray( 413 new RolapMember[origMeasureList.size()]); 414 this.measuresHierarchy.setMemberReader( 415 new CacheMemberReader( 416 new MeasureMemberSource(this.measuresHierarchy, measures))); 417 418 List<Formula> finalCalcMemberList = new ArrayList<Formula>(); 421 for (Formula calculatedMember : calculatedMembers) { 422 if (findOriginalMembers( 423 calculatedMember, 424 origCalcMeasureList, 425 finalCalcMemberList)) { 426 continue; 427 } 428 findOriginalMembers( 429 calculatedMember, 430 Arrays.asList(xmlVirtualCube.calculatedMembers), 431 finalCalcMemberList); 432 } 433 calculatedMembers = 434 finalCalcMemberList.toArray( 435 new Formula[finalCalcMemberList.size()]); 436 437 } 439 440 private boolean findOriginalMembers( 441 Formula formula, 442 List<MondrianDef.CalculatedMember> calcMemberList, 443 List<Formula> finalCalcMemberList) 444 { 445 for (MondrianDef.CalculatedMember xmlCalcMember : calcMemberList) { 446 Dimension dimension = 447 (Dimension) lookupDimension(xmlCalcMember.dimension); 448 if (formula.getName().equals(xmlCalcMember.name) && 449 formula.getMdxMember().getDimension().getName().equals( 450 dimension.getName())) { 451 finalCalcMemberList.add(formula); 452 return true; 453 } 454 } 455 return false; 456 } 457 458 protected void validate() { 459 Map<String , List<Object >> aliases = new HashMap<String , List<Object >>(); 462 List<Object > joinPath = new ArrayList<Object >(); 463 joinPath.add(this); 464 for (Dimension dimension : dimensions) { 465 final Hierarchy[] hierarchies = dimension.getHierarchies(); 466 for (Hierarchy hierarchy : hierarchies) { 467 MondrianDef.Relation relation = 468 ((RolapHierarchy) hierarchy).getRelation(); 469 if (relation != null) { 470 final HierarchyUsage hierarchyUsage = 471 getFirstUsage(hierarchy); 472 joinPath.add(hierarchyUsage.getForeignKey()); 473 validateRelation( 474 aliases, 475 relation, 476 joinPath); 477 joinPath.remove(joinPath.size() - 1); 478 } 479 } 480 } 481 } 482 483 private void validateRelation( 484 Map<String , List<Object >> aliases, 485 MondrianDef.Relation relation, 486 List<Object > joinPath) { 487 if (relation instanceof MondrianDef.Join) { 488 MondrianDef.Join join = (MondrianDef.Join) relation; 489 490 validateRelation(aliases, join.left, joinPath); 491 492 int saveSize = joinPath.size(); 493 flatten(relation, joinPath); 494 joinPath.add(join.leftKey); 495 joinPath.add(join.rightKey); 496 validateRelation(aliases, join.right, joinPath); 497 while (joinPath.size() > saveSize) { 498 joinPath.remove(joinPath.size() - 1); 499 } 500 } else { 501 String alias; 502 if (relation instanceof MondrianDef.Table) { 503 MondrianDef.Table table = (MondrianDef.Table) relation; 504 alias = table.alias; 505 if (alias == null) { 506 alias = table.name; 507 } 508 } else if (relation instanceof MondrianDef.InlineTable) { 509 MondrianDef.InlineTable table = (MondrianDef.InlineTable) relation; 510 alias = table.alias; 511 } else { 512 final MondrianDef.View view = (MondrianDef.View) relation; 513 alias = view.alias; 514 } 515 joinPath.add(relation); 516 joinPath.add(alias); 517 List joinPath2 = aliases.get(alias); 518 if (joinPath2 == null) { 519 aliases.put(alias, new ArrayList<Object >(joinPath)); 520 } else { 521 if (!joinPath.equals(joinPath2)) { 522 throw MondrianResource.instance().DuplicateAliasInCube.ex( 523 alias, this.getUniqueName()); 524 } 525 } 526 joinPath.remove(joinPath.size() - 1); 527 joinPath.remove(joinPath.size() - 1); 528 } 529 } 530 531 private void flatten(MondrianDef.Relation relation, List<Object > joinPath) { 532 if (relation instanceof MondrianDef.Join) { 533 MondrianDef.Join join = (MondrianDef.Join) relation; 534 flatten(join.left, joinPath); 535 flatten(join.right, joinPath); 536 } else { 537 joinPath.add(relation); 538 } 539 } 540 541 protected Logger getLogger() { 542 return LOGGER; 543 } 544 545 public boolean hasAggGroup() { 546 return (aggGroup != null); 547 } 548 public ExplicitRules.Group getAggGroup() { 549 return aggGroup; 550 } 551 void loadAggGroup(MondrianDef.Cube xmlCube) { 552 aggGroup = ExplicitRules.Group.make(this, xmlCube); 553 } 554 555 565 private RolapDimension getOrCreateDimension( 566 MondrianDef.CubeDimension xmlCubeDimension, 567 RolapSchema schema, 568 MondrianDef.Schema xmlSchema) { 569 570 if (xmlCubeDimension instanceof MondrianDef.DimensionUsage) { 571 MondrianDef.DimensionUsage usage = 572 (MondrianDef.DimensionUsage) xmlCubeDimension; 573 final RolapHierarchy sharedHierarchy = 574 schema.getSharedHierarchy(usage.source); 575 if (sharedHierarchy != null) { 576 581 return (RolapDimension) sharedHierarchy.getDimension(); 582 } 583 } 584 MondrianDef.Dimension xmlDimension = 585 xmlCubeDimension.getDimension(xmlSchema); 586 594 return new RolapDimension(schema, this, xmlDimension, 595 xmlCubeDimension); 596 } 597 598 602 private void init(MondrianDef.Cube xmlCube) { 603 List<Member> memberList = new ArrayList<Member>(); 608 List<Formula> formulaList = new ArrayList<Formula>(); 609 createCalcMembersAndNamedSets( 610 xmlCube.calculatedMembers, xmlCube.namedSets, 611 memberList, formulaList, this, true); 612 } 613 614 615 623 private void checkOrdinals( 624 String cubeName, 625 RolapMember measures[], 626 MondrianDef.CalculatedMember[] xmlCalcMembers) 627 { 628 Map<Integer , String > ordinals = new HashMap<Integer , String >(); 629 630 for (RolapMember measure : measures) { 632 Integer ordinal = measure.getOrdinal(); 633 if (!ordinals.containsKey(ordinal)) { 634 ordinals.put(ordinal, measure.getUniqueName()); 635 } else { 636 throw MondrianResource.instance().MeasureOrdinalsNotUnique.ex( 637 cubeName, 638 ordinal.toString(), 639 ordinals.get(ordinal), 640 measure.getUniqueName()); 641 } 642 } 643 644 for (MondrianDef.CalculatedMember xmlCalcMember : xmlCalcMembers) { 646 if (xmlCalcMember.dimension.equalsIgnoreCase("Measures")) { 647 MondrianDef.CalculatedMemberProperty[] properties = 648 xmlCalcMember.memberProperties; 649 650 for (int j = 0; j < properties.length; j++) { 651 if (properties[j].name.equals( 652 Property.MEMBER_ORDINAL.getName())) { 653 Integer ordinal = new Integer (properties[j].value); 654 655 final String uname = 656 "[Measures].[" + xmlCalcMember.name + "]"; 657 if (!ordinals.containsKey(ordinal)) { 658 ordinals.put(ordinal, uname); 659 } else { 660 throw MondrianResource.instance(). 661 MeasureOrdinalsNotUnique.ex( 662 cubeName, 663 ordinal.toString(), 664 ordinals.get(ordinal), 665 uname); 666 } 667 } 668 } 669 } 670 } 671 } 672 673 684 private void createCalcMembersAndNamedSets( 685 MondrianDef.CalculatedMember[] xmlCalcMembers, 686 MondrianDef.NamedSet[] xmlNamedSets, 687 List<Member> memberList, 688 List<Formula> formulaList, 689 RolapCube cube, 690 boolean errOnDups) { 691 692 final Query queryExp = 693 resolveCalcMembers( 694 xmlCalcMembers, 695 xmlNamedSets, 696 cube, 697 errOnDups); 698 if (queryExp == null) { 699 return; 700 } 701 702 Util.assertTrue(queryExp.formulas.length == 704 xmlCalcMembers.length + xmlNamedSets.length); 705 for (int i = 0; i < xmlCalcMembers.length; i++) { 706 postCalcMember(xmlCalcMembers, i, queryExp, memberList); 707 } 708 for (int i = 0; i < xmlNamedSets.length; i++) { 709 postNamedSet(xmlNamedSets, xmlCalcMembers.length, i, queryExp, formulaList); 710 } 711 } 712 713 private Query resolveCalcMembers( 714 MondrianDef.CalculatedMember[] xmlCalcMembers, 715 MondrianDef.NamedSet[] xmlNamedSets, 716 RolapCube cube, 717 boolean errOnDups) 718 { 719 if (xmlCalcMembers.length == 0 && xmlNamedSets.length == 0) { 722 return null; 723 } 724 725 StringBuilder buf = new StringBuilder (256); 726 buf.append("WITH").append(Util.nl); 727 728 for (int i = 0; i < xmlCalcMembers.length; i++) { 730 preCalcMember(xmlCalcMembers, i, buf, cube, errOnDups); 731 } 732 733 Set <String > nameSet = new HashSet<String >(); 735 for (Formula namedSet : namedSets) { 736 nameSet.add(namedSet.getName()); 737 } 738 for (MondrianDef.NamedSet xmlNamedSet : xmlNamedSets) { 739 preNamedSet(xmlNamedSet, nameSet, buf); 740 } 741 742 buf.append("SELECT FROM ") 743 .append(Util.quoteMdxIdentifier(cube.getUniqueName())); 744 745 final String queryString = buf.toString(); 747 final Query queryExp; 748 try { 749 RolapConnection conn = schema.getInternalConnection(); 750 queryExp = conn.parseQuery(queryString, load); 751 } catch (Exception e) { 752 throw MondrianResource.instance().UnknownNamedSetHasBadFormula.ex( 753 getUniqueName(), e); 754 } 755 queryExp.resolve(); 756 return queryExp; 757 } 758 759 private void postNamedSet( 760 MondrianDef.NamedSet[] xmlNamedSets, 761 final int offset, int i, 762 final Query queryExp, 763 List<Formula> formulaList) { 764 MondrianDef.NamedSet xmlNamedSet = xmlNamedSets[i]; 765 Util.discard(xmlNamedSet); 766 Formula formula = queryExp.formulas[offset + i]; 767 namedSets = (Formula[]) RolapUtil.addElement(namedSets, formula); 768 formulaList.add(formula); 769 } 770 771 private void preNamedSet( 772 MondrianDef.NamedSet xmlNamedSet, 773 Set <String > nameSet, 774 StringBuilder buf) { 775 if (!nameSet.add(xmlNamedSet.name)) { 776 throw MondrianResource.instance().NamedSetNotUnique.ex( 777 xmlNamedSet.name, getUniqueName()); 778 } 779 780 buf.append("SET ") 781 .append(Util.makeFqName(xmlNamedSet.name)) 782 .append(Util.nl) 783 .append(" AS "); 784 Util.singleQuoteString(xmlNamedSet.getFormula(), buf); 785 buf.append(Util.nl); 786 } 787 788 private void postCalcMember( 789 MondrianDef.CalculatedMember[] xmlCalcMembers, 790 int i, 791 final Query queryExp, 792 List<Member> memberList) { 793 MondrianDef.CalculatedMember xmlCalcMember = xmlCalcMembers[i]; 794 final Formula formula = queryExp.formulas[i]; 795 796 calculatedMembers = (Formula[]) 797 RolapUtil.addElement(calculatedMembers, formula); 798 799 Member member = formula.getMdxMember(); 800 801 Boolean visible = xmlCalcMember.visible; 802 if (visible == null) { 803 visible = Boolean.TRUE; 804 } 805 member.setProperty(Property.VISIBLE.name, visible); 806 807 if ((xmlCalcMember.caption != null) && 808 xmlCalcMember.caption.length() > 0) { 809 member.setProperty( 810 Property.CAPTION.name, 811 xmlCalcMember.caption); 812 } 813 814 memberList.add(formula.getMdxMember()); 815 } 816 817 private void preCalcMember( 818 MondrianDef.CalculatedMember[] xmlCalcMembers, 819 int j, 820 StringBuilder buf, 821 RolapCube cube, 822 boolean errOnDup) { 823 MondrianDef.CalculatedMember xmlCalcMember = xmlCalcMembers[j]; 824 825 final Dimension dimension = 827 (Dimension) lookupDimension(xmlCalcMember.dimension); 828 if (dimension == null) { 829 throw MondrianResource.instance().CalcMemberHasBadDimension.ex( 830 xmlCalcMember.dimension, xmlCalcMember.name, 831 getUniqueName()); 832 } 833 834 List<Formula> newCalcMemberList = new ArrayList<Formula>(); 840 for (Formula formula : calculatedMembers) { 841 if (formula.getName().equals(xmlCalcMember.name) && 842 formula.getMdxMember().getDimension().getName().equals( 843 dimension.getName())) { 844 if (errOnDup) { 845 throw MondrianResource.instance().CalcMemberNotUnique.ex( 846 Util.makeFqName(dimension, xmlCalcMember.name), 847 getUniqueName()); 848 } 849 continue; 850 } else { 851 newCalcMemberList.add(formula); 852 } 853 } 854 calculatedMembers = 855 newCalcMemberList.toArray(new Formula[newCalcMemberList.size()]); 856 857 for (int k = 0; k < j; k++) { 860 MondrianDef.CalculatedMember xmlCalcMember2 = xmlCalcMembers[k]; 861 if (xmlCalcMember2.name.equals(xmlCalcMember.name) && 862 xmlCalcMember2.dimension.equals(xmlCalcMember.dimension)) { 863 throw MondrianResource.instance().CalcMemberNotUnique.ex( 864 Util.makeFqName(dimension, xmlCalcMember.name), 865 getUniqueName()); 866 } 867 } 868 869 final String memberUniqueName = Util.makeFqName( 870 dimension.getUniqueName(), xmlCalcMember.name); 871 final MondrianDef.CalculatedMemberProperty[] xmlProperties = 872 xmlCalcMember.memberProperties; 873 List<String > propNames = new ArrayList<String >(); 874 List<String > propExprs = new ArrayList<String >(); 875 validateMemberProps(xmlProperties, propNames, propExprs, 876 xmlCalcMember.name); 877 878 final int measureCount = 879 cube.measuresHierarchy.getMemberReader().getMemberCount(); 880 881 assert memberUniqueName.startsWith("["); 883 buf.append("MEMBER ").append(memberUniqueName) 884 .append(Util.nl) 885 .append(" AS "); 886 Util.singleQuoteString(xmlCalcMember.getFormula(), buf); 887 888 assert propNames.size() == propExprs.size(); 889 processFormatStringAttribute(xmlCalcMember, buf); 890 891 for (int i = 0; i < propNames.size(); i++) { 892 String name = propNames.get(i); 893 String expr = propExprs.get(i); 894 buf.append(",").append(Util.nl) 895 .append(name).append(" = ").append(expr); 896 } 897 buf.append(",").append(Util.nl). 900 append(Util.quoteMdxIdentifier(Property.MEMBER_SCOPE.name)). 901 append(" = 'CUBE'"); 902 903 if (!propNames.contains(Property.MEMBER_ORDINAL.getName())) { 905 buf.append(",").append(Util.nl). 906 append(Property.MEMBER_ORDINAL).append(" = "). 907 append(measureCount + j); 908 } 909 buf.append(Util.nl); 910 } 911 912 void processFormatStringAttribute(MondrianDef.CalculatedMember xmlCalcMember, StringBuilder buf) { 913 if (xmlCalcMember.formatString != null) { 914 buf.append(",").append(Util.nl) 915 .append(Property.FORMAT_STRING.name).append(" = ").append(Util.quoteForMdx(xmlCalcMember.formatString)); 916 } 917 } 918 919 928 private void validateMemberProps( 929 final MondrianDef.CalculatedMemberProperty[] xmlProperties, 930 List<String > propNames, 931 List<String > propExprs, 932 String memberName) { 933 934 MemberProperty[] properties = new MemberProperty[xmlProperties.length]; 935 for (int i = 0; i < properties.length; i++) { 936 final MondrianDef.CalculatedMemberProperty xmlProperty = 937 xmlProperties[i]; 938 if (xmlProperty.expression == null && 939 xmlProperty.value == null) { 940 941 throw MondrianResource.instance() 942 .NeitherExprNorValueForCalcMemberProperty.ex( 943 xmlProperty.name, 944 memberName, 945 getUniqueName()); 946 } 947 if (xmlProperty.expression != null && 948 xmlProperty.value != null) { 949 950 throw MondrianResource.instance() 951 .ExprAndValueForMemberProperty.ex( 952 xmlProperty.name, 953 memberName, 954 getUniqueName()); 955 } 956 propNames.add(xmlProperty.name); 957 if (xmlProperty.expression != null) { 958 propExprs.add(xmlProperty.expression); 959 } else { 960 propExprs.add(Util.quoteForMdx(xmlProperty.value)); 961 } 962 } 963 } 964 965 966 public Schema getSchema() { 967 return schema; 968 } 969 970 977 public synchronized SchemaReader getSchemaReader() { 978 if (schemaReader == null) { 979 schemaReader = getSchemaReader(null); 980 } 981 return schemaReader; 982 } 983 984 public SchemaReader getSchemaReader(Role role) { 985 if (role == null) { 986 role = schema.getDefaultRole().makeMutableClone(); 987 role.grant(this, Access.ALL); 988 } 989 return new RolapCubeSchemaReader(role); 990 } 991 992 MondrianDef.CubeDimension lookup( 993 MondrianDef.CubeDimension[] xmlDimensions, 994 String name) { 995 for (MondrianDef.CubeDimension cd : xmlDimensions) { 996 if (name.equals(cd.name)) { 997 return cd; 998 } 999 } 1000 return null; 1002 } 1003 1004 private void init(MondrianDef.CubeDimension[] xmlDimensions) { 1005 int max = -1; 1006 for (Dimension dimension1 : dimensions) { 1007 final RolapDimension dimension = (RolapDimension) dimension1; 1008 1013 dimension.init(this, lookup(xmlDimensions, dimension.getName())); 1014 max = Math.max(max, dimension.getGlobalOrdinal()); 1015 } 1016 this.localDimensionOrdinals = new int[max + 1]; 1017 Arrays.fill(localDimensionOrdinals, -1); 1018 for (int i = 0; i < dimensions.length; i++) { 1019 final RolapDimension dimension = (RolapDimension) dimensions[i]; 1020 final int globalOrdinal = dimension.getGlobalOrdinal(); 1021 1028 localDimensionOrdinals[globalOrdinal] = i; 1029 } 1030 register(); 1031 } 1032 1033 private void register() { 1034 if (isVirtual()) { 1035 return; 1036 } 1037 List<Member> list = new ArrayList<Member>(); 1038 Member[] measures = getMeasures(); 1039 for (Member measure : measures) { 1040 if (measure instanceof RolapBaseCubeMeasure) { 1041 list.add(measure); 1042 } 1043 } 1044 RolapBaseCubeMeasure[] storedMeasures = 1045 list.toArray(new RolapBaseCubeMeasure[list.size()]); 1046 1047 RolapStar star = getStar(); 1048 RolapStar.Table table = star.getFactTable(); 1049 1050 for (RolapBaseCubeMeasure storedMeasure : storedMeasures) { 1052 table.makeMeasure(storedMeasure); 1053 } 1054 1055 Dimension[] dimensions = this.getDimensions(); 1057 for (Dimension dimension : dimensions) { 1058 registerDimension(dimension); 1059 } 1060 } 1061 1062 int getOrdinal(int globalOrdinal) { 1063 return this.localDimensionOrdinals[globalOrdinal]; 1064 } 1065 1066 CellReader getCellReader() { 1067 return this.cellReader; 1068 } 1069 1070 1076 public boolean isCacheAggregations() { 1077 return isVirtual() || star.isCacheAggregations(); 1078 } 1079 1080 1086 public void setCacheAggregations(boolean cache) { 1087 if (! isVirtual()) { 1088 star.setCacheAggregations(cache); 1089 } 1090 } 1091 1092 1096 public void clearCachedAggregations() { 1097 if (isVirtual()) { 1098 schema.flushRolapStarCaches(false); 1103 } else { 1104 star.clearCachedAggregations(false); 1105 } 1106 } 1107 1108 1111 public void checkAggregateModifications() { 1112 if (isVirtual()) { 1113 schema.checkAggregateModifications(); 1118 } else { 1119 star.checkAggregateModifications(); 1120 } 1121 } 1122 1126 public void pushAggregateModificationsToGlobalCache() { 1127 if (isVirtual()) { 1128 schema.pushAggregateModificationsToGlobalCache(); 1133 } else { 1134 star.pushAggregateModificationsToGlobalCache(); 1135 } 1136 } 1137 1138 1139 1140 1143 public RolapStar getStar() { 1144 return star; 1145 } 1146 1147 private void createUsages(RolapDimension dimension, 1148 MondrianDef.CubeDimension xmlCubeDimension) { 1149 RolapHierarchy[] hierarchies = 1155 (RolapHierarchy[]) dimension.getHierarchies(); 1156 1157 if (hierarchies.length == 1) { 1158 createUsage(hierarchies[0], xmlCubeDimension); 1160 1161 } else if ((xmlCubeDimension instanceof MondrianDef.DimensionUsage) && 1162 (((MondrianDef.DimensionUsage) xmlCubeDimension).level != null)) { 1163 MondrianDef.DimensionUsage du = 1167 (MondrianDef.DimensionUsage) xmlCubeDimension; 1168 1169 int cnt = 0; 1170 1171 for (RolapHierarchy hierarchy : hierarchies) { 1172 if (getLogger().isDebugEnabled()) { 1173 getLogger().debug("RolapCube<init>: hierarchy=" 1174 + hierarchy.getName()); 1175 } 1176 RolapLevel joinLevel = (RolapLevel) 1177 Util.lookupHierarchyLevel(hierarchy, du.level); 1178 if (joinLevel == null) { 1179 continue; 1180 } 1181 createUsage(hierarchy, xmlCubeDimension); 1182 cnt++; 1183 } 1184 1185 if (cnt == 0) { 1186 createUsage(hierarchies[0], xmlCubeDimension); 1189 } 1190 1191 } else { 1192 for (RolapHierarchy hierarchy : hierarchies) { 1194 if (getLogger().isDebugEnabled()) { 1195 getLogger().debug("RolapCube<init>: hierarchy=" 1196 + hierarchy.getName()); 1197 } 1198 createUsage(hierarchy, xmlCubeDimension); 1199 } 1200 } 1201 } 1202 1203 synchronized void createUsage( 1204 RolapHierarchy hierarchy, 1205 MondrianDef.CubeDimension cubeDim) { 1206 1207 HierarchyUsage usage = new HierarchyUsage(this, hierarchy, cubeDim); 1208 if (LOGGER.isDebugEnabled()) { 1209 LOGGER.debug("RolapCube.createUsage: "+ 1210 "cube=" +getName()+ 1211 ", hierarchy=" +hierarchy.getName() + 1212 ", usage=" +usage); 1213 } 1214 for (HierarchyUsage hierUsage : hierarchyUsages) { 1215 if (hierUsage.equals(usage)) { 1216 getLogger().warn( 1217 "RolapCube.createUsage: duplicate " + hierUsage); 1218 return; 1219 } 1220 } 1221 if (getLogger().isDebugEnabled()) { 1222 getLogger().debug("RolapCube.createUsage: register " +usage); 1223 } 1224 this.hierarchyUsages.add(usage); 1225 } 1226 1227 private synchronized HierarchyUsage getUsageByName(String name) { 1228 for (HierarchyUsage hierUsage : hierarchyUsages) { 1229 if (hierUsage.getFullName().equals(name)) { 1230 return hierUsage; 1231 } 1232 } 1233 return null; 1234 } 1235 1236 1245 public synchronized HierarchyUsage[] getUsages(Hierarchy hierarchy) { 1246 String name = hierarchy.getName(); 1247 if (getLogger().isDebugEnabled()) { 1248 getLogger().debug("RolapCube.getUsages: name="+name); 1249 } 1250 1251 HierarchyUsage hierUsage = null; 1252 List<HierarchyUsage> list = null; 1253 1254 for (HierarchyUsage hu : hierarchyUsages) { 1255 if (hu.getHierarchyName().equals(name)) { 1256 if (list != null) { 1257 if (getLogger().isDebugEnabled()) { 1258 getLogger().debug("RolapCube.getUsages: " 1259 + "add list HierarchyUsage.name=" + hu.getName()); 1260 } 1261 list.add(hu); 1262 } else if (hierUsage == null) { 1263 hierUsage = hu; 1264 } else { 1265 list = new ArrayList<HierarchyUsage>(); 1266 if (getLogger().isDebugEnabled()) { 1267 getLogger().debug("RolapCube.getUsages: " 1268 + "add list hierUsage.name=" 1269 + hierUsage.getName() 1270 + ", hu.name=" 1271 + hu.getName()); 1272 } 1273 list.add(hierUsage); 1274 list.add(hu); 1275 hierUsage = null; 1276 } 1277 } 1278 } 1279 if (hierUsage != null) { 1280 return new HierarchyUsage[] { hierUsage }; 1281 } else if (list != null) { 1282 if (getLogger().isDebugEnabled()) { 1283 getLogger().debug("RolapCube.getUsages: return list"); 1284 } 1285 return list.toArray(new HierarchyUsage[list.size()]); 1286 } else { 1287 return new HierarchyUsage[0]; 1288 } 1289 } 1290 1291 synchronized HierarchyUsage getFirstUsage(Hierarchy hier) { 1292 HierarchyUsage hierarchyUsage = firstUsageMap.get(hier); 1293 if (hierarchyUsage == null) { 1294 HierarchyUsage[] hierarchyUsages = getUsages(hier); 1295 if (hierarchyUsages.length != 0) { 1296 hierarchyUsage = hierarchyUsages[0]; 1297 firstUsageMap.put(hier, hierarchyUsage); 1298 } 1299 } 1300 return hierarchyUsage; 1301 } 1302 1303 1310 synchronized HierarchyUsage[] getUsagesBySource(String source) { 1311 if (getLogger().isDebugEnabled()) { 1312 getLogger().debug("RolapCube.getUsagesBySource: source="+source); 1313 } 1314 1315 HierarchyUsage hierUsage = null; 1316 List<HierarchyUsage> list = null; 1317 1318 for (HierarchyUsage hu : hierarchyUsages) { 1319 String s = hu.getSource(); 1320 if ((s != null) && s.equals(source)) { 1321 if (list != null) { 1322 if (getLogger().isDebugEnabled()) { 1323 getLogger().debug("RolapCube.getUsagesBySource: " 1324 + "add list HierarchyUsage.name=" 1325 + hu.getName()); 1326 } 1327 list.add(hu); 1328 } else if (hierUsage == null) { 1329 hierUsage = hu; 1330 } else { 1331 list = new ArrayList<HierarchyUsage>(); 1332 if (getLogger().isDebugEnabled()) { 1333 getLogger().debug("RolapCube.getUsagesBySource: " 1334 + "add list hierUsage.name=" 1335 + hierUsage.getName() 1336 + ", hu.name=" 1337 + hu.getName()); 1338 } 1339 list.add(hierUsage); 1340 list.add(hu); 1341 hierUsage = null; 1342 } 1343 } 1344 } 1345 if (hierUsage != null) { 1346 return new HierarchyUsage[] { hierUsage }; 1347 } else if (list != null) { 1348 if (getLogger().isDebugEnabled()) { 1349 getLogger().debug("RolapCube.getUsagesBySource: return list"); 1350 } 1351 return list.toArray(new HierarchyUsage[list.size()]); 1352 } else { 1353 return new HierarchyUsage[0]; 1354 } 1355 } 1356 1357 1358 1363 void registerDimension(Dimension dimension) { 1364 RolapStar star = getStar(); 1365 1366 Hierarchy[] hierarchies = dimension.getHierarchies(); 1367 1368 for (Hierarchy hierarchy1 : hierarchies) { 1369 RolapHierarchy hierarchy = (RolapHierarchy) hierarchy1; 1370 1371 MondrianDef.Relation relation = hierarchy.getRelation(); 1372 if (relation == null) { 1373 continue; } 1375 RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels(); 1376 1377 HierarchyUsage[] hierarchyUsages = getUsages(hierarchy); 1378 if (hierarchyUsages.length == 0) { 1379 if (getLogger().isDebugEnabled()) { 1380 StringBuilder buf = new StringBuilder (64); 1381 buf.append("RolapCube.registerDimension: "); 1382 buf.append("hierarchyUsages == null for cube=\""); 1383 buf.append(this.name); 1384 buf.append("\", hierarchy=\""); 1385 buf.append(hierarchy.getName()); 1386 buf.append("\""); 1387 getLogger().debug(buf.toString()); 1388 } 1389 continue; 1390 } 1391 1392 for (HierarchyUsage hierarchyUsage : hierarchyUsages) { 1393 String usagePrefix = hierarchyUsage.getUsagePrefix(); 1394 RolapStar.Table table = star.getFactTable(); 1395 1396 String levelName = hierarchyUsage.getLevelName(); 1397 1398 if (relation instanceof MondrianDef.Join) { 1415 1416 MondrianDef.Relation relationTmp1 = relation; 1419 1420 relation = reorder(relation, levels); 1421 1422 if (relation == null && getLogger().isDebugEnabled()) { 1423 getLogger().debug( 1424 "RolapCube.registerDimension: after reorder relation==null"); 1425 getLogger().debug( 1426 "RolapCube.registerDimension: reorder relationTmp1=" 1427 + format(relationTmp1)); 1428 } 1429 } 1430 1431 MondrianDef.Relation relationTmp2 = relation; 1432 1433 if (levelName != null) { 1434 1440 RolapLevel level = 1442 RolapLevel.lookupLevel(levels, levelName); 1443 if (level == null) { 1444 StringBuilder buf = new StringBuilder (64); 1445 buf.append("For cube \""); 1446 buf.append(getName()); 1447 buf.append("\" and HierarchyUsage ["); 1448 buf.append(hierarchyUsage); 1449 buf.append("], there is no level with given"); 1450 buf.append(" level name \""); 1451 buf.append(levelName); 1452 buf.append("\""); 1453 throw Util.newInternal(buf.toString()); 1454 } 1455 1456 if (relation instanceof MondrianDef.Join) { 1463 RolapLevel childLevel = 1464 (RolapLevel) level.getChildLevel(); 1465 if (childLevel != null) { 1466 String tableName = childLevel.getTableName(); 1467 if (tableName != null) { 1468 relation = snip(relation, tableName); 1469 1470 if (relation == null && 1471 getLogger().isDebugEnabled()) { 1472 getLogger().debug( 1473 "RolapCube.registerDimension: after snip relation==null"); 1474 getLogger().debug( 1475 "RolapCube.registerDimension: snip relationTmp2=" 1476 + format(relationTmp2)); 1477 } 1478 } 1479 } 1480 } 1481 1482 } 1483 1484 if (!relation.equals(table.getRelation())) { 1486 if (hierarchyUsage.getForeignKey() == null) { 1488 throw MondrianResource.instance() 1489 .HierarchyMustHaveForeignKey.ex( 1490 hierarchy.getName(), getName()); 1491 } 1492 if (false && 1494 !star.getFactTable() 1495 .containsColumn(hierarchyUsage.getForeignKey())) { 1496 throw MondrianResource.instance() 1497 .HierarchyInvalidForeignKey.ex( 1498 hierarchyUsage.getForeignKey(), 1499 hierarchy.getName(), 1500 getName()); 1501 } 1502 MondrianDef.Column column = 1506 new MondrianDef.Column(table.getAlias(), 1507 hierarchyUsage.getForeignKey()); 1508 RolapStar.Condition joinCondition = 1512 new RolapStar.Condition(column, 1513 hierarchyUsage.getJoinExp()); 1514 1515 table = table.addJoin(relation, joinCondition); 1516 } 1517 1518 RolapStar.Column parentColumn = null; 1523 1524 if (levelName != null) { 1528 for (RolapLevel level : levels) { 1529 if (level.getKeyExp() != null) { 1530 parentColumn = makeColumns(table, 1531 level, parentColumn, usagePrefix); 1532 } 1533 if (levelName.equals(level.getName())) { 1534 break; 1535 } 1536 } 1537 } else { 1538 for (RolapLevel level : levels) { 1541 if (level.getKeyExp() != null) { 1542 parentColumn = makeColumns(table, 1543 level, parentColumn, usagePrefix); 1544 } 1545 } 1546 } 1547 } 1548 } 1549 } 1550 1551 1556 protected RolapStar.Column makeColumns( 1557 RolapStar.Table table, 1558 RolapLevel level, 1559 RolapStar.Column parentColumn, 1560 String usagePrefix) { 1561 1562 String tableName = level.getTableName(); 1572 if (tableName != null) { 1573 if (table.getAlias().equals(tableName)) { 1574 parentColumn = table.makeColumns(this, level, 1575 parentColumn, usagePrefix); 1576 } else if (table.equalsTableName(tableName)) { 1577 parentColumn = table.makeColumns(this, level, 1578 parentColumn, usagePrefix); 1579 } else { 1580 RolapStar.Table t = table.findAncestor(tableName); 1581 if (t != null) { 1582 parentColumn = t.makeColumns(this, level, 1583 parentColumn, usagePrefix); 1584 } else { 1585 StringBuilder buf = new StringBuilder (64); 1587 buf.append("RolapCube.makeColumns: for cube \""); 1588 buf.append(getName()); 1589 buf.append("\" the Level \""); 1590 buf.append(level.getName()); 1591 buf.append("\" has a table name attribute \""); 1592 buf.append(tableName); 1593 buf.append("\" but the associated RolapStar does not"); 1594 buf.append(" have a table with that name."); 1595 getLogger().warn(buf.toString()); 1596 1597 parentColumn = table.makeColumns(this, level, 1598 parentColumn, usagePrefix); 1599 } 1600 } 1601 } else { 1602 parentColumn = table.makeColumns(this, level, 1605 parentColumn, usagePrefix); 1606 } 1607 1608 return parentColumn; 1609 } 1610 1611 1617 1623 private static String format(MondrianDef.Relation relation) { 1624 StringBuilder buf = new StringBuilder (); 1625 format(relation, buf, ""); 1626 return buf.toString(); 1627 } 1628 1629 private static void format( 1630 MondrianDef.Relation relation, 1631 StringBuilder buf, String indent) { 1632 if (relation instanceof MondrianDef.Table) { 1633 MondrianDef.Table table = (MondrianDef.Table) relation; 1634 1635 buf.append(indent); 1636 buf.append(table.name); 1637 if (table.alias != null) { 1638 buf.append('('); 1639 buf.append(table.alias); 1640 buf.append(')'); 1641 } 1642 buf.append(Util.nl); 1643 } else { 1644 MondrianDef.Join join = (MondrianDef.Join) relation; 1645 String subindent = indent + " "; 1646 1647 buf.append(indent); 1648 buf.append(join.getLeftAlias()); 1650 buf.append('.'); 1651 buf.append(join.leftKey); 1652 buf.append('='); 1653 buf.append(join.getRightAlias()); 1654 buf.append('.'); 1656 buf.append(join.rightKey); 1657 buf.append(Util.nl); 1658 format(join.left, buf, subindent); 1659 format(join.right, buf, indent); 1660 } 1661 } 1662 1663 1670 private static class RelNode { 1671 1672 1679 private static RelNode lookup(MondrianDef.Table table, Map<String , RelNode> map) { 1680 RelNode relNode = map.get(table.name); 1681 if ((relNode == null) && (table.alias != null)) { 1682 relNode = map.get(table.alias); 1683 } 1684 return relNode; 1685 } 1686 1687 private int depth; 1688 private String alias; 1689 private MondrianDef.Table table; 1690 RelNode(String alias, int depth) { 1691 this.alias = alias; 1692 this.depth = depth; 1693 } 1694 1695 } 1696 1697 1807 private static MondrianDef.Relation reorder( 1808 MondrianDef.Relation relation, 1809 RolapLevel[] levels) { 1810 if (levels.length < 2) { 1812 return relation; 1813 } 1814 1815 Map<String , RelNode> nodeMap = new HashMap<String , RelNode>(); 1816 1817 for (int i = 0; i < levels.length; i++) { 1819 RolapLevel level = levels[i]; 1820 1821 if (level.isAll()) { 1822 continue; 1823 } 1824 1825 String tableName = level.getTableName(); 1827 if (tableName == null) { 1828 return relation; 1830 } 1831 RelNode rnode = new RelNode(tableName, i); 1832 nodeMap.put(tableName, rnode); 1833 } 1834 if (! validateNodes(relation, nodeMap)) { 1835 return relation; 1836 } 1837 relation = copy(relation); 1838 1839 leftToRight(relation, nodeMap); 1841 1842 topToBottom(relation); 1844 1845 return relation; 1846 } 1847 1848 1856 private static boolean validateNodes( 1857 MondrianDef.Relation relation, 1858 Map<String , RelNode> map) 1859 { 1860 if (relation instanceof MondrianDef.Table) { 1861 MondrianDef.Table table = (MondrianDef.Table) relation; 1862 1863 RelNode relNode = RelNode.lookup(table, map); 1864 return (relNode != null); 1865 1866 } else if (relation instanceof MondrianDef.Join) { 1867 MondrianDef.Join join = (MondrianDef.Join) relation; 1868 1869 return validateNodes(join.left, map) && 1870 validateNodes(join.right, map); 1871 1872 } else { 1873 throw Util.newInternal("bad relation type " + relation); 1874 } 1875 1876 } 1877 1878 1886 private static int leftToRight( 1887 MondrianDef.Relation relation, 1888 Map<String , RelNode> map) 1889 { 1890 if (relation instanceof MondrianDef.Table) { 1891 MondrianDef.Table table = (MondrianDef.Table) relation; 1892 1893 RelNode relNode = RelNode.lookup(table, map); 1894 relNode.table = table; 1897 1898 return relNode.depth; 1899 1900 } else if (relation instanceof MondrianDef.Join) { 1901 MondrianDef.Join join = (MondrianDef.Join) relation; 1902 int leftDepth = leftToRight(join.left, map); 1903 int rightDepth = leftToRight(join.right, map); 1904 1905 if (rightDepth > leftDepth) { 1907 String leftAlias = join.leftAlias; 1909 String leftKey = join.leftKey; 1910 MondrianDef.Relation left = join.left; 1911 join.leftAlias = join.rightAlias; 1912 join.leftKey = join.rightKey; 1913 join.left = join.right; 1914 join.rightAlias = leftAlias; 1915 join.rightKey = leftKey; 1916 join.right = left; 1917 } 1918 return leftDepth; 1924 1925 } else { 1926 throw Util.newInternal("bad relation type " + relation); 1927 } 1928 1929 } 1930 1931 1937 private static void topToBottom(MondrianDef.Relation relation) { 1938 if (relation instanceof MondrianDef.Table) { 1939 1941 } else if (relation instanceof MondrianDef.Join) { 1942 MondrianDef.Join join = (MondrianDef.Join) relation; 1943 1944 while (join.left instanceof MondrianDef.Join) { 1945 MondrianDef.Join jleft = (MondrianDef.Join) join.left; 1946 1947 join.right = new MondrianDef.Join( 1948 join.leftAlias, 1949 join.leftKey, 1950 jleft.right, 1951 join.rightAlias, 1952 join.rightKey, 1953 join.right); 1954 1955 join.left = jleft.left; 1956 1957 join.rightAlias = jleft.rightAlias; 1958 join.rightKey = jleft.rightKey; 1959 join.leftAlias = jleft.leftAlias; 1960 join.leftKey = jleft.leftKey; 1961 } 1962 } 1963 1964 } 1965 1966 1971 private static MondrianDef.Relation copy(MondrianDef.Relation relation) { 1972 if (relation instanceof MondrianDef.Table) { 1973 MondrianDef.Table table = (MondrianDef.Table) relation; 1974 return new MondrianDef.Table(table); 1975 1976 } else if (relation instanceof MondrianDef.Join) { 1977 MondrianDef.Join join = (MondrianDef.Join) relation; 1978 1979 MondrianDef.Relation left = copy(join.left); 1980 MondrianDef.Relation right = copy(join.right); 1981 1982 return new MondrianDef.Join(join.leftAlias, join.leftKey, left, 1983 join.rightAlias, join.rightKey, right); 1984 1985 } else { 1986 throw Util.newInternal("bad relation type " + relation); 1987 } 1988 } 1989 1990 1998 private static MondrianDef.Relation snip( 1999 MondrianDef.Relation relation, 2000 String tableName) { 2001 if (relation instanceof MondrianDef.Table) { 2002 MondrianDef.Table table = (MondrianDef.Table) relation; 2003 return ((table.alias != null) && table.alias.equals(tableName)) 2005 ? null 2006 : (table.name.equals(tableName) ? null : table); 2007 2008 } else if (relation instanceof MondrianDef.Join) { 2009 MondrianDef.Join join = (MondrianDef.Join) relation; 2010 2011 MondrianDef.Relation left = snip(join.left, tableName); 2013 if (left == null) { 2014 return join.right; 2017 2018 } else { 2019 join.left = left; 2021 2022 MondrianDef.Relation right = snip(join.right, tableName); 2024 if (right == null) { 2025 return join.left; 2027 2028 } else { 2029 join.right = right; 2032 return join; 2033 } 2034 } 2035 2036 2037 } else { 2038 throw Util.newInternal("bad relation type " + relation); 2039 } 2040 2041 } 2042 2045 2046 2047 public Member[] getMembersForQuery(String query, List<Member> calcMembers) { 2048 throw new UnsupportedOperationException (); 2049 } 2050 2051 Member[] getMeasures() { 2052 Level measuresLevel = dimensions[0].getHierarchies()[0].getLevels()[0]; 2053 return getSchemaReader().getLevelMembers(measuresLevel, true); 2054 } 2055 2056 2059 MondrianDef.Relation getFact() { 2060 return fact; 2061 } 2062 2063 2067 public boolean isVirtual() { 2068 return (fact == null); 2069 } 2070 2071 RolapDimension createDimension(MondrianDef.CubeDimension xmlCubeDimension) { 2072 MondrianDef.Dimension xmlDimension; 2073 final RolapDimension dimension; 2074 if (xmlCubeDimension instanceof MondrianDef.Dimension) { 2075 xmlDimension = (MondrianDef.Dimension) xmlCubeDimension; 2076 dimension = new RolapDimension(schema, this, xmlDimension, 2077 xmlCubeDimension); 2078 } else if (xmlCubeDimension instanceof MondrianDef.DimensionUsage) { 2079 final MondrianDef.DimensionUsage usage = 2080 (MondrianDef.DimensionUsage) xmlCubeDimension; 2081 final RolapHierarchy sharedHierarchy = 2082 schema.getSharedHierarchy(usage.source); 2083 if (sharedHierarchy == null) { 2084 throw Util.newInternal("todo: Shared hierarchy '" + usage.source + 2085 "' not found"); 2086 } 2087 2088 final RolapDimension sharedDimension = 2089 (RolapDimension) sharedHierarchy.getDimension(); 2090 dimension = sharedDimension.copy(this, usage.name, 2091 xmlCubeDimension); 2092 } else { 2093 throw Util.newInternal("Unexpected subtype, " + xmlCubeDimension); 2094 } 2095 2096 dimension.init(this, xmlCubeDimension); 2097 final int localOrdinal = dimensions.length; 2099 this.dimensions = (DimensionBase[]) 2100 RolapUtil.addElement(dimensions, dimension); 2101 2102 RolapHierarchy hierarchy = (RolapHierarchy) dimension.getHierarchy(); 2103 createUsage(hierarchy, xmlCubeDimension); 2104 2105 2106 final int globalOrdinal = dimension.getGlobalOrdinal(); 2108 if (globalOrdinal >= localDimensionOrdinals.length) { 2109 int[] newLocalDimensionOrdinals = new int[globalOrdinal + 1]; 2110 System.arraycopy(localDimensionOrdinals, 0, 2111 newLocalDimensionOrdinals, 0, localDimensionOrdinals.length); 2112 Arrays.fill(newLocalDimensionOrdinals, 2113 localDimensionOrdinals.length, 2114 newLocalDimensionOrdinals.length, -1); 2115 this.localDimensionOrdinals = newLocalDimensionOrdinals; 2116 } 2117 Util.assertTrue(localDimensionOrdinals[globalOrdinal] == -1); 2118 localDimensionOrdinals[globalOrdinal] = localOrdinal; 2119 registerDimension(dimension); 2120 return dimension; 2121 } 2122 2123 public OlapElement lookupChild(SchemaReader schemaReader, String s) { 2124 return lookupChild(schemaReader, s, MatchType.EXACT); 2125 } 2126 2127 public OlapElement lookupChild( 2128 SchemaReader schemaReader, String s, MatchType matchType) 2129 { 2130 OlapElement oe; 2133 String status = null; 2134 if (s.equals("Measures")) { 2135 oe = super.lookupChild(schemaReader, s, MatchType.EXACT); 2140 2141 } else { 2142 2158 HierarchyUsage hierUsage = getUsageByName(s); 2159 2160 if (hierUsage == null) { 2161 oe = super.lookupChild(schemaReader, s, MatchType.EXACT); 2162 status = "hierUsage == null"; 2163 2164 if (oe instanceof RolapDimension) { 2167 HierarchyUsage[] usages = getUsagesBySource(s); 2168 2169 if (usages.length > 0) { 2170 StringBuilder buf = new StringBuilder (64); 2171 buf.append("RolapCube.lookupChild: "); 2172 buf.append("In cube \""); 2173 buf.append(getName()); 2174 buf.append("\" use of unaliased Dimension name \""); 2175 buf.append(s); 2176 2177 if (usages.length == 1) { 2178 buf.append("\" rather than the alias name "); 2180 buf.append("\""); 2181 buf.append(usages[0].getName()); 2182 buf.append("\" "); 2183 getLogger().error(buf.toString()); 2184 throw new MondrianException(buf.toString()); 2185 } else { 2186 buf.append("\" rather than one of the alias names "); 2188 for (HierarchyUsage usage : usages) { 2189 buf.append("\""); 2190 buf.append(usage.getName()); 2191 buf.append("\" "); 2192 } 2193 getLogger().error(buf.toString()); 2194 throw new MondrianException(buf.toString()); 2195 } 2196 } 2197 } 2198 } else if (hierUsage.isShared()) { 2199 status = "hierUsage == shared"; 2200 String source = hierUsage.getSource(); 2202 oe = super.lookupChild(schemaReader, source, MatchType.EXACT); 2203 2204 } else { 2205 status = "hierUsage == not shared"; 2206 oe = super.lookupChild(schemaReader, s, MatchType.EXACT); 2208 } 2209 } 2210 if (getLogger().isDebugEnabled()) { 2211 StringBuilder buf = new StringBuilder (64); 2212 buf.append("RolapCube.lookupChild: "); 2213 buf.append("name="); 2214 buf.append(getName()); 2215 buf.append(", childname="); 2216 buf.append(s); 2217 if (status != null) { 2218 buf.append(", status="); 2219 buf.append(status); 2220 } 2221 if (oe == null) { 2222 buf.append(" returning null"); 2223 } else { 2224 buf.append(" returning elementname=").append(oe.getName()); 2225 } 2226 getLogger().debug(buf.toString()); 2227 } 2228 2229 return oe; 2230 } 2231 2232 2235 public Hierarchy getMeasuresHierarchy(){ 2236 return measuresHierarchy; 2237 } 2238 2239 public RolapMember[] getMeasuresMembers(){ 2241 return measuresHierarchy.getMemberReader().getMembers(); 2242 } 2243 2244 public Member createCalculatedMember(String xml) { 2245 MondrianDef.CalculatedMember xmlCalcMember; 2246 try { 2247 final Parser xmlParser = XOMUtil.createDefaultParser(); 2248 final DOMWrapper def = xmlParser.parse(xml); 2249 final String tagName = def.getTagName(); 2250 if (tagName.equals("CalculatedMember")) { 2251 xmlCalcMember = new MondrianDef.CalculatedMember(def); 2252 } else { 2253 throw new XOMException("Got <" + tagName + 2254 "> when expecting <CalculatedMember>"); 2255 } 2256 } catch (XOMException e) { 2257 throw Util.newError(e, 2258 "Error while creating calculated member from XML [" + 2259 xml + "]"); 2260 } 2261 2262 final ArrayList<Member> memberList = new ArrayList<Member>(); 2263 createCalcMembersAndNamedSets( 2264 new MondrianDef.CalculatedMember[] {xmlCalcMember}, 2265 new MondrianDef.NamedSet[0], 2266 memberList, 2267 new ArrayList<Formula>(), 2268 this, 2269 true); 2270 assert memberList.size() == 1; 2271 return memberList.get(0); 2272 } 2273 2274 2279 private class RolapCubeSchemaReader extends RolapSchemaReader { 2280 public RolapCubeSchemaReader(Role role) { 2281 super(role, schema); 2282 assert role != null : "precondition: role != null"; 2283 } 2284 2285 public Member[] getLevelMembers( 2286 Level level, boolean includeCalculated) { 2287 Member[] members = super.getLevelMembers(level, false); 2288 if (includeCalculated) { 2289 members = Util.addLevelCalculatedMembers(this, level, members); 2290 } 2291 return members; 2292 } 2293 2294 2295 public Member getCalculatedMember(String [] nameParts) { 2296 final String uniqueName = Util.implode(nameParts); 2297 for (Formula formula : calculatedMembers) { 2298 final String formulaUniqueName = 2299 formula.getMdxMember().getUniqueName(); 2300 if (formulaUniqueName.equals(uniqueName) && 2301 getRole().canAccess(formula.getMdxMember())) 2302 { 2303 return formula.getMdxMember(); 2304 } 2305 } 2306 return null; 2307 } 2308 2309 public NamedSet getNamedSet(String [] nameParts) { 2310 if (nameParts.length == 1) { 2311 String name = nameParts[0]; 2312 for (Formula namedSet : namedSets) { 2313 if (namedSet.getName().equals(name)) { 2314 return namedSet.getNamedSet(); 2315 } 2316 } 2317 } 2318 return super.getNamedSet(nameParts); 2319 } 2320 2321 public List<Member> getCalculatedMembers(Hierarchy hierarchy) { 2322 ArrayList<Member> list = new ArrayList<Member>(); 2323 2324 if (getRole().getAccess(hierarchy) == Access.NONE) { 2325 return list; 2326 } 2327 2328 for (Formula formula : calculatedMembers) { 2329 Member member = formula.getMdxMember(); 2330 if (member.getHierarchy().equals(hierarchy) && 2331 getRole().canAccess(member)) { 2332 list.add(member); 2333 } 2334 } 2335 return list; 2336 } 2337 2338 public List<Member> getCalculatedMembers(Level level) { 2339 List<Member> list = new ArrayList<Member>(); 2340 2341 if (getRole().getAccess(level) == Access.NONE) { 2342 return list; 2343 } 2344 2345 for (Member member : getCalculatedMembers(level.getHierarchy())) { 2346 if (member.getLevel().equals(level) && 2347 getRole().canAccess(member)) { 2348 list.add(member); 2349 } 2350 } 2351 return list; 2352 } 2353 2354 public List<Member> getCalculatedMembers() { 2355 List<Member> list = new ArrayList<Member>(); 2356 for (Formula formula : calculatedMembers) { 2357 Member member = formula.getMdxMember(); 2358 if (getRole().canAccess(member)) { 2359 list.add(member); 2360 } 2361 } 2362 return list; 2363 } 2364 2365 public Member getMemberByUniqueName( 2366 String [] uniqueNameParts, boolean failIfNotFound) 2367 { 2368 return getMemberByUniqueName( 2369 uniqueNameParts, failIfNotFound, MatchType.EXACT); 2370 } 2371 2372 public Member getMemberByUniqueName( 2373 String [] uniqueNameParts, boolean failIfNotFound, 2374 MatchType matchType) 2375 { 2376 Member member = (Member) lookupCompound( 2377 RolapCube.this, uniqueNameParts, 2378 failIfNotFound, Category.Member, 2379 matchType); 2380 if (!failIfNotFound && member == null) { 2381 return null; 2382 } 2383 if (getRole().canAccess(member)) { 2384 return member; 2385 } else { 2386 return null; 2387 } 2388 } 2389 2390 public Cube getCube() { 2391 return RolapCube.this; 2392 } 2393 } 2394 2395 2404 private class MeasureFinder extends MdxVisitorImpl 2405 { 2406 2410 private RolapCube virtualCube; 2411 2412 2415 private RolapCube baseCube; 2416 2417 2420 private RolapLevel measuresLevel; 2421 2422 2425 private List<RolapVirtualCubeMeasure> measuresFound; 2426 2427 2430 private List<RolapCalculatedMember> calcMembersSeen; 2431 2432 public MeasureFinder( 2433 RolapCube virtualCube, 2434 RolapCube baseCube, 2435 RolapLevel measuresLevel) 2436 { 2437 this.virtualCube = virtualCube; 2438 this.baseCube = baseCube; 2439 this.measuresLevel = measuresLevel; 2440 this.measuresFound = new ArrayList<RolapVirtualCubeMeasure>(); 2441 this.calcMembersSeen = new ArrayList<RolapCalculatedMember>(); 2442 } 2443 2444 public Object visit(MemberExpr memberExpr) 2445 { 2446 Member member = memberExpr.getMember(); 2447 if (member instanceof RolapCalculatedMember) { 2448 if (calcMembersSeen.contains(member)) { 2451 return null; 2452 } 2453 RolapCalculatedMember calcMember = 2454 (RolapCalculatedMember) member; 2455 Formula formula = calcMember.getFormula(); 2456 formula.accept(this); 2457 calcMembersSeen.add(calcMember); 2458 2459 RolapMember[] measures = (RolapMember[]) 2463 measuresFound.toArray( 2464 new RolapMember[measuresFound.size()]); 2465 virtualCube.measuresHierarchy.setMemberReader( 2466 new CacheMemberReader( 2467 new MeasureMemberSource( 2468 virtualCube.measuresHierarchy, measures))); 2469 MondrianDef.CalculatedMember xmlCalcMember = 2470 schema.lookupXmlCalculatedMember( 2471 calcMember.getUniqueName(), 2472 baseCube.name); 2473 createCalcMembersAndNamedSets( 2474 new MondrianDef.CalculatedMember [] { xmlCalcMember }, 2475 new MondrianDef.NamedSet[0], 2476 new ArrayList<Member>(), 2477 new ArrayList<Formula>(), 2478 virtualCube, 2479 false); 2480 return null; 2481 2482 } else if (member instanceof RolapBaseCubeMeasure) { 2483 RolapBaseCubeMeasure baseMeasure = 2484 (RolapBaseCubeMeasure) member; 2485 RolapVirtualCubeMeasure virtualCubeMeasure = 2486 new RolapVirtualCubeMeasure( 2487 null, 2488 measuresLevel, 2489 baseMeasure); 2490 if (!measuresFound.contains(virtualCubeMeasure)) { 2491 measuresFound.add(virtualCubeMeasure); 2492 } 2493 } 2494 2495 return null; 2496 } 2497 2498 public List<RolapVirtualCubeMeasure> getMeasuresFound() 2499 { 2500 return measuresFound; 2501 } 2502 } 2503 2504 private class CubeComparator implements Comparator<RolapCube> 2505 { 2506 public int compare(RolapCube c1, RolapCube c2) 2507 { 2508 return c1.getName().compareTo(c2.getName()); 2509 } 2510 } 2511} 2512 2513 | Popular Tags |