001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2004-2005 TONBELLER AG
008// Copyright (C) 2005-2013 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.rolap;
012
013import mondrian.calc.TupleList;
014import mondrian.calc.impl.DelegatingTupleList;
015import mondrian.calc.impl.UnaryTupleList;
016import mondrian.olap.*;
017import mondrian.olap.fun.FunUtil;
018import mondrian.rolap.sql.TupleConstraint;
019import mondrian.server.Locus;
020import mondrian.server.monitor.SqlStatementEvent;
021import mondrian.util.Pair;
022import mondrian.util.TraversalList;
023
024import java.sql.SQLException;
025import java.util.*;
026
027import javax.sql.DataSource;
028
029/**
030 * Reads the members of a single level (level.members) or of multiple levels
031 * (crossjoin).
032 *
033 * @deprecated Deprecated for Mondrian 4.0.
034 * @author luis f. canals
035 * @since Dec, 2007
036 */
037@Deprecated
038public class HighCardSqlTupleReader extends SqlTupleReader {
039    private ResultLoader resultLoader;
040    private boolean moreRows;
041
042    int maxRows = 0;
043
044    public HighCardSqlTupleReader(final TupleConstraint constraint) {
045        super(constraint);
046    }
047
048    public void addLevelMembers(
049        final RolapLevel level,
050        final MemberBuilder memberBuilder,
051        final List<RolapMember> srcMembers)
052    {
053        targets.add(new Target(
054            level, memberBuilder, srcMembers, constraint, this));
055    }
056
057    protected void prepareTuples(
058        final DataSource dataSource,
059        final TupleList partialResult,
060        final List<List<RolapMember>> newPartialResult)
061    {
062        String message = "Populating member cache with members for " + targets;
063        SqlStatement stmt = null;
064        boolean execQuery = (partialResult == null);
065        boolean success = false;
066        try {
067            if (execQuery) {
068                // we're only reading tuples from the targets that are
069                // non-enum targets
070                List<TargetBase> partialTargets = new ArrayList<TargetBase>();
071                for (TargetBase target : targets) {
072                    if (target.getSrcMembers() == null) {
073                        partialTargets.add(target);
074                    }
075                }
076                final Pair<String, List<SqlStatement.Type>> pair =
077                    makeLevelMembersSql(dataSource);
078                String sql = pair.left;
079                List<SqlStatement.Type> types = pair.right;
080                stmt = RolapUtil.executeQuery(
081                    dataSource, sql, types, maxRows, 0,
082                    new SqlStatement.StatementLocus(
083                        Locus.peek().execution,
084                        "HighCardSqlTupleReader.readTuples " + partialTargets,
085                        message,
086                        SqlStatementEvent.Purpose.TUPLES, 0),
087                    -1, -1, null);
088            }
089
090            for (TargetBase target : targets) {
091                target.open();
092            }
093
094            // determine how many enum targets we have
095            int enumTargetCount = getEnumTargetCount();
096
097            int currPartialResultIdx = 0;
098            if (execQuery) {
099                this.moreRows = stmt.getResultSet().next();
100                if (this.moreRows) {
101                    ++stmt.rowCount;
102                }
103            } else {
104                this.moreRows = currPartialResultIdx < partialResult.size();
105            }
106
107            this.resultLoader =
108                new ResultLoader(
109                    enumTargetCount,
110                    targets, stmt, execQuery, partialResult,
111                    newPartialResult);
112
113            // Read first and second elements if exists (or marks
114            // source as having "no more rows")
115            readNextTuple();
116            readNextTuple();
117            success = true;
118        } catch (SQLException sqle) {
119            if (stmt != null) {
120                throw stmt.handle(sqle);
121            } else {
122                throw Util.newError(sqle, message);
123            }
124        } finally {
125            if (!moreRows || !success) {
126                if (stmt != null) {
127                    stmt.close();
128                }
129            }
130        }
131    }
132
133    public TupleList readMembers(
134        final DataSource dataSource,
135        final TupleList partialResult,
136        final List<List<RolapMember>> newPartialResult)
137    {
138        prepareTuples(dataSource, partialResult, newPartialResult);
139
140        assert targets.size() == 1;
141
142        return new UnaryTupleList(
143            targets.get(0).close());
144    }
145
146    public TupleList readTuples(
147        final DataSource jdbcConnection,
148        final TupleList partialResult,
149        final List<List<RolapMember>> newPartialResult)
150    {
151        prepareTuples(jdbcConnection, partialResult, newPartialResult);
152
153        // List of tuples
154        final int n = targets.size();
155        @SuppressWarnings({"unchecked"})
156        final List<Member>[] lists = new List[n];
157        for (int i = 0; i < n; i++) {
158            lists[i] = targets.get(i).close();
159        }
160
161        final List<List<Member>> list =
162            new TraversalList<Member>(lists, Member.class);
163        TupleList tupleList = new DelegatingTupleList(n, list);
164
165        // need to hierarchize the columns from the enumerated targets
166        // since we didn't necessarily add them in the order in which
167        // they originally appeared in the cross product
168        int enumTargetCount = getEnumTargetCount();
169        if (enumTargetCount > 0) {
170            tupleList = FunUtil.hierarchizeTupleList(tupleList, false);
171        }
172        return tupleList;
173    }
174
175    /**
176     * Reads next tuple, notifying all internal targets.
177     *
178     * @return whether there are any more rows
179     */
180    public boolean readNextTuple() {
181        if (!this.moreRows) {
182            return false;
183        }
184        try {
185            this.moreRows = this.resultLoader.loadResult();
186        } catch (SQLException sqle) {
187            this.moreRows = false;
188            throw this.resultLoader.handle(sqle);
189        }
190        if (!this.moreRows) {
191            this.resultLoader.close();
192        }
193        return this.moreRows;
194    }
195
196    public void setMaxRows(int maxRows) {
197        this.maxRows = maxRows;
198    }
199
200    public int getMaxRows() {
201        return maxRows;
202    }
203
204    Collection<RolapCube> getBaseCubeCollection(final Query query) {
205        return query.getBaseCubes();
206    }
207}
208// End HighCardSqlTupleReader.java