use of mondrian.mdx.UnresolvedFunCall in project mondrian by pentaho.
the class ParserTest method testMultipleAxes.
public void testMultipleAxes() throws Exception {
TestParser p = createParser();
String query = "select {[axis0mbr]} on axis(0), " + "{[axis1mbr]} on axis(1) from cube";
assertNull("Test parser should return null query", p.parseInternal(null, query, false, funTable, false));
QueryAxis[] axes = p.getAxes();
assertEquals("Number of axes", 2, axes.length);
assertEquals("Axis index name must be correct", AxisOrdinal.StandardAxisOrdinal.forLogicalOrdinal(0).name(), axes[0].getAxisName());
assertEquals("Axis index name must be correct", AxisOrdinal.StandardAxisOrdinal.forLogicalOrdinal(1).name(), axes[1].getAxisName());
query = "select {[axis1mbr]} on aXiS(1), " + "{[axis0mbr]} on AxIs(0) from cube";
assertNull("Test parser should return null query", p.parseInternal(null, query, false, funTable, false));
assertEquals("Number of axes", 2, axes.length);
assertEquals("Axis index name must be correct", AxisOrdinal.StandardAxisOrdinal.forLogicalOrdinal(0).name(), axes[0].getAxisName());
assertEquals("Axis index name must be correct", AxisOrdinal.StandardAxisOrdinal.forLogicalOrdinal(1).name(), axes[1].getAxisName());
Exp colsSetExpr = axes[0].getSet();
assertNotNull("Column tuples", colsSetExpr);
UnresolvedFunCall fun = (UnresolvedFunCall) colsSetExpr;
Id arg0 = (Id) (fun.getArgs()[0]);
Id.NameSegment id = (Id.NameSegment) arg0.getElement(0);
assertEquals("Correct member on axis", "axis0mbr", id.name);
Exp rowsSetExpr = axes[1].getSet();
assertNotNull("Row tuples", rowsSetExpr);
fun = (UnresolvedFunCall) rowsSetExpr;
arg0 = (Id) (fun.getArgs()[0]);
id = (Id.NameSegment) arg0.getElement(0);
assertEquals("Correct member on axis", "axis1mbr", id.name);
}
use of mondrian.mdx.UnresolvedFunCall in project mondrian by pentaho.
the class Util method lookup.
/**
* Converts an identifier into an expression by resolving its parts into
* an OLAP object (dimension, hierarchy, level or member) within the
* context of a query.
*
* <p>If <code>allowProp</code> is true, also allows property references
* from valid members, for example
* <code>[Measures].[Unit Sales].FORMATTED_VALUE</code>.
* In this case, the result will be a {@link ResolvedFunCall}.
*
* @param q Query expression belongs to
* @param schemaReader Schema reader
* @param segments Parts of the identifier
* @param allowProp Whether to allow property references
* @return OLAP object or property reference
*/
public static Exp lookup(Query q, SchemaReader schemaReader, List<Id.Segment> segments, boolean allowProp) {
// First, look for a calculated member defined in the query.
final String fullName = quoteMdxIdentifier(segments);
// Look for any kind of object (member, level, hierarchy,
// dimension) in the cube. Use a schema reader without restrictions.
final SchemaReader schemaReaderSansAc = schemaReader.withoutAccessControl().withLocus();
final Cube cube = q.getCube();
OlapElement olapElement = schemaReaderSansAc.lookupCompound(cube, segments, false, Category.Unknown);
if (olapElement != null) {
Role role = schemaReader.getRole();
if (!role.canAccess(olapElement)) {
olapElement = null;
}
if (olapElement instanceof Member) {
olapElement = schemaReader.substitute((Member) olapElement);
}
}
if (olapElement == null) {
if (allowProp && segments.size() > 1) {
List<Id.Segment> segmentsButOne = segments.subList(0, segments.size() - 1);
final Id.Segment lastSegment = last(segments);
final String propertyName = lastSegment instanceof Id.NameSegment ? ((Id.NameSegment) lastSegment).getName() : null;
final Member member = (Member) schemaReaderSansAc.lookupCompound(cube, segmentsButOne, false, Category.Member);
if (member != null && propertyName != null && isValidProperty(propertyName, member.getLevel())) {
return new UnresolvedFunCall(propertyName, Syntax.Property, new Exp[] { createExpr(member) });
}
final Level level = (Level) schemaReaderSansAc.lookupCompound(cube, segmentsButOne, false, Category.Level);
if (level != null && propertyName != null && isValidProperty(propertyName, level)) {
return new UnresolvedFunCall(propertyName, Syntax.Property, new Exp[] { createExpr(level) });
}
}
// hierarchy by incrementally truncating the name of the element
if (q.ignoreInvalidMembers()) {
int nameLen = segments.size() - 1;
olapElement = null;
while (nameLen > 0 && olapElement == null) {
List<Id.Segment> partialName = segments.subList(0, nameLen);
olapElement = schemaReaderSansAc.lookupCompound(cube, partialName, false, Category.Unknown);
nameLen--;
}
if (olapElement != null) {
olapElement = olapElement.getHierarchy().getNullMember();
} else {
throw MondrianResource.instance().MdxChildObjectNotFound.ex(fullName, cube.getQualifiedName());
}
} else {
throw MondrianResource.instance().MdxChildObjectNotFound.ex(fullName, cube.getQualifiedName());
}
}
// keep track of any measure members referenced; these will be used
// later to determine if cross joins on virtual cubes can be
// processed natively
q.addMeasuresMembers(olapElement);
return createExpr(olapElement);
}
use of mondrian.mdx.UnresolvedFunCall in project mondrian by pentaho.
the class AbstractExpCompiler method registerParameter.
public ParameterSlot registerParameter(Parameter parameter) {
ParameterSlot slot = parameterSlots.get(parameter);
if (slot != null) {
return slot;
}
int index = parameterSlots.size();
ParameterSlotImpl slot2 = new ParameterSlotImpl(parameter, index);
parameterSlots.put(parameter, slot2);
slot2.value = parameter.getValue();
// Compile the expression only AFTER the parameter has been
// registered with a slot. Otherwise a cycle is possible.
final Type type = parameter.getType();
Exp defaultExp = parameter.getDefaultExp();
Calc calc;
if (type instanceof ScalarType) {
if (!defaultExp.getType().equals(type)) {
defaultExp = new UnresolvedFunCall("Cast", Syntax.Cast, new Exp[] { defaultExp, Literal.createSymbol(Category.instance.getName(TypeUtil.typeToCategory(type))) });
defaultExp = getValidator().validate(defaultExp, true);
}
calc = compileScalar(defaultExp, true);
} else {
calc = compileAs(defaultExp, type, resultStyles);
}
slot2.setDefaultValueCalc(calc);
return slot2;
}
use of mondrian.mdx.UnresolvedFunCall in project mondrian by pentaho.
the class DescendantsFunDef method compileCall.
public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
final Type type0 = call.getArg(0).getType();
if (type0 instanceof SetType) {
final SetType setType = (SetType) type0;
if (setType.getElementType() instanceof TupleType) {
throw MondrianResource.instance().DescendantsAppliedToSetOfTuples.ex();
}
MemberType memberType = (MemberType) setType.getElementType();
final Hierarchy hierarchy = memberType.getHierarchy();
if (hierarchy == null) {
throw MondrianResource.instance().CannotDeduceTypeOfSet.ex();
}
// Convert
// Descendants(<set>, <args>)
// into
// Generate(<set>, Descendants(<dimension>.CurrentMember, <args>))
Exp[] descendantsArgs = call.getArgs().clone();
descendantsArgs[0] = new UnresolvedFunCall("CurrentMember", Syntax.Property, new Exp[] { new HierarchyExpr(hierarchy) });
final ResolvedFunCall generateCall = (ResolvedFunCall) compiler.getValidator().validate(new UnresolvedFunCall("Generate", new Exp[] { call.getArg(0), new UnresolvedFunCall("Descendants", descendantsArgs) }), false);
return generateCall.accept(compiler);
}
final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
Flag flag = Flag.SELF;
if (call.getArgCount() == 1) {
flag = Flag.SELF_BEFORE_AFTER;
}
final boolean depthSpecified = call.getArgCount() >= 2 && call.getArg(1).getType() instanceof NumericType;
final boolean depthEmpty = call.getArgCount() >= 2 && call.getArg(1).getType() instanceof EmptyType;
if (call.getArgCount() >= 3) {
flag = FunUtil.getLiteralArg(call, 2, Flag.SELF, Flag.class);
}
if (call.getArgCount() >= 2 && depthEmpty) {
if (flag != Flag.LEAVES) {
throw Util.newError("depth must be specified unless DESC_FLAG is LEAVES");
}
}
if ((depthSpecified || depthEmpty) && flag.leaves) {
final IntegerCalc depthCalc = depthSpecified ? compiler.compileInteger(call.getArg(1)) : null;
return new AbstractListCalc(call, new Calc[] { memberCalc, depthCalc }) {
public TupleList evaluateList(Evaluator evaluator) {
final Member member = memberCalc.evaluateMember(evaluator);
List<Member> result = new ArrayList<Member>();
int depth = -1;
if (depthCalc != null) {
depth = depthCalc.evaluateInteger(evaluator);
if (depth < 0) {
// no limit
depth = -1;
}
}
final SchemaReader schemaReader = evaluator.getSchemaReader();
descendantsLeavesByDepth(member, result, schemaReader, depth);
hierarchizeMemberList(result, false);
return new UnaryTupleList(result);
}
};
} else if (depthSpecified) {
final IntegerCalc depthCalc = compiler.compileInteger(call.getArg(1));
final Flag flag1 = flag;
return new AbstractListCalc(call, new Calc[] { memberCalc, depthCalc }) {
public TupleList evaluateList(Evaluator evaluator) {
final Member member = memberCalc.evaluateMember(evaluator);
List<Member> result = new ArrayList<Member>();
final int depth = depthCalc.evaluateInteger(evaluator);
final SchemaReader schemaReader = evaluator.getSchemaReader();
descendantsByDepth(member, result, schemaReader, depth, flag1.before, flag1.self, flag1.after, evaluator);
hierarchizeMemberList(result, false);
return new UnaryTupleList(result);
}
};
} else {
final LevelCalc levelCalc = call.getArgCount() > 1 ? compiler.compileLevel(call.getArg(1)) : null;
final Flag flag2 = flag;
return new AbstractListCalc(call, new Calc[] { memberCalc, levelCalc }) {
public TupleList evaluateList(Evaluator evaluator) {
final Evaluator context = evaluator.isNonEmpty() ? evaluator : null;
final Member member = memberCalc.evaluateMember(evaluator);
List<Member> result = new ArrayList<Member>();
final SchemaReader schemaReader = evaluator.getSchemaReader();
final Level level = levelCalc != null ? levelCalc.evaluateLevel(evaluator) : member.getLevel();
descendantsByLevel(schemaReader, member, level, result, flag2.before, flag2.self, flag2.after, flag2.leaves, context);
hierarchizeMemberList(result, false);
return new UnaryTupleList(result);
}
};
}
}
Aggregations