query.java

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

JAVA
1,168
字号
/*
// $Id: //open/mondrian/src/main/mondrian/olap/Query.java#53 $
// 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.
// (C) Copyright 1998-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 20 January, 1999
*/

package mondrian.olap;
import mondrian.olap.fun.*;
import mondrian.olap.type.*;
import mondrian.resource.MondrianResource;

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

/**
 * <code>Query</code> is an MDX query.
 *
 * <p>It is created by calling {@link Connection#parseQuery},
 * and executed by calling {@link Connection#execute},
 * to return a {@link Result}.
 **/
public class Query extends QueryPart {

    /**
     * public-private: This must be public because it is still accessed in rolap.RolapCube
     */
    public Formula[] formulas;

    /**
     * public-private: This must be public because it is still accessed in rolap.RolapConnection
     */
    public QueryAxis[] axes;

    /**
     * public-private: This must be public because it is still accessed in rolap.RolapResult
     */
    public Exp slicer;

    /**
     * Definitions of all parameters used in this query.
     */
    private Parameter[] parameters;

    /**
     * Cell properties. Not currently used.
     */
    private final QueryPart[] cellProps;

    /**
     * Cube this query belongs to.
     */
    private final Cube cube;

    private final Connection connection;

    /** Constructs a Query. */
    public Query(
            Connection connection,
            Formula[] formulas,
            QueryAxis[] axes,
            String cube,
            Exp slicer,
            QueryPart[] cellProps) {
        this(connection,
                connection.getSchema().lookupCube(cube, true),
                formulas,
                axes,
                slicer,
                cellProps,
                new Parameter[0]);
    }

    /**
     * Creates a Query.
     */
    public Query(
            Connection connection,
            Cube mdxCube,
            Formula[] formulas,
            QueryAxis[] axes,
            Exp slicer,
            QueryPart[] cellProps,
            Parameter[] parameters) {
        this.connection = connection;
        this.cube = mdxCube;
        this.formulas = formulas;
        this.axes = axes;
        normalizeAxes();
        setSlicer(slicer);
        this.cellProps = cellProps;
        this.parameters = parameters;
        resolve();
    }

    /**
     * add a new formula specifying a set
     *  to an existing query
     */
    public void addFormula(String[] names, Exp exp) {
        Formula newFormula = new Formula(names, exp);
        int nFor = 0;
        if (formulas.length > 0) {
            nFor = formulas.length;
        }
        Formula[] newFormulas = new Formula[nFor + 1];
        for (int i = 0; i < nFor; i++ ) {
            newFormulas[i] = formulas[i];
        }
        newFormulas[nFor] = newFormula;
        formulas = newFormulas;
        resolve();
    }

    /**
     * add a new formula specifying a member
     *  to an existing query
     */
    public void addFormula(String[] names,
                           Exp exp,
                           MemberProperty[] memberProperties) {
        Formula newFormula = new Formula(names, exp, memberProperties);
        int nFor = 0;
        if (formulas.length > 0) {
            nFor = formulas.length;
        }
        Formula[] newFormulas = new Formula[nFor + 1];
        for (int i = 0; i < nFor; i++ ) {
            newFormulas[i] = formulas[i];
        }
        newFormulas[nFor] = newFormula;
        formulas = newFormulas;
        resolve();
    }


    public Validator createValidator() {
        return new StackValidator(connection.getSchema().getFunTable());
    }

    public Object clone() throws CloneNotSupportedException {
        return new Query(connection,
                cube,
                Formula.cloneArray(formulas),
                QueryAxis.cloneArray(axes),
                (slicer == null) ? null : (Exp) slicer.clone(),
                cellProps,
                Parameter.cloneArray(parameters));
    }

    public Query safeClone() {
        try {
            return (Query) clone();
        } catch (CloneNotSupportedException e) {
            throw Util.newInternal(e, "Query.clone() failed");
        }
    }

    public Connection getConnection() {
        return connection;
    }

    /**
     * Returns the MDX query string. If the query was created by parsing an
     * MDX string, the string returned by this method may not be identical, but
     * it will have the same meaning. If the query's parse tree has been
     * manipulated (for instance, the rows and columns axes have been
     * interchanged) the returned string represents the current parse tree.
     */
    public String getQueryString() {
        return toMdx();
    }

    private void normalizeAxes() {
        for (int i = 0; i < axes.length; i++) {
            AxisOrdinal correctOrdinal = AxisOrdinal.get(i);
            if (axes[i].getAxisOrdinal() != correctOrdinal) {
                for (int j = i + 1; j < axes.length; j++) {
                    if (axes[j].getAxisOrdinal() == correctOrdinal) {
                        // swap axes
                        QueryAxis temp = axes[i];
                        axes[i] = axes[j];
                        axes[j] = temp;
                        break;
                    }
                }
            }
        }
    }

    /**
     * Performs type-checking and validates internal consistency of a query,
     * using the default resolver.
     *
     * <p>This method is called automatically when a query is created; you need
     * to call this method manually if you have modified the query's expression
     * tree in any way.
     */
    public void resolve() {
        resolve(createValidator()); // resolve self and children
    }

    /**
     * Performs type-checking and validates internal consistency of a query.
     *
     * @param validator Validator
     */
    void resolve(Validator validator) {
        if (formulas != null) {
            //resolving of formulas should be done in two parts
            //because formulas might depend on each other, so all calculated
            //mdx elements have to be defined during resolve
            for (int i = 0; i < formulas.length; i++) {
                formulas[i].createElement(validator.getQuery());
            }
            for (int i = 0; i < formulas.length; i++) {
                validator.validate(formulas[i]);
            }
        }

        if (axes != null) {
            for (int i = 0; i < axes.length; i++) {
                validator.validate(axes[i]);
            }
        }
        if (slicer != null) {
            setSlicer(validator.validate(slicer, false));
        }

        // Now that out Parameters have been created (from FunCall's to
        // Parameter() and ParamRef()), resolve them.
        for (int i = 0; i < parameters.length; i++) {
            parameters[i] = validator.validate(parameters[i]);
        }
        resolveParameters();

        // Make sure that no dimension is used on more than one axis.
        final Dimension[] dimensions = getCube().getDimensions();
        for (int i = 0; i < dimensions.length; i++) {
            Dimension dimension = dimensions[i];
            int useCount = 0;
            for (int j = -1; j < axes.length; j++) {
                final Exp axisExp;
                if (j < 0) {
                    if (slicer == null) {
                        continue;
                    }
                    axisExp = slicer;
                } else {
                    axisExp = axes[j].set;
                }
                if (axisExp.getTypeX().usesDimension(dimension)) {
                    ++useCount;
                }
            }
            if (useCount > 1) {
                throw MondrianResource.instance().DimensionInIndependentAxes.ex(
                                dimension.getUniqueName());
            }
        }
    }

    public void unparse(PrintWriter pw) {
        if (formulas != null) {
            for (int i = 0; i < formulas.length; i++) {
                if (i == 0) {
                    pw.print("with ");
                } else {
                    pw.print("  ");
                }
                formulas[i].unparse(pw);
                pw.println();
            }
        }
        pw.print("select ");
        if (axes != null) {
            for (int i = 0; i < axes.length; i++) {
                axes[i].unparse(pw);
                if (i < axes.length - 1) {
                    pw.println(",");
                    pw.print("  ");
                } else {
                    pw.println();
                }
            }
        }
        if (cube != null) {
            pw.println("from [" + cube.getName() + "]");
        }
        if (slicer != null) {
            pw.print("where ");
            slicer.unparse(pw);
            pw.println();
        }
    }

    public String toMdx() {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new QueryPrintWriter(sw);
        unparse(pw);
        return sw.toString();
    }

    /** Returns the MDX query string. */
    public String toString() {
        resolve();
        return toMdx();
    }

    public Object[] getChildren() {
        // Chidren are axes, slicer, and formulas (in that order, to be
        // consistent with replaceChild).
        List list = new ArrayList();
        for (int i = 0; i < axes.length; i++) {
            list.add(axes[i]);
        }
        if (slicer != null) {
            list.add(slicer);
        }
        for (int i = 0; i < formulas.length; i++) {
            list.add(formulas[i]);
        }
        return list.toArray();
    }

    public void replaceChild(int i, QueryPart with) {
        int i0 = i;
        if (i < axes.length) {
            if (with == null) {
                // We need to remove the axis.  Copy the array, omitting
                // element i.
                QueryAxis[] oldAxes = axes;
                axes = new QueryAxis[oldAxes.length - 1];
                for (int j = 0; j < axes.length; j++) {
                    axes[j] = oldAxes[j < i ? j : j + 1];
                }
            } else {
                axes[i] = (QueryAxis) with;
            }
            return;
        }

        i -= axes.length;
        if (i == 0) {
            setSlicer((Exp) with); // replace slicer
            return;
        }

        i -= 1;
        if (i < formulas.length) {
            if (with == null) {
                // We need to remove the formula.  Copy the array, omitting
                // element i.
                Formula[] oldFormulas = formulas;
                formulas = new Formula[oldFormulas.length - 1];
                for (int j = 0; j < formulas.length; j++) {
                    formulas[j] = oldFormulas[j < i ? j : j + 1];
                }
            } else {
                formulas[i] = (Formula) with;
            }
            return;
        }
        throw Util.newInternal(
                "Query child ordinal " + i0 + " out of range (there are " +
                axes.length + " axes, " + formulas.length + " formula)");
    }

    /**
     * Normalize slicer into a tuple of members. For example, '[Time]' becomes
     * '([Time].DefaultMember)'.
     *
     * <p>todo: Make slicer an Axis, not an Exp, and
     * put this code inside Axis.
     */
    public void setSlicer(Exp exp) {
        slicer = exp;
        if (slicer instanceof Level ||
            slicer instanceof Hierarchy ||
            slicer instanceof Dimension) {

            slicer = new FunCall("DefaultMember",
                                 Syntax.Property,
                                 new Exp[] {slicer});
        }

⌨️ 快捷键说明

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