1 10 package mondrian.rolap; 11 12 import mondrian.olap.*; 13 import mondrian.olap.fun.FunUtil; 14 import mondrian.resource.MondrianResource; 15 import mondrian.rolap.sql.MemberChildrenConstraint; 16 import mondrian.rolap.sql.SqlQuery; 17 import mondrian.rolap.sql.TupleConstraint; 18 19 import javax.sql.DataSource ; 20 import java.sql.ResultSet ; 21 import java.sql.SQLException ; 22 import java.util.*; 23 24 63 public class SqlTupleReader implements TupleReader { 64 TupleConstraint constraint; 65 List<Target> targets = new ArrayList<Target>(); 66 int maxRows = 0; 67 68 71 private class Target { 72 final RolapLevel level; 73 final MemberCache cache; 74 75 RolapLevel[] levels; 76 List<RolapMember> list; 77 int levelDepth; 78 boolean parentChild; 79 RolapMember[] members; 80 List<RolapMember>[] siblings; 81 final MemberBuilder memberBuilder; 82 private final RolapMember[] srcMembers; 85 private RolapMember currMember; 88 89 public Target( 90 RolapLevel level, MemberBuilder memberBuilder, 91 RolapMember[] srcMembers) { 92 this.level = level; 93 this.cache = memberBuilder.getMemberCache(); 94 this.memberBuilder = memberBuilder; 95 this.srcMembers = srcMembers; 96 } 97 98 public void open() { 99 levels = (RolapLevel[]) level.getHierarchy().getLevels(); 100 list = new ArrayList<RolapMember>(); 101 levelDepth = level.getDepth(); 102 parentChild = level.isParentChild(); 103 members = new RolapMember[levels.length]; 106 siblings = new List[levels.length + 1]; 107 } 108 109 119 public int addRow(ResultSet resultSet, int column) throws SQLException { 120 synchronized (cache) { 121 return internalAddRow(resultSet, column); 122 } 123 } 124 125 private int internalAddRow(ResultSet resultSet, int column) throws SQLException { 126 RolapMember member = null; 127 if (currMember != null) { 128 member = currMember; 129 } else { 130 boolean checkCacheStatus=true; 131 for (int i = 0; i <= levelDepth; i++) { 132 RolapLevel childLevel = levels[i]; 133 if (childLevel.isAll()) { 134 member = level.getHierarchy().getAllMember(); 135 continue; 136 } 137 Object value = resultSet.getObject(++column); 138 if (value == null) { 139 value = RolapUtil.sqlNullValue; 140 } 141 Object captionValue; 142 if (childLevel.hasCaptionColumn()) { 143 captionValue = resultSet.getObject(++column); 144 } else { 145 captionValue = null; 146 } 147 RolapMember parentMember = member; 148 Object key = cache.makeKey(parentMember, value); 149 member = cache.getMember(key, checkCacheStatus); 150 checkCacheStatus = false; 151 if (member == null) { 152 member = memberBuilder.makeMember( 153 parentMember, childLevel, value, captionValue, 154 parentChild, resultSet, key, column); 155 } 156 157 if (!childLevel.getOrdinalExp().equals(childLevel.getKeyExp())) { 159 ++column; 160 } 161 column += childLevel.getProperties().length; 162 163 if (member != members[i]) { 164 List<RolapMember> children = siblings[i + 1]; 166 if (children != null) { 167 MemberChildrenConstraint mcc = constraint 168 .getMemberChildrenConstraint(members[i]); 169 if (mcc != null) 170 cache.putChildren(members[i], mcc, children); 171 } 172 MemberChildrenConstraint mcc = constraint 176 .getMemberChildrenConstraint(member); 177 List cachedChildren = cache.getChildrenFromCache(member, mcc); 179 if (i < levelDepth && cachedChildren == null) { 180 siblings[i + 1] = new ArrayList<RolapMember>(); 181 } else { 182 siblings[i + 1] = null; } 184 members[i] = member; 186 if (siblings[i] != null) { 189 if (value == RolapUtil.sqlNullValue) { 190 addAsOldestSibling(siblings[i], member); 191 } else { 192 siblings[i].add(member); 193 } 194 } 195 } 196 } 197 currMember = member; 198 } 199 list.add(member); 200 return column; 201 } 202 203 public List<RolapMember> close() { 204 synchronized (cache) { 205 return internalClose(); 206 } 207 } 208 209 215 public List<RolapMember> internalClose() { 216 for (int i = 0; i < members.length; i++) { 217 RolapMember member = members[i]; 218 final List<RolapMember> children = siblings[i + 1]; 219 if (member != null && children != null) { 220 MemberChildrenConstraint mcc = 221 constraint.getMemberChildrenConstraint(member); 222 if (mcc != null) { 223 cache.putChildren(member, mcc, children); 224 } 225 } 226 } 227 return list; 228 } 229 230 234 private void addAsOldestSibling(List<RolapMember> list, RolapMember member) { 235 int i = list.size(); 236 while (--i >= 0) { 237 RolapMember sibling = list.get(i); 238 if (sibling.getParentMember() != member.getParentMember()) { 239 break; 240 } 241 } 242 list.add(i + 1, member); 243 } 244 245 public RolapLevel getLevel() { 246 return level; 247 } 248 249 public String toString() { 250 return level.getUniqueName(); 251 } 252 253 } 254 255 public SqlTupleReader(TupleConstraint constraint) { 256 this.constraint = constraint; 257 } 258 259 public void addLevelMembers( 260 RolapLevel level, 261 MemberBuilder memberBuilder, 262 RolapMember[] srcMembers) 263 { 264 targets.add(new Target(level, memberBuilder, srcMembers)); 265 } 266 267 public Object getCacheKey() { 268 List<Object > key = new ArrayList<Object >(); 269 key.add(constraint.getCacheKey()); 270 key.add(SqlTupleReader.class); 271 for (Target target : targets) { 272 if (target.srcMembers != null) { 275 key.add(target.getLevel()); 276 } 277 } 278 return key; 279 } 280 281 285 public int getEnumTargetCount() 286 { 287 int enumTargetCount = 0; 288 for (Target target : targets) { 289 if (target.srcMembers != null) { 290 enumTargetCount++; 291 } 292 } 293 return enumTargetCount; 294 } 295 296 private void prepareTuples( 297 DataSource dataSource, 298 List<List<RolapMember>> partialResult, 299 List<List<RolapMember>> newPartialResult) 300 { 301 String message = "Populating member cache with members for " + targets; 302 SqlStatement stmt = null; 303 final ResultSet resultSet; 304 boolean execQuery = (partialResult == null); 305 try { 306 if (execQuery) { 307 List<Target> partialTargets = new ArrayList<Target>(); 310 for (Target target : targets) { 311 if (target.srcMembers == null) { 312 partialTargets.add(target); 313 } 314 } 315 String sql = makeLevelMembersSql(dataSource); 316 stmt = RolapUtil.executeQuery( 317 dataSource, sql, maxRows, 318 "SqlTupleReader.readTuples " + partialTargets, 319 message, 320 -1, -1); 321 resultSet = stmt.getResultSet(); 322 } else { 323 resultSet = null; 324 } 325 326 for (Target target : targets) { 327 target.open(); 328 } 329 330 int limit = MondrianProperties.instance().ResultLimit.get(); 331 int fetchCount = 0; 332 333 int enumTargetCount = getEnumTargetCount(); 335 int[] srcMemberIdxes = null; 336 if (enumTargetCount > 0) { 337 srcMemberIdxes = new int[enumTargetCount]; 338 } 339 340 boolean moreRows; 341 int currPartialResultIdx = 0; 342 if (execQuery) { 343 moreRows = resultSet.next(); 344 ++stmt.rowCount; 345 } else { 346 moreRows = currPartialResultIdx < partialResult.size(); 347 } 348 while (moreRows) { 349 350 if (limit > 0 && limit < ++fetchCount) { 351 throw MondrianResource.instance().MemberFetchLimitExceeded 353 .ex((long) limit); 354 } 355 356 if (enumTargetCount == 0) { 357 int column = 0; 358 for (Target target : targets) { 359 target.currMember = null; 360 column = 361 target.addRow(resultSet, column); 362 } 363 } else { 364 int firstEnumTarget = 0; 369 for ( ; firstEnumTarget < targets.size(); 370 firstEnumTarget++) 371 { 372 if (targets.get(firstEnumTarget). 373 srcMembers != null) { 374 break; 375 } 376 } 377 List<RolapMember> partialRow; 378 if (execQuery) { 379 partialRow = null; 380 } else { 381 partialRow = partialResult.get(currPartialResultIdx); 382 } 383 resetCurrMembers(partialRow); 384 addTargets( 385 0, firstEnumTarget, enumTargetCount, srcMemberIdxes, 386 resultSet, message); 387 if (newPartialResult != null) { 388 savePartialResult(newPartialResult); 389 } 390 } 391 392 if (execQuery) { 393 moreRows = resultSet.next(); 394 } else { 395 currPartialResultIdx++; 396 moreRows = currPartialResultIdx < partialResult.size(); 397 } 398 } 399 } catch (Exception e) { 400 if (stmt == null) { 401 throw Util.newError(e, message); 402 } else { 403 stmt.handle(e); 404 } 405 } finally { 406 if (stmt != null) { 407 stmt.close(); 408 } 409 } 410 } 411 412 public List<RolapMember> readMembers( 413 DataSource dataSource, 414 List<List<RolapMember>> partialResult, 415 List<List<RolapMember>> newPartialResult) 416 { 417 prepareTuples(dataSource, partialResult, newPartialResult); 418 assert targets.size() == 1; 419 return targets.get(0).close(); 420 } 421 422 public List<RolapMember[]> readTuples( 423 DataSource jdbcConnection, 424 List<List<RolapMember>> partialResult, 425 List<List<RolapMember>> newPartialResult) 426 { 427 prepareTuples(jdbcConnection, partialResult, newPartialResult); 428 429 int n = targets.size(); 431 List<RolapMember[]> tupleList = new ArrayList<RolapMember[]>(); 432 Iterator<RolapMember>[] iter = new Iterator[n]; 433 for (int i = 0; i < n; i++) { 434 Target t = targets.get(i); 435 iter[i] = t.close().iterator(); 436 } 437 while (iter[0].hasNext()) { 438 RolapMember[] tuples = new RolapMember[n]; 439 for (int i = 0; i < n; i++) { 440 tuples[i] = iter[i].next(); 441 } 442 tupleList.add(tuples); 443 } 444 445 int enumTargetCount = getEnumTargetCount(); 449 if (enumTargetCount > 0) { 450 FunUtil.hierarchize(tupleList, false); 451 } 452 return tupleList; 453 } 454 455 461 private void resetCurrMembers(List<RolapMember> partialRow) { 462 int nativeTarget = 0; 463 for (Target target : targets) { 464 if (target.srcMembers == null) { 465 if (partialRow != null) { 470 target.currMember = partialRow.get(nativeTarget++); 471 } else { 472 target.currMember = null; 473 } 474 } 475 } 476 } 477 478 493 private void addTargets( 494 int currEnumTargetIdx, int currTargetIdx, int nEnumTargets, 495 int[] srcMemberIdxes, ResultSet resultSet, String message) { 496 497 Target currTarget = targets.get(currTargetIdx); 499 for (int i = 0; i < currTarget.srcMembers.length; i++) { 500 srcMemberIdxes[currEnumTargetIdx] = i; 501 if (currEnumTargetIdx < nEnumTargets - 1) { 504 int nextTargetIdx = currTargetIdx + 1; 505 for (; nextTargetIdx < targets.size(); nextTargetIdx++) { 506 if (targets.get(nextTargetIdx).srcMembers != null) { 507 break; 508 } 509 } 510 addTargets( 511 currEnumTargetIdx + 1, nextTargetIdx, nEnumTargets, 512 srcMemberIdxes, resultSet, message); 513 } else { 514 int column = 0; 518 int enumTargetIdx = 0; 519 for (Target target : targets) { 520 if (target.srcMembers == null) { 521 try { 522 column = target.addRow(resultSet, column); 523 } catch (Throwable e) { 524 throw Util.newError(e, message); 525 } 526 } else { 527 RolapMember member = 528 target.srcMembers[srcMemberIdxes[enumTargetIdx++]]; 529 target.list.add(member); 530 } 531 } 532 } 533 } 534 } 535 536 543 private void savePartialResult(List<List<RolapMember>> partialResult) { 544 List<RolapMember> row = new ArrayList<RolapMember>(); 545 for (Target target : targets) { 546 if (target.srcMembers == null) { 547 row.add(target.currMember); 548 } 549 } 550 partialResult.add(row); 551 } 552 553 String makeLevelMembersSql(DataSource dataSource) { 554 555 RolapCube cube = null; 565 boolean virtualCube = false; 566 if (constraint instanceof SqlContextConstraint) { 567 SqlContextConstraint sqlConstraint = 568 (SqlContextConstraint) constraint; 569 if (sqlConstraint.isJoinRequired()) { 570 Query query = constraint.getEvaluator().getQuery(); 571 cube = (RolapCube) query.getCube(); 572 virtualCube = cube.isVirtual(); 573 } 574 } 575 576 if (virtualCube) { 577 String selectString = ""; 578 Query query = constraint.getEvaluator().getQuery(); 579 Set <Map<RolapLevel, RolapStar.Column>> baseCubesLevelToColumnMaps = 580 query.getVirtualCubeBaseCubeMaps(); 581 Map<Map<RolapLevel, RolapStar.Column>, RolapMember> measureMap = 582 query.getLevelMapToMeasureMap(); 583 584 int k = -1; 587 for (Map<RolapLevel, RolapStar.Column> map : 588 baseCubesLevelToColumnMaps) 589 { 590 boolean finalSelect = 591 (++k == baseCubesLevelToColumnMaps.size() - 1); 592 RolapMember measure = measureMap.get(map); 597 assert measure instanceof RolapStoredMeasure; 598 Evaluator evaluator = constraint.getEvaluator(); 599 evaluator.push(); 600 evaluator.setContext(measure); 601 WhichSelect whichSelect = 602 finalSelect ? WhichSelect.LAST : 603 WhichSelect.NOT_LAST; 604 selectString += 605 generateSelectForLevels( 606 dataSource, map, whichSelect); 607 if (!finalSelect) { 608 selectString += " union "; 609 } 610 } 611 return selectString; 612 } else { 613 Map<RolapLevel, RolapStar.Column> map = 614 cube == null ? 615 null : 616 cube.getStar().getLevelToColumnMap(cube); 617 return generateSelectForLevels(dataSource, map, WhichSelect.ONLY); 618 } 619 } 620 621 631 private String generateSelectForLevels( 632 DataSource dataSource, 633 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 634 WhichSelect whichSelect) { 635 636 String s = "while generating query to retrieve members of level(s) " + targets; 637 SqlQuery sqlQuery = SqlQuery.newQuery(dataSource, s); 638 639 for (Target target : targets) { 641 if (target.srcMembers == null) { 644 addLevelMemberSql( 645 sqlQuery, 646 target.getLevel(), 647 levelToColumnMap, 648 whichSelect); 649 } 650 } 651 652 constraint.addConstraint(sqlQuery, levelToColumnMap); 654 655 return sqlQuery.toString(); 656 } 657 658 682 private void addLevelMemberSql( 683 SqlQuery sqlQuery, 684 RolapLevel level, 685 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 686 WhichSelect whichSelect) 687 { 688 RolapHierarchy hierarchy = level.getHierarchy(); 689 690 RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels(); 691 int levelDepth = level.getDepth(); 692 for (int i = 0; i <= levelDepth; i++) { 693 RolapLevel level2 = levels[i]; 694 if (level2.isAll()) { 695 continue; 696 } 697 hierarchy.addToFrom(sqlQuery, level2.getKeyExp()); 698 String keySql = level2.getKeyExp().getExpression(sqlQuery); 699 sqlQuery.addSelect(keySql); 700 sqlQuery.addGroupBy(keySql); 701 hierarchy.addToFrom(sqlQuery, level2.getOrdinalExp()); 702 703 constraint.addLevelConstraint( 704 sqlQuery, null, level2, levelToColumnMap); 705 706 if (level2.hasCaptionColumn()) { 707 MondrianDef.Expression captionExp = level2.getCaptionExp(); 708 hierarchy.addToFrom(sqlQuery, captionExp); 709 String captionSql = captionExp.getExpression(sqlQuery); 710 sqlQuery.addSelect(captionSql); 711 sqlQuery.addGroupBy(captionSql); 712 } 713 714 String ordinalSql = level2.getOrdinalExp().getExpression(sqlQuery); 715 sqlQuery.addGroupBy(ordinalSql); 716 if (!ordinalSql.equals(keySql)) { 717 sqlQuery.addSelect(ordinalSql); 718 } 719 720 switch (whichSelect) { 724 case LAST: 725 sqlQuery.addOrderBy( 726 Integer.toString( 727 sqlQuery.getCurrentSelectListSize()), 728 true, false, true); 729 break; 730 case ONLY: 731 sqlQuery.addOrderBy(ordinalSql, true, false, true); 732 break; 733 } 734 RolapProperty[] properties = level2.getProperties(); 735 for (RolapProperty property : properties) { 736 String propSql = property.getExp().getExpression(sqlQuery); 737 sqlQuery.addSelect(propSql); 738 sqlQuery.addGroupBy(propSql); 739 } 740 } 741 } 742 743 int getMaxRows() { 744 return maxRows; 745 } 746 747 void setMaxRows(int maxRows) { 748 this.maxRows = maxRows; 749 } 750 751 755 enum WhichSelect { 756 759 ONLY, 760 764 NOT_LAST, 765 769 LAST 770 } 771 } 772 773 | Popular Tags |