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) 2006-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.AbstractListCalc;
014import mondrian.mdx.ResolvedFunCall;
015import mondrian.olap.Evaluator;
016import mondrian.olap.FunDef;
017
018/**
019 * Definition of the <code>Subset</code> MDX function.
020 *
021 * @author jhyde
022 * @since Mar 23, 2006
023 */
024class SubsetFunDef extends FunDefBase {
025    static final ReflectiveMultiResolver Resolver =
026        new ReflectiveMultiResolver(
027            "Subset",
028            "Subset(<Set>, <Start>[, <Count>])",
029            "Returns a subset of elements from a set.",
030            new String[] {"fxxn", "fxxnn"},
031            SubsetFunDef.class);
032
033    public SubsetFunDef(FunDef dummyFunDef) {
034        super(dummyFunDef);
035    }
036
037    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
038        final ListCalc listCalc =
039            compiler.compileList(call.getArg(0));
040        final IntegerCalc startCalc =
041            compiler.compileInteger(call.getArg(1));
042        final IntegerCalc countCalc =
043            call.getArgCount() > 2
044            ? compiler.compileInteger(call.getArg(2))
045            : null;
046        return new AbstractListCalc(
047            call, new Calc[] {listCalc, startCalc, countCalc})
048        {
049            public TupleList evaluateList(Evaluator evaluator) {
050                final int savepoint = evaluator.savepoint();
051                try {
052                    evaluator.setNonEmpty(false);
053                    final TupleList list = listCalc.evaluateList(evaluator);
054                    final int start = startCalc.evaluateInteger(evaluator);
055                    int end;
056                    if (countCalc != null) {
057                        final int count = countCalc.evaluateInteger(evaluator);
058                        end = start + count;
059                    } else {
060                        end = list.size();
061                    }
062                    if (end > list.size()) {
063                        end = list.size();
064                    }
065                    if (start >= end || start < 0) {
066                        return TupleCollections.emptyList(list.getArity());
067                    }
068                    if (start == 0 && end == list.size()) {
069                        return list;
070                    }
071                    assert 0 <= start;
072                    assert start < end;
073                    assert end <= list.size();
074                    return list.subList(start, end);
075                } finally {
076                    evaluator.restore(savepoint);
077                }
078            }
079        };
080    }
081}
082
083// End SubsetFunDef.java