funtableimpl.java

来自「数据仓库展示程序」· Java 代码 · 共 533 行 · 第 1/2 页

JAVA
533
字号
/*
// $Id: //open/mondrian/src/main/mondrian/olap/fun/FunTableImpl.java#4 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2002-2005 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap.fun;

import mondrian.olap.*;
import mondrian.olap.type.*;
import mondrian.olap.type.DimensionType;
import mondrian.resource.MondrianResource;

import java.util.*;
import java.io.PrintWriter;

/**
 * Abstract implementation of {@link FunTable}.
 *
 * <p>The derived class must implement {@link #defineFunctions()} to define
 * each function which will be recognized by this table. This method is called
 * from the constructor, after which point, no further functions can be added.
 */
public abstract class FunTableImpl implements FunTable {
    /**
     * Maps the upper-case name of a function plus its
     * {@link mondrian.olap.Syntax} to an array of
     * {@link mondrian.olap.Validator} objects for that name.
     */
    protected final Map mapNameToResolvers = new HashMap();
    private final HashSet reservedWords = new HashSet();
    private final HashSet propertyWords = new HashSet();
    protected static final Resolver[] emptyResolverArray = new Resolver[0];
    /** used during initialization **/
    protected final List resolvers = new ArrayList();
    protected final List funInfoList = new ArrayList();

    protected FunTableImpl() {
    }

    /**
     * Initializes the function table.
     */
    public void init() {
        defineFunctions();
        organizeFunctions();
    }

    protected static String makeResolverKey(String name, Syntax syntax) {
        return name.toUpperCase() + "$" + syntax;
    }

    protected void define(FunDef funDef) {
        define(new SimpleResolver(funDef));
    }

    protected void define(Resolver resolver) {
        addFunInfo(resolver);
        if (resolver.getSyntax() == Syntax.Property) {
            defineProperty(resolver.getName());
        }
        resolvers.add(resolver);
        final String[] reservedWords = resolver.getReservedWords();
        for (int i = 0; i < reservedWords.length; i++) {
            String reservedWord = reservedWords[i];
            defineReserved(reservedWord);
        }
    }

    protected void addFunInfo(Resolver resolver) {
        this.funInfoList.add(FunInfo.make(resolver));
    }

    public Exp createValueFunCall(Exp exp, Validator validator) {
        final Type type = exp.getTypeX();
        if (type instanceof ScalarType) {
            return exp;
        }
        if (!TypeUtil.canEvaluate(type)) {
            String exprString = Util.unparse(exp);
            throw MondrianResource.instance().MdxMemberExpIsSet.ex(exprString);
        }
        if (type instanceof MemberType) {
            return new MemberScalarExp(exp);
        } else if (type instanceof DimensionType ||
                type instanceof HierarchyType) {
            exp = new FunCall(
                    "CurrentMember",
                    Syntax.Property,
                    new Exp[]{exp});
            exp = exp.accept(validator);
            return new MemberScalarExp(exp);
        } else if (type instanceof TupleType) {
            if (exp instanceof FunCall) {
                FunCall call = (FunCall) exp;
                if (call.getFunDef() instanceof TupleFunDef) {
                    return new MemberListScalarExp(call.getArgs());
                }
            }
            return new TupleScalarExp(exp);
        } else {
            throw Util.newInternal("Unknown type " + type);
        }
    }

    /**
     * Creates an expression which will yield the current value of the current
     * measure.
     */
    static Exp createValueFunCall() {
        return new ScalarExp();
    }

    public FunDef getDef(FunCall call, Validator validator) {
        String key = makeResolverKey(call.getFunName(), call.getSyntax());

        // Resolve function by its upper-case name first.  If there is only one
        // function with that name, stop immediately.  If there is more than
        // function, use some custom method, which generally involves looking
        // at the type of one of its arguments.
        String signature = call.getSyntax().getSignature(call.getFunName(),
                Category.Unknown, ExpBase.getTypes(call.getArgs()));
        Resolver[] resolvers = (Resolver[]) mapNameToResolvers.get(key);
        if (resolvers == null) {
            resolvers = emptyResolverArray;
        }

        int[] conversionCount = new int[] {0};
        int minConversions = Integer.MAX_VALUE;
        int matchCount = 0;
        FunDef matchDef = null;
        for (int i = 0; i < resolvers.length; i++) {
            conversionCount[0] = 0;
            FunDef def = resolvers[i].resolve(
                    call.getArgs(), validator, conversionCount);
            if (def != null) {
                int conversions = conversionCount[0];
                if (conversions < minConversions) {
                    minConversions = conversions;
                    matchCount = 1;
                    matchDef = def;
                } else if (conversions == minConversions) {
                    matchCount++;
                } else {
                    // ignore this match -- it required more coercions than
                    // other overloadings we've seen
                }
            }
        }
        switch (matchCount) {
        case 0:
            throw MondrianResource.instance().NoFunctionMatchesSignature.ex(
                    signature);
        case 1:
            final String matchKey = makeResolverKey(matchDef.getName(),
                    matchDef.getSyntax());
            Util.assertTrue(matchKey.equals(key), matchKey);
            return matchDef;
        default:
            throw MondrianResource.instance().MoreThanOneFunctionMatchesSignature.ex(signature);
        }
    }

    public boolean requiresExpression(
            FunCall call,
            int k,
            Validator validator) {
        final FunDef funDef = call.getFunDef();
        if (funDef != null) {
            final int[] parameterTypes = funDef.getParameterTypes();
            return parameterTypes[k] != Category.Set;
        }
        // The function call has not been resolved yet. In fact, this method
        // may have been invoked while resolving the child. Consider this:
        //   CrossJoin([Measures].[Unit Sales] * [Measures].[Store Sales])
        //
        // In order to know whether to resolve '*' to the multiplication
        // operator (which returns a scalar) or the crossjoin operator (which
        // returns a set) we have to know what kind of expression is expected.
        String key = makeResolverKey(call.getFunName(), call.getSyntax());
        Resolver[] resolvers = (Resolver[]) mapNameToResolvers.get(key);
        if (resolvers == null) {
            resolvers = emptyResolverArray;
        }
        for (int i = 0; i < resolvers.length; i++) {
            Resolver resolver2 = resolvers[i];
            if (!resolver2.requiresExpression(k)) {
                // This resolver accepts a set in this argument position,
                // therefore we don't REQUIRE a scalar expression.
                return false;
            }
        }
        return true;
    }

    public List getReservedWords() {
        return new ArrayList(reservedWords);
    }

    public boolean isReserved(String s) {
        return reservedWords.contains(s.toUpperCase());
    }

    /**
     * Defines a reserved word.
     * @see #isReserved
     */
    protected void defineReserved(String s) {
        reservedWords.add(s.toUpperCase());
    }

    public List getResolvers() {
        final List list = new ArrayList();
        final Collection c = mapNameToResolvers.values();
        for (Iterator iterator = c.iterator(); iterator.hasNext();) {
            Resolver[] resolvers = (Resolver[]) iterator.next();
            for (int i = 0; i < resolvers.length; i++) {
                Resolver resolver = resolvers[i];
                list.add(resolver);
            }
        }
        return list;
    }

    public boolean isProperty(String s) {
        return propertyWords.contains(s.toUpperCase());
    }

    /**
     * Defines a word matching a property function name.
     * @see #isProperty
     */
    protected void defineProperty(String s) {
        propertyWords.add(s.toUpperCase());
    }

    public List getFunInfoList() {
        return Collections.unmodifiableList(this.funInfoList);
    }

    /**
     * Indexes the collection of functions.
     */
    protected void organizeFunctions() {
        Collections.sort(funInfoList);
        // Map upper-case function names to resolvers.
        for (int i = 0, n = resolvers.size(); i < n; i++) {
            Resolver resolver = (Resolver) resolvers.get(i);
            String key = makeResolverKey(resolver.getName(), resolver.getSyntax());
            final Object value = mapNameToResolvers.get(key);
            if (value instanceof Resolver[]) {
                continue; // has already been converted
            }
            List v2 = (List) value;
            if (v2 == null) {
                v2 = new ArrayList();
                mapNameToResolvers.put(key, v2);
            }
            v2.add(resolver);
        }
        // Convert the Lists into arrays.
        for (Iterator keys = mapNameToResolvers.keySet().iterator(); keys.hasNext();) {
            String key = (String) keys.next();
            final Object value = mapNameToResolvers.get(key);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?