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) 2005-2009 Pentaho and others
008// All Rights Reserved.
009*/
010package mondrian.olap.fun;
011
012import mondrian.calc.*;
013import mondrian.calc.impl.GenericCalc;
014import mondrian.calc.impl.GenericIterCalc;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.*;
017import mondrian.olap.type.SetType;
018import mondrian.olap.type.Type;
019
020import java.io.PrintWriter;
021import java.util.List;
022
023/**
024 * Definition of the <code>Cache</code> system function, which is smart enough
025 * to evaluate its argument only once.
026 *
027 * @author jhyde
028 * @since 2005/8/14
029 */
030public class CacheFunDef extends FunDefBase {
031    static final String NAME = "Cache";
032    private static final String SIGNATURE = "Cache(<<Exp>>)";
033    private static final String DESCRIPTION =
034        "Evaluates and returns its sole argument, applying statement-level caching";
035    private static final Syntax SYNTAX = Syntax.Function;
036    static final CacheFunResolver Resolver = new CacheFunResolver();
037
038    CacheFunDef(
039        String name,
040        String signature,
041        String description,
042        Syntax syntax,
043        int category,
044        Type type)
045    {
046        super(
047            name, signature, description, syntax,
048            category, new int[] {category});
049        Util.discard(type);
050    }
051
052    public void unparse(Exp[] args, PrintWriter pw) {
053        args[0].unparse(pw);
054    }
055
056    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
057        final Exp exp = call.getArg(0);
058        final ExpCacheDescriptor cacheDescriptor =
059                new ExpCacheDescriptor(exp, compiler);
060        if (call.getType() instanceof SetType) {
061            return new GenericIterCalc(call) {
062                public Object evaluate(Evaluator evaluator) {
063                    return evaluator.getCachedResult(cacheDescriptor);
064                }
065
066                public Calc[] getCalcs() {
067                    return new Calc[] {cacheDescriptor.getCalc()};
068                }
069
070                public ResultStyle getResultStyle() {
071                    // cached lists are immutable
072                    return ResultStyle.LIST;
073                }
074            };
075        } else {
076            return new GenericCalc(call) {
077                public Object evaluate(Evaluator evaluator) {
078                    return evaluator.getCachedResult(cacheDescriptor);
079                }
080
081                public Calc[] getCalcs() {
082                    return new Calc[] {cacheDescriptor.getCalc()};
083                }
084
085                public ResultStyle getResultStyle() {
086                    return ResultStyle.VALUE;
087                }
088            };
089        }
090    }
091
092    public static class CacheFunResolver extends ResolverBase {
093        CacheFunResolver() {
094            super(NAME, SIGNATURE, DESCRIPTION, SYNTAX);
095        }
096
097        public FunDef resolve(
098            Exp[] args,
099            Validator validator,
100            List<Conversion> conversions)
101        {
102            if (args.length != 1) {
103                return null;
104            }
105            final Exp exp = args[0];
106            final int category = exp.getCategory();
107            final Type type = exp.getType();
108            return new CacheFunDef(
109                NAME, SIGNATURE, DESCRIPTION, SYNTAX,
110                category, type);
111        }
112
113        public boolean requiresExpression(int k) {
114            return false;
115        }
116    }
117}
118
119// End CacheFunDef.java