001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/ResultLoader.java#2 $ 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) 2003-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 // 010 // jhyde, Feb 21, 2003 011 */ 012 package mondrian.rolap; 013 014 import mondrian.olap.Util; 015 016 import java.sql.ResultSet; 017 import java.sql.SQLException; 018 import java.util.ArrayList; 019 import java.util.List; 020 021 /** 022 * Loader to be iterated to load all results from database. 023 * 024 * @version $Id: //open/mondrian/src/main/mondrian/rolap/ResultLoader.java#2 $ 025 * @author luis f. canals 026 */ 027 public class ResultLoader { 028 private final List<Target> targets; 029 private final int enumTargetCount; 030 private final ResultSet resultSet; 031 private final boolean execQuery; 032 private final String message; 033 private final List<List<RolapMember>> partialResult, newPartialResult; 034 private final SqlStatement stmt; 035 036 private final int[] srcMemberIdxes; 037 038 int currPartialResultIdx = 0; 039 040 public ResultLoader( 041 final int enumTargetCount, 042 final List<Target> targets, 043 final SqlStatement stmt, 044 final ResultSet resultSet, 045 final boolean execQuery, 046 final List<List<RolapMember>> partialResult, 047 final List<List<RolapMember>> newPartialResult) 048 throws SQLException 049 { 050 this.targets = targets; 051 this.enumTargetCount = enumTargetCount; 052 this.stmt = stmt; 053 this.resultSet = resultSet; 054 this.execQuery = execQuery; 055 this.partialResult = partialResult; 056 this.newPartialResult = newPartialResult; 057 this.srcMemberIdxes = 058 enumTargetCount > 0 059 ? new int[enumTargetCount] 060 : null; 061 this.message = "Populating member cache with members for " + targets; 062 } 063 064 065 public boolean loadResult() throws SQLException { 066 boolean moreRows = true; 067 /* 068 if (limit > 0 && limit < ++fetchCount) { 069 throw MondrianResource.instance().MemberFetchLimitExceeded 070 .ex((long) limit); 071 } 072 */ 073 if (enumTargetCount == 0) { 074 int column = 0; 075 for (Target target : targets) { 076 target.removeCurrMember(); 077 column = target.addRow(resultSet, column); 078 } 079 } else { 080 int firstEnumTarget = 0; 081 for (; firstEnumTarget < targets.size(); firstEnumTarget++) { 082 if (targets.get(firstEnumTarget).getSrcMembers() != null) { 083 break; 084 } 085 } 086 List<RolapMember> partialRow; 087 if (execQuery) { 088 partialRow = null; 089 } else { 090 partialRow = partialResult.get(currPartialResultIdx); 091 } 092 resetCurrMembers(partialRow); 093 addTargets( 094 0, firstEnumTarget, enumTargetCount, srcMemberIdxes, 095 resultSet, message); 096 if (newPartialResult != null) { 097 savePartialResult(newPartialResult); 098 } 099 } 100 101 if (execQuery) { 102 moreRows = resultSet.next(); 103 if (moreRows) { 104 ++stmt.rowCount; 105 } 106 } else { 107 currPartialResultIdx++; 108 moreRows = currPartialResultIdx < partialResult.size(); 109 } 110 return moreRows; 111 } 112 113 114 /** 115 * Closes internal statement. 116 */ 117 public void close() { 118 if (this.stmt != null) { 119 this.stmt.close(); 120 } 121 } 122 123 124 /** 125 * Handles error 126 */ 127 public void handle(Exception e) { 128 if (stmt != null) { 129 stmt.handle(e); 130 } else { 131 throw Util.newError(e, message); 132 } 133 } 134 135 // 136 // Private stuff ------------------------------- 137 // 138 139 /** 140 * Sets the current member for those targets that retrieve their column 141 * values from native sql. 142 * 143 * @param partialRow if set, previously cached result set 144 */ 145 private void resetCurrMembers(List<RolapMember> partialRow) { 146 int nativeTarget = 0; 147 for (Target target : targets) { 148 if (target.getSrcMembers() == null) { 149 if (partialRow != null) { 150 target.setCurrMember(partialRow.get(nativeTarget++)); 151 } else { 152 target.removeCurrMember(); 153 } 154 } 155 } 156 } 157 158 /** 159 * Recursively forms the cross product of a row retrieved through sql 160 * with each of the targets that contains an enumerated set of members. 161 * 162 * @param currEnumTargetIdx current enum target that recursion 163 * is being applied on 164 * @param currTargetIdx index within the list of a targets that 165 * currEnumTargetIdx corresponds to 166 * @param nEnumTargets number of targets that have enumerated members 167 * @param srcMemberIdxes for each enumerated target, the current member 168 * to be retrieved to form the current cross product row 169 * @param resultSet result set corresponding to rows retrieved through 170 * native sql 171 * @param message Message to issue on failure 172 */ 173 private void addTargets( 174 int currEnumTargetIdx, int currTargetIdx, int nEnumTargets, 175 int[] srcMemberIdxes, ResultSet resultSet, String message) { 176 177 Target currTarget = targets.get(currTargetIdx); 178 for (int i = 0; i < currTarget.getSrcMembers().size(); i++) { 179 srcMemberIdxes[currEnumTargetIdx] = i; 180 if (currEnumTargetIdx < nEnumTargets - 1) { 181 int nextTargetIdx = currTargetIdx + 1; 182 for (; nextTargetIdx < targets.size(); nextTargetIdx++) { 183 if (targets.get(nextTargetIdx).getSrcMembers() != null) { 184 break; 185 } 186 } 187 addTargets( 188 currEnumTargetIdx + 1, nextTargetIdx, nEnumTargets, 189 srcMemberIdxes, resultSet, message); 190 } else { 191 int column = 0; 192 int enumTargetIdx = 0; 193 for (Target target : targets) { 194 if (target.getSrcMembers() == null) { 195 try { 196 column = target.addRow(resultSet, column); 197 } catch (Throwable e) { 198 throw Util.newError(e, message); 199 } 200 } else { 201 RolapMember member = target.getSrcMembers().get( 202 srcMemberIdxes[enumTargetIdx++]); 203 target.add(member); 204 } 205 } 206 } 207 } 208 } 209 210 /** 211 * Retrieves the current members fetched from the targets executed 212 * through sql and form tuples, adding them to partialResult 213 * 214 * @param partialResult list containing the columns and rows corresponding 215 * to data fetched through sql 216 */ 217 private void savePartialResult(List<List<RolapMember>> partialResult) { 218 List<RolapMember> row = new ArrayList<RolapMember>(); 219 for (Target target : targets) { 220 if (target.getSrcMembers() == null) { 221 row.add(target.getCurrMember()); 222 } 223 } 224 partialResult.add(row); 225 } 226 227 } 228 229 // End ResultLoader.java