/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 TONBELLER AG
// Copyright (C) 2005-2005 Julian Hyde
// Copyright (C) 2005-2013 Pentaho and others
// All Rights Reserved.
*/
package mondrian.rolap;
import mondrian.calc.ResultStyle;
import mondrian.olap.*;
import mondrian.rolap.sql.TupleConstraint;
import java.sql.SQLException;
import java.util.*;
/**
* Helper class for {@link mondrian.rolap.HighCardSqlTupleReader} that
* keeps track of target levels and constraints for adding to SQL query.
*
* @deprecated Deprecated for Mondrian 4.0.
* @author luis f. canals, Kurtis Walker
* @since July 23, 2009
*/
@Deprecated
public class Target extends TargetBase {
private final HighCardSqlTupleReader sqlTupleReader;
private final MemberCache cache;
private final TupleConstraint constraint;
boolean parentChild;
private RolapLevel[] levels;
private int levelDepth;
public Target(
final RolapLevel level,
final TupleReader.MemberBuilder memberBuilder,
final List<RolapMember> srcMembers,
final TupleConstraint constraint,
final HighCardSqlTupleReader sqlTupleReader)
{
super(srcMembers, level, memberBuilder);
this.sqlTupleReader = sqlTupleReader;
this.constraint = constraint;
this.cache = memberBuilder.getMemberCache();
}
public void open() {
levels = (RolapLevel[]) level.getHierarchy().getLevels();
setList(new ArrayList<RolapMember>());
levelDepth = level.getDepth();
parentChild = level.isParentChild();
}
int internalAddRow(SqlStatement stmt, int column)
throws SQLException
{
RolapMember member = null;
if (getCurrMember() != null) {
member = getCurrMember();
} else {
boolean checkCacheStatus = true;
final List<SqlStatement.Accessor> accessors = stmt.getAccessors();
for (int i = 0; i <= levelDepth; i++) {
RolapLevel childLevel = levels[i];
if (childLevel.isAll()) {
member = memberBuilder.allMember();
continue;
}
if (childLevel.isParentChild()) {
column++;
}
Object value = accessors.get(column++).get();
if (value == null) {
value = RolapUtil.sqlNullValue;
}
Object captionValue;
if (childLevel.hasCaptionColumn()) {
captionValue = accessors.get(column++).get();
} else {
captionValue = null;
}
RolapMember parentMember = member;
Object key = cache.makeKey(parentMember, value);
member = cache.getMember(key, checkCacheStatus);
checkCacheStatus = false; /* Only check the first time */
if (member == null) {
if (constraint instanceof
RolapNativeCrossJoin.NonEmptyCrossJoinConstraint
&& childLevel.isParentChild())
{
member = castToNonEmptyCJConstraint(constraint)
.findMember(value);
}
if (member == null) {
member = memberBuilder.makeMember(
parentMember, childLevel, value, captionValue,
parentChild, stmt, key, column);
}
}
// Skip over the columns consumed by makeMember
if (!childLevel.getOrdinalExp().equals(
childLevel.getKeyExp()))
{
++column;
}
column += childLevel.getProperties().length;
}
setCurrMember(member);
}
getList().add(member);
return column;
}
public List<Member> close() {
final boolean asList = this.constraint.getEvaluator() != null
&& this.constraint.getEvaluator().getQuery().getResultStyle()
== ResultStyle.LIST;
final int limit = MondrianProperties.instance().ResultLimit.get();
final List<RolapMember> l = new AbstractList<RolapMember>() {
private boolean moreRows = true;
private int offset = 0;
private RolapMember first = null;
private boolean firstMemberAssigned = false;
/**
* Performs a load of the whole result set.
*/
public int size() {
while (this.moreRows) {
this.moreRows = sqlTupleReader.readNextTuple();
if (limit > 0 && !asList && getList().size() > limit) {
System.out.println(
"Target: 199, Ouch! Toooo big array..."
+ hashCode());
new Throwable().printStackTrace();
}
}
return getList().size();
}
public RolapMember get(final int idx) {
if (asList) {
return getList().get(idx);
}
if (idx == 0 && this.firstMemberAssigned) {
return this.first;
}
int index = idx - offset;
if (0 < limit && index < 0) {
// Cannot send NoSuchElementException since its intercepted
// by AbstractSequentialList to identify out of bounds.
throw new RuntimeException(
"Element " + idx
+ " has been forgotten");
}
while (index >= getList().size() && this.moreRows) {
this.moreRows = sqlTupleReader.readNextTuple();
if (limit > 0 && getList().size() >= limit) {
// We have to offset the list, but we don't want to use
// a 0(n) operation. What we do is we calculate an
// offset value corresponding to 10% of the current
// size of the list and use subList(), which will
// create a view of the sub array with an offset.
//
// We use a ~10% offset increment because we don't want
// to perform this operation too often and impair
// performance by spawning too many sublists.
//
// REVIEW: It doesn't matter right now if this code
// is sub-optimal. The highCardinality feature is
// marked for deprecation in 4.0. In practice,
// this code should never get executed because if
// you create a tuple list bigger than the value
// of 'limit', the code will throw an exception
// upstream before it ever reaches this point.
// For now it is sufficient. We get the speed of
// random access along with quick offsets.
int deltaOffset = Math.round((limit / 10) + 0.5f);
index -= deltaOffset;
offset += deltaOffset;
setList(
getList().subList(
deltaOffset,
getList().size()));
}
}
if (idx == 0) {
this.first = getList().get(index);
// Above might run into exception which is caught in
// isEmpty(). So can change the state of the object after
// that.
this.firstMemberAssigned = true;
return this.first;
} else {
return getList().get(index);
}
}
public RolapMember set(final int i, final RolapMember e) {
if (asList) {
return getList().set(i, e);
} else {
throw new UnsupportedOperationException();
}
}
public boolean isEmpty() {
try {
get(0);
return false;
} catch (IndexOutOfBoundsException e) {
return true;
}
}
public int hashCode() {
return Target.this.hashCode();
}
public Iterator<RolapMember> iterator() {
return new Iterator<RolapMember>() {
private int cursor = 0;
public boolean hasNext() {
try {
get(cursor);
return true;
} catch (IndexOutOfBoundsException ioobe) {
return false;
}
}
public RolapMember next() {
return get(cursor++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
if (asList) {
l.size();
}
return Util.cast(l);
}
}
// End Target.java