Skip to content

Commit

Permalink
MONDRIAN: Implement Extract function;
Browse files Browse the repository at this point in the history
	when gleaning version number, be more resilient if manifest does not exist.

[git-p4: depot-paths = "//open/mondrian/": change = 9444]
  • Loading branch information
julianhyde committed Jun 11, 2007
1 parent 01ee4f1 commit 69ac0a4
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 50 deletions.
8 changes: 8 additions & 0 deletions src/main/mondrian/olap/MondrianServerImpl.java
Expand Up @@ -111,11 +111,19 @@ private static synchronized MondrianVersion getVersionStatic() {
String vendor = vendorTitleVersion[0];
final String title = vendorTitleVersion[1];
final String versionString = vendorTitleVersion[2];
if (false) {
System.out.println(
"vendor=" + vendor
+ ", title=" + title
+ ", versionString=" + versionString);
}
int dot1 = versionString.indexOf('.');
final int majorVersion =
dot1 < 0 ? 1 :
Integer.valueOf(versionString.substring(0, dot1));
int dot2 = versionString.indexOf('.', dot1 + 1);
final int minorVersion =
dot2 < 0 ? 0 :
Integer.valueOf(versionString.substring(dot1 + 1, dot2));
version = new MondrianVersion() {
public String getVersionString() {
Expand Down
46 changes: 4 additions & 42 deletions src/main/mondrian/olap/fun/BuiltinFunTable.java
Expand Up @@ -937,36 +937,7 @@ public List evaluateList(Evaluator evaluator) {

define(DescendantsFunDef.Resolver);

define(new FunDefBase(
"Distinct",
"Distinct(<Set>)",
"Eliminates duplicate tuples from a set.",
"fxx") {
public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
final ListCalc listCalc =
compiler.compileList(call.getArg(0));
return new AbstractListCalc(call, new Calc[] {listCalc}) {
public List evaluateList(Evaluator evaluator) {
List list = listCalc.evaluateList(evaluator);
return distinct(list);
}
};
}

List<Object> distinct(List list) {
Set<MemberHelper> set = new HashSet<MemberHelper>(list.size());
List<Object> result = new ArrayList<Object>();

for (Object element : list) {
MemberHelper lookupObj = new MemberHelper(element);

if (set.add(lookupObj)) {
result.add(element);
}
}
return result;
}
});
define(DistinctFunDef.instance);

define(DrilldownLevelFunDef.Resolver);

Expand Down Expand Up @@ -1033,17 +1004,7 @@ public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
});

define(ExceptFunDef.Resolver);

if (false) define(new FunDefBase(
"Extract",
"Extract(<Set>, <Dimension>[, <Dimension>...])",
"Returns a set of tuples from extracted dimension elements. The opposite of Crossjoin.",
"fx*") {
public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
throw new UnsupportedOperationException();
}
});

define(ExtractFunDef.Resolver);
define(FilterFunDef.instance);

define(GenerateFunDef.ListResolver);
Expand Down Expand Up @@ -1599,7 +1560,7 @@ public double evaluateDouble(Evaluator evaluator) {
final double v1 = calc1.evaluateDouble(evaluator);
// Null in numerator always returns DoubleNull.
//
// If the mondrian property
// If the mondrian property
// mondrian.olap.NullDenominatorProducesInfinity is true(default),
// Null in denominator with numeric numerator returns infinity.
// This is consistent with MSAS.
Expand Down Expand Up @@ -2210,6 +2171,7 @@ static List<Member> dimensionMembers(
Hierarchy hierarchy = dimension.getHierarchy();
return hierarchyMembers(hierarchy, evaluator, includeCalcMembers);
}

}

// End BuiltinFunTable.java
79 changes: 79 additions & 0 deletions src/main/mondrian/olap/fun/DistinctFunDef.java
@@ -0,0 +1,79 @@
/*
// $Id$
// 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) 2007-2007 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap.fun;

import mondrian.calc.Calc;
import mondrian.calc.ExpCompiler;
import mondrian.calc.ListCalc;
import mondrian.calc.impl.AbstractListCalc;
import mondrian.mdx.ResolvedFunCall;
import mondrian.olap.Evaluator;

import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;

/**
* Definition of the <code>Distinct</code> MDX function.
*
* <p>Syntax:
* <blockquote><code>Distinct(&lt;Set&gt;)</code></blockquote>
*
* @author jhyde
* @version $Id$
* @since Jun 10, 2007
*/
class DistinctFunDef extends FunDefBase {
public static final DistinctFunDef instance = new DistinctFunDef();

private DistinctFunDef() {
super("Distinct",
"Distinct(<Set>)",
"Eliminates duplicate tuples from a set.",
"fxx");
}

public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
final ListCalc listCalc =
compiler.compileList(call.getArg(0));
return new CalcImpl(call, listCalc);
}

static class CalcImpl extends AbstractListCalc {
private final ListCalc listCalc;

public CalcImpl(ResolvedFunCall call, ListCalc listCalc) {
super(call, new Calc[]{listCalc});
this.listCalc = listCalc;
}

public List evaluateList(Evaluator evaluator) {
List list = listCalc.evaluateList(evaluator);
return distinct(list);
}

static List<Object> distinct(List list) {
Set<MemberHelper> set = new HashSet<MemberHelper>(list.size());
List<Object> result = new ArrayList<Object>();

for (Object element : list) {
MemberHelper lookupObj = new MemberHelper(element);

if (set.add(lookupObj)) {
result.add(element);
}
}
return result;
}
}
}

// End DistinctFunDef.java
225 changes: 225 additions & 0 deletions src/main/mondrian/olap/fun/ExtractFunDef.java
@@ -0,0 +1,225 @@
/*
// $Id$
// 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) 2007-2007 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.olap.fun;

import mondrian.calc.Calc;
import mondrian.calc.ExpCompiler;
import mondrian.calc.ListCalc;
import mondrian.calc.impl.AbstractListCalc;
import mondrian.mdx.ResolvedFunCall;
import mondrian.mdx.DimensionExpr;
import mondrian.olap.*;
import mondrian.olap.type.*;

import java.util.*;

/**
* Definition of the <code>Extract</code> MDX function.
*
* <p>Syntax:
* <blockquote><code>Extract(&lt;Set&gt;, &lt;Dimension&gt;[,
* &lt;Dimension&gt;...])</code></blockquote>
*
* @author jhyde
* @version $Id$
* @since Jun 10, 2007
*/
class ExtractFunDef extends FunDefBase {
static final ResolverBase Resolver = new ResolverBase(
"Extract",
"Extract(<Set>, <Dimension>[, <Dimension>...])",
"Returns a set of tuples from extracted dimension elements. The opposite of Crossjoin.",
Syntax.Function) {

public FunDef resolve(
Exp[] args, Validator validator, int[] conversionCount) {
if (args.length < 2) {
return null;
}
if (!validator.canConvert(
args[0], Category.Set, conversionCount)) {
return null;
}
for (int i = 1; i < args.length; ++i) {
if (!validator.canConvert(
args[i], Category.Dimension, conversionCount)) {
return null;
}
}

// Find the dimensionality of the set expression.

// Form a list of ordinals of the dimensions being extracted.
// For example, in
// Extract(X.Members * Y.Members * Z.Members, Z, X)
// the dimension ordinals are X=0, Y=1, Z=2, and the extracted
// ordinals are {2, 0}.
//
// Each dimension extracted must exist in the LHS,
// and no dimension may be extracted more than once.
List<Integer> extractedOrdinals = new ArrayList<Integer>();
final List<Dimension> extractedDimensions = new ArrayList<Dimension>();
findExtractedDimensions(args, extractedDimensions, extractedOrdinals);
int[] parameterTypes = new int[args.length];
parameterTypes[0] = Category.Set;
Arrays.fill(parameterTypes, 1, parameterTypes.length, Category.Dimension);
return new ExtractFunDef(this, Category.Set, parameterTypes);
}
};

private ExtractFunDef(
Resolver resolver, int returnType, int[] parameterTypes)
{
super(resolver, returnType, parameterTypes);
}

public Type getResultType(Validator validator, Exp[] args) {
final List<Dimension> extractedDimensions =
new ArrayList<Dimension>();
final List<Integer> extractedOrdinals = new ArrayList<Integer>();
findExtractedDimensions(args, extractedDimensions, extractedOrdinals);
if (extractedDimensions.size() == 1) {
return new SetType(
new MemberType(extractedDimensions.get(0), null, null, null));
} else {
List<Type> typeList = new ArrayList<Type>();
for (Dimension extractedDimension : extractedDimensions) {
typeList.add(
new MemberType(
extractedDimension, null, null, null));
}
return new SetType(
new TupleType(
typeList.toArray(new Type[typeList.size()])));
}
}

private static void findExtractedDimensions(
Exp[] args,
List<Dimension> extractedDimensions,
List<Integer> extractedOrdinals)
{
SetType type = (SetType) args[0].getType();
final List<Dimension> dimensions = new ArrayList<Dimension>();
if (type.getElementType() instanceof TupleType) {
for (Type elementType : ((TupleType) type
.getElementType()).elementTypes) {
Dimension dimension = elementType.getDimension();
if (dimension == null) {
throw new RuntimeException("dimension of argument not known");
}
dimensions.add(dimension);
}
} else {
Dimension dimension = type.getDimension();
if (dimension == null) {
throw new RuntimeException("dimension of argument not known");
}
dimensions.add(dimension);
}

for (int i = 1; i < args.length; i++) {
Exp arg = args[i];
if (arg instanceof DimensionExpr) {
DimensionExpr dimensionExpr = (DimensionExpr) arg;
final Dimension extractedDimension =
dimensionExpr.getDimension();
int ordinal = dimensions.indexOf(extractedDimension);
if (ordinal == -1) {
throw new RuntimeException(
"dimension " +
extractedDimension.getUniqueName() +
" is not a dimension of the expression " + args[0]);
}
if (extractedOrdinals.indexOf(ordinal) >= 0) {
throw new RuntimeException(
"dimension " +
extractedDimension.getUniqueName() +
" is extracted more than once");
}
extractedOrdinals.add(ordinal);
extractedDimensions.add(extractedDimension);
} else {
throw new RuntimeException("not a constant dimension: " + arg);
}
}
}

private static int[] toIntArray(List<Integer> integerList) {
final int[] ints = new int[integerList.size()];
for (int i = 0; i < ints.length; i++) {
ints[i] = integerList.get(i);
}
return ints;
}

public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
List<Dimension> extractedDimensionList = new ArrayList<Dimension>();
List<Integer> extractedOrdinalList = new ArrayList<Integer>();
findExtractedDimensions(
call.getArgs(),
extractedDimensionList,
extractedOrdinalList);
Util.assertTrue(
extractedOrdinalList.size() == extractedDimensionList.size());
Exp arg = call.getArg(0);
final ListCalc listCalc = compiler.compileList(arg, false);
int inArity = ((SetType) arg.getType()).getArity();
final int outArity = extractedOrdinalList.size();
if (inArity == 1) {
// LHS is a set of members, RHS is the same dimension. Extract boils
// down to eliminating duplicate members.
Util.assertTrue(outArity == 1);
return new DistinctFunDef.CalcImpl(call, listCalc);
}
final int[] extractedOrdinals = toIntArray(extractedOrdinalList);
if (outArity == 1) {
return new AbstractListCalc(call, new Calc[] {listCalc}) {
public List evaluateList(Evaluator evaluator) {
List<Member> result = new ArrayList<Member>();
List<Member[]> list = listCalc.evaluateList(evaluator);
Set<Member> emittedMembers = new HashSet<Member>();
for (Member[] members : list) {
Member outMember = members[extractedOrdinals[0]];
if (emittedMembers.contains(outMember)) {
continue;
}
emittedMembers.add(outMember);
result.add(outMember);
}
return result;
}
};
} else {
return new AbstractListCalc(call, new Calc[] {listCalc}) {
public List evaluateList(Evaluator evaluator) {
List<Member[]> result = new ArrayList<Member[]>();
List<Member[]> list = listCalc.evaluateList(evaluator);
Set<List<Member>> emittedTuples = new HashSet<List<Member>>();
for (Member[] members : list) {
Member[] outMembers = new Member[outArity];
for (int i = 0; i < outMembers.length; i++) {
outMembers[i] = members[extractedOrdinals[i]];
}
final List<Member> outTuple = Arrays.asList(outMembers);
if (emittedTuples.contains(outTuple)) {
continue;
}
emittedTuples.add(outTuple);
result.add(outMembers);
}
return result;
}
};
}
}
}

// End ExtractFunDef.java

0 comments on commit 69ac0a4

Please sign in to comment.