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 + -
显示快捷键?