/* // $Id: //guest/julian_hyde/mondrian/src/main/mondrian/olap/FunDef.java#1 $ // 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 1999-2002 Kana Software, Inc. and others. // All Rights Reserved. // You must accept the terms of that agreement to use this software. // // jhyde, 21 April, 1999 */ package mondrian.olap; import java.util.*; import java.math.BigDecimal; /** * MDX function definitions. **/ public class FunDef { /** * Constructor is private, because outside world gets definitions via * definition table. **/ FunDef(int type, String name, String usage, String desc, int flags) { this.type = type; this.name = name; this.usage = usage; this.flags = flags; } FunDef(int type, String name, String usage, String desc) { this(type, name, usage, desc, 0); } // Members String name; int type; // must be Exp.CatUnknown..Exp.CatTuple int flags; String usage; static Hashtable upperName2Def; // lookup function definition by its name static Hashtable sig2Def; // lookup function by its signature static Hashtable propertyFunNames; //lookup of property functions /** @return whether function is invoked 'object.METHOD(args)' or * 'object.METHOD()' */ boolean isMethod() { return (flags & FlagMethod) != 0; } /** whether function is invoked 'object.PROPERTY' */ boolean isProperty() { return (flags & FlagProperty) != 0; } /** whether function is an infix operator (like '+') */ boolean isInfix() { return (flags & FlagInfix) != 0; } /** whether function is a prefix operator (like unary '-') */ boolean isPrefix() { return (flags & FlagPrefix) != 0; } static boolean isFunction(String name) { FunDef def = (FunDef) upperName2Def.get(name.toUpperCase()); return def != null || isOverloaded(name); } static boolean isProperty(String name) { FunDef def = (FunDef) upperName2Def.get(name.toUpperCase()); return ((def != null && def.isProperty()) || ( propertyFunNames.get(name.toUpperCase()) != null )); } /** * This function returns whether a particular function occurs more than * once in the array. For each function name here, there MUST be a handler * in getDef(). */ private static boolean isOverloaded(String name) { return name.equalsIgnoreCase("CoalesceEmpty") || name.equalsIgnoreCase("Dimension") || name.equalsIgnoreCase("Dimensions") || name.equalsIgnoreCase("Hierarchy") || name.equalsIgnoreCase("IIf") || name.equalsIgnoreCase("Item") || name.equalsIgnoreCase("Levels") || name.equalsIgnoreCase("Members") || name.equalsIgnoreCase("Name") || name.equalsIgnoreCase("UniqueName") || name.equalsIgnoreCase("Parameter"); } /** * This function returns whether a particular function can be used as * a property */ private static boolean isPropertyName(String name) { return name.equalsIgnoreCase("CoalesceEmpty") || name.equalsIgnoreCase("Dimension") || name.equalsIgnoreCase("Dimensions") || name.equalsIgnoreCase("Hierarchy") || name.equalsIgnoreCase("IIf") || name.equalsIgnoreCase("Item") || name.equalsIgnoreCase("Levels") || name.equalsIgnoreCase("Members") || name.equalsIgnoreCase("Name") || name.equalsIgnoreCase("UniqueName") || name.equalsIgnoreCase("Parameter"); } static private boolean stringEqual( String s1, String s2, boolean bIgnoreCase) { return bIgnoreCase ? s1.equalsIgnoreCase(s2) : s1.equals(s2); } /** * Get the return type when a function called "name" is applied as in * "call". */ static FunDef getDef(FunCall call) { boolean bIgnoreCase = true; // this may become a parameter String sName = call.getFunName(); String sUpperName = sName.toUpperCase(); // 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. FunDef def = (FunDef) upperName2Def.get(sUpperName); if (def != null) { return def; } else if (stringEqual(sName,"CoalesceEmpty",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatNumeric: return (FunDef) sig2Def.get("CoalesceEmpty(<Numeric Expression>[, <Numeric Expression>]...)"); case Exp.CatString: return (FunDef) sig2Def.get("CoalesceEmpty(<String Expression>[, <String Expression>]...)"); } } else if (stringEqual(sName,"Dimension",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatHierarchy: case Exp.CatDimension: return (FunDef) sig2Def.get("<Hierarchy>.Dimension"); case Exp.CatLevel: return (FunDef) sig2Def.get("<Level>.Dimension"); case Exp.CatMember: return (FunDef) sig2Def.get("<Member>.Dimension"); } } else if (stringEqual(sName,"Dimensions",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatNumeric: return (FunDef) sig2Def.get("Dimensions(<Numeric Expression>)"); case Exp.CatString: return (FunDef) sig2Def.get("Dimensions(<String Expression>)"); } } else if (stringEqual(sName,"Hierarchy",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatLevel: return (FunDef) sig2Def.get("<Level>.Hierarchy"); case Exp.CatMember: return (FunDef) sig2Def.get("<Member>.Hierarchy"); } } else if (stringEqual(sName,"IIf",bIgnoreCase)) { // 2 forms, look at type of 1th arg. switch (call.args[1].getCategory()) { case Exp.CatNumeric: return (FunDef) sig2Def.get("IIf(<Logical Expression>, <Numeric Expression1>, <Numeric Expression2>)"); case Exp.CatString: return (FunDef) sig2Def.get("IIf(<Logical Expression>, <String Expression1>, <String Expression2>)"); } } else if (stringEqual(sName,"Item",bIgnoreCase)) { // Two forms: // <Tuple>.Item(<Numeric Expression>) // returns member // <Set>.Item(<String Expression>, ...) // returns tuple switch (call.args[0].getCategory()) { case Exp.CatTuple: return (FunDef) sig2Def.get("<Tuple>.Item(<Numeric Expression>)"); case Exp.CatSet: return (FunDef) sig2Def.get("<Set>.Item(<String Expression>[, <String Expression>...] | <Index>)"); } } else if (stringEqual(sName,"Levels",bIgnoreCase)) { if (call.invokedOnObject()) { if (call.args[0].getCategory() == Exp.CatDimension) { return (FunDef) sig2Def.get("<Dimension>.Levels(<Numeric Expression>)"); } // e.g. <Member>.Levels() --> drop through, crash and burn } else { return (FunDef) sig2Def.get("Levels(<String Expression>)"); } } else if (stringEqual(sName,"Members",bIgnoreCase)) { if (call.invokedOnObject()) { switch (call.args[0].getCategory()) { case Exp.CatDimension: case Exp.CatMember: return (FunDef) sig2Def.get("<Dimension>.Members"); case Exp.CatHierarchy: return (FunDef) sig2Def.get("<Hierarchy>.Members"); case Exp.CatLevel: return (FunDef) sig2Def.get("<Level>.Members"); } } else { return (FunDef) sig2Def.get("Members(<String Expression>)"); } } else if (stringEqual(sName,"Name",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatDimension: return (FunDef) sig2Def.get("<Dimension>.Name"); case Exp.CatHierarchy: return (FunDef) sig2Def.get("<Hierarchy>.Name"); case Exp.CatLevel: return (FunDef) sig2Def.get("<Level>.Name"); case Exp.CatMember: return (FunDef) sig2Def.get("<Member>.Name"); } } else if (stringEqual(sName,"UniqueName",bIgnoreCase)) { switch (call.args[0].getCategory()) { case Exp.CatDimension: return (FunDef) sig2Def.get("<Dimension>.UniqueName"); case Exp.CatHierarchy: return (FunDef) sig2Def.get("<Hierarchy>.UniqueName"); case Exp.CatLevel: return (FunDef) sig2Def.get("<Level>.UniqueName"); case Exp.CatMember: return (FunDef) sig2Def.get("<Member>.UniqueName"); } } // Have never heard of this function before... make one up. // "PROPERTIES" is handled like this. return new FunDef( Exp.CatUnknown, sName, sName, "", call.invokedOnObject() ? FlagMethod : FlagNone); } /** * Get the return type when a function called "name" is applied as in * "call". * * Obsolete!! */ static int getReturnType(FunCall call) { boolean bIgnoreCase = true; // this may become a parameter String sName = call.getFunName(); String sUpperName = sName.toUpperCase(); FunDef def = (FunDef) upperName2Def.get(sUpperName); if (def != null) { return def.type; } else if (stringEqual(sName,"CoalesceEmpty",bIgnoreCase)) { // Two forms, always returns type of 0th arg: // CoalesceEmpty(StringExpression[,StringExpression]...) // CoalesceEmpty(NumericExpression[,NumericExpression]...) return call.args[0].getCategory(); } else if (stringEqual(sName,"Dimension",bIgnoreCase)) { // 3 forms, always returns dimension: // <Hierarchy>.Dimension // <Level>.Dimension // <Member>.Dimension return Exp.CatDimension; } else if (stringEqual(sName,"Dimensions",bIgnoreCase)) { // 2 forms, always returns dimension: // Dimensions(<StringExpression>) // Dimensions(<NumericExpression>) return Exp.CatDimension; } else if (stringEqual(sName,"Hierarchy",bIgnoreCase)) { // 2 forms, always returns hierarchy: // <Level>.Hierarchy // <Member>.Hierarchy return Exp.CatHierarchy; } else if (stringEqual(sName,"IIf",bIgnoreCase)) { // 2 forms, always returns type of 1th arg: // IIf(<LogicalExpression>,<NumericExpression>,<NumericExpression>) // IIf(<LogicalExpression>,<StringExpression>,<StringExpression>) return call.args[1].getCategory(); } else if (stringEqual(sName,"Item",bIgnoreCase)) { // <Tuple>.Item(<Numeric Expression>) // returns member // <Set>.Item(<String Expression>, ...) // returns tuple return call.args[0].getCategory() == Exp.CatTuple ? Exp.CatMember : Exp.CatTuple; } else if (stringEqual(sName,"Levels",bIgnoreCase)) { // 2 forms, always returns level: // <Dimension>.Levels (<Numeric Expression>) // Levels(<String Expression>) return Exp.CatLevel; } else if (stringEqual(sName,"Members",bIgnoreCase)) { // 4 forms, returns a member when a function, a set when a method // Members(<String Expression>) // <Dimension>.Members // <Hierarchy>.Members // <Level>.Members return call.invokedOnObject() ? Exp.CatSet : Exp.CatMember; } else if (stringEqual(sName,"Name",bIgnoreCase)) { // 4 forms, always a string: // <Dimension>.Name // <Hierarchy>.Name // <Level>.Name // <Member>.Name return Exp.CatString; } else if (stringEqual(sName,"UniqueName",bIgnoreCase)) { // 4 forms, always a string: // <Dimension>.UniqueName // <Hierarchy>.UniqueName // <Level>.UniqueName // <Member>.UniqueName return Exp.CatString; } else { throw Util.getRes().newMdxFuncUnknown(call.getFunName()); } } /** * Return the hierarchy of <code>call</code>, or null if no dimension is * defined. * * @see Exp#getHierarchy */ Hierarchy getHierarchy(FunCall call) { if (type != Exp.CatSet && type != Exp.CatTuple) { if(type == Exp.CatMember || type == Exp.CatHierarchy) { return (call.args[0]).getHierarchy(); } else { // only CatHierarchy and CatMember expressions have a // Hierarchy return null; } } else if ((flags & FlagDimDeriv) != 0) { // We derive the Hierarchy of this function in a non-standard way. if (name.equals("Crossjoin")) { // CROSSJOIN(<Set1>,<Set2>) has Hierarchy [Hie1] x [Hie2], // which we can't represent, so we return null. return null; } else if (name.equals("_Tuple")) { // _Tuple(<Member1>[,<MemberI>]...), which is written // (<Member1>[,<MemberI>]...), has Hierarchy [Hie1] x ... x // [HieN], which we can't represent, so we return null. But if // there is only one member, it merely represents a // parenthesized expression, whose Hierarchy is that of the // member. return (call.args.length == 1) ? call.args[0].getHierarchy() : null; } else if (name.equals("_Set")) { // All of the members in _Set(<Member1>[,<MemberI>]...), which // is written {<Member1>[,<MemberI>]...}, must have the same // Hierarchy. But if there are no members, we can't derive a // Hierarchy, so we return null. return (call.args.length == 0) ? null : call.args[0].getHierarchy(); } else if (name.equalsIgnoreCase("StrToTuple") || name.equalsIgnoreCase("StrToSet")) { // StrToTuple(s, <Hie1>, ... <HieN>) is of type [Hie1] x ... x // [HieN]; so, for example, So StrToTuple("[Time].[1997]", // [Time]) is of type [Time]. But if n > 1, we cannot // represent the compound type, and we return null. return (call.args.length == 2) ? (Hierarchy) call.args[1] : null; } else if (name.equals("_Parentheses")) { Util.assert(call.args.length == 1); return call.args[0].getHierarchy(); } else { Util.assert( false, "cannot derive hierarchy for function '" + name + "'"); return null; } } else { // We derive the dimension of this function in the standard way: it // is the same as the 0th arg. int iArg = 0; Exp arg = call.args[iArg]; return arg.getHierarchy(); } } /** * Evaluates this function with the given set of expressions. The * implementation will often evaluate the expressions first. For example, * <code>TopCount([Promotion Media].members, 2 + 3, [Measures].[Unit * Sales])</code> would evaluate the first and second arguments, but not * the third. **/ public Object evaluate(Evaluator evaluator, Exp[] args) { throw new Error("mdx function '" + this.name + "' is not implemented"); } // Flags to FunDef() static final int FlagNone = 0; /** * Functions are invoked 3 ways: * 1. object.PROPERTY; * 2. object.METHOD() or object.METHOD(args); * 3. FUNCTION() or FUNCTION(args). * * FlagProperty is set in 'flags' for type 1; FlagMethod is set for type 2; * neither for type 3. */ static final int FlagProperty = 1; /** @see FlagProperty */ static final int FlagMethod = 2; /** set in 'flags' if function's derivation is not computed by looking at * the dimensionality of its first argument. */ static final int FlagDimDeriv = 4; /** set in 'flags' if function is an infix operator, like '+' or 'AND' */ static final int FlagInfix = 8; /** set in 'flags' if function is an infix operator, like unary '-' */ static final int FlagPrefix = 16; public static synchronized void init() { makeFunctionCategoryTable(); } private static void makeFunctionCategoryTable() { // Populate a hash table with the definitions of all functions which // are not overloaded. Have to use code to resolve the overloaded // ones. upperName2Def = new Hashtable(); sig2Def = new Hashtable(); Hashtable dupNames = new Hashtable(); propertyFunNames = new Hashtable(); for (int i = 0; i < FunDefTable.funDefs.length; i++) { FunDef funDef = FunDefTable.funDefs[i]; sig2Def.put(funDef.usage, funDef); String sUpperName = funDef.name.toUpperCase(); //FunName is considered to be property function, if it is used // as <Expression>.FunName if( funDef.isProperty() && propertyFunNames.get( sUpperName ) == null ){ propertyFunNames.put( sUpperName, funDef ); } if (dupNames.get(sUpperName) != null) { continue; } else if (upperName2Def.get(sUpperName) != null) { dupNames.put(sUpperName,funDef); // record that name is duped upperName2Def.remove(sUpperName); // remove from table Util.assert( FunDef.isOverloaded(sUpperName), "function '" + sUpperName + "' should not be overloaded"); } else { upperName2Def.put(sUpperName, funDef); } } } } class FunDefTable extends Util { static FunDef[] funDefs = { // ARRAY FUNCTIONS new FunDef(Exp.CatArray, "SetToArray", "SetToArray(<Set>[, <Set>]...[, <Numeric Expression>])", "Converts one or more sets to an array for use in a user-defined function."), // // DIMENSION FUNCTIONS new FunDef(Exp.CatDimension, "Dimension", "<Hierarchy>.Dimension", "Returns the dimension that contains a specified hierarchy.", FunDef.FlagProperty), new FunDef(Exp.CatDimension, "Dimension", "<Level>.Dimension", "Returns the dimension that contains a specified level.", FunDef.FlagProperty), new FunDef(Exp.CatDimension, "Dimension", "<Member>.Dimension", "Returns the dimension that contains a specified member.", FunDef.FlagProperty), new FunDef(Exp.CatDimension, "Dimensions", "Dimensions(<Numeric Expression>)", "Returns the dimension whose zero-based position within the cube is specified by a numeric expression."), new FunDef(Exp.CatDimension, "Dimensions", "Dimensions(<String Expression>)", "Returns the dimension whose name is specified by a string."), // // HIERARCHY FUNCTIONS new FunDef(Exp.CatHierarchy, "Hierarchy", "<Level>.Hierarchy", "Returns a level's hierarchy.", FunDef.FlagProperty), new FunDef(Exp.CatHierarchy, "Hierarchy", "<Member>.Hierarchy", "Returns a member's hierarchy.", FunDef.FlagProperty), // // LEVEL FUNCTIONS new FunDef(Exp.CatLevel, "Level", "<Member>.Level", "Returns a member's level.", FunDef.FlagProperty), new FunDef(Exp.CatLevel, "Levels", "<Dimension>.Levels(<Numeric Expression>)", "Returns the level whose position in a dimension is specified by a numeric expression.", FunDef.FlagMethod), new FunDef(Exp.CatLevel, "Levels", "Levels(<String Expression>)", "Returns the level whose name is specified by a string expression."), // // LOGICAL FUNCTIONS new FunDef(Exp.CatLogical, "IsEmpty", "IsEmpty(<Value Expression>)", "Determines if an expression evaluates to the empty cell value."), // // MEMBER FUNCTIONS new FunDef(Exp.CatMember, "Ancestor", "Ancestor(<Member>, <Level>)", "Returns the ancestor of a member at a specified level."), new FunDef(Exp.CatMember, "ClosingPeriod", "ClosingPeriod([<Level>[, <Member>]])", "Returns the last sibling among the descendants of a member at a level."), new FunDef(Exp.CatMember, "Cousin", "Cousin(<Member1>, <Member2>)", "Returns the member with the same relative position under a member as the member specified."), new FunDef(Exp.CatMember, "CurrentMember", "<Dimension>.CurrentMember", "Returns the current member along a dimension during an iteration.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "DefaultMember", "<Dimension>.DefaultMember", "Returns the default member of a dimension.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Hierarchy hierarchy = getHierarchyArg(evaluator, args, 0, true); return hierarchy.getDefaultMember(); } }, new FunDef(Exp.CatMember, "FirstChild", "<Member>.FirstChild", "Returns the first child of a member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "FirstSibling", "<Member>.FirstSibling", "Returns the first child of the parent of a member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "Item", "<Tuple>.Item(<Numeric Expression>)", "Returns a member from a tuple.", FunDef.FlagMethod), new FunDef(Exp.CatMember, "Lag", "<Member>.Lag(<Numeric Expression>)", "Returns a member prior to the specified member along the member's dimension.", FunDef.FlagMethod), new FunDef(Exp.CatMember, "LastChild", "<Member>.LastChild", "Returns the last child of a member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "LastSibling", "<Member>.LastSibling", "Returns the last child of the parent of a member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "Lead", "<Member>.Lead(<Numeric Expression>)", "Returns a member further along the specified member's dimension.", FunDef.FlagMethod), new FunDef(Exp.CatMember, "Members", "Members(<String Expression>)", "Returns the member whose name is specified by a string expression."), new FunDef(Exp.CatMember, "NextMember", "<Member>.NextMember", "Returns the next member in the level that contains a specified member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "OpeningPeriod", "OpeningPeriod([<Level>[, <Member>]])", "Returns the first sibling among the descendants of a member at a level."), new FunDef(Exp.CatMember, "ParallelPeriod", "ParallelPeriod([<Level>[, <Numeric Expression>[, <Member>]]])", "Returns a member from a prior period in the same relative position as a specified member."), new FunDef(Exp.CatMember, "Parent", "<Member>.Parent", "Returns the parent of a member.", FunDef.FlagProperty), new FunDef(Exp.CatMember, "PrevMember", "<Member>.PrevMember", "Returns the previous member in the level that contains a specified member.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Member member = getMemberArg(evaluator, args, 0, true); return member.getLeadMember(-1); } }, new FunDef(Exp.CatMember, "ValidMeasure", "ValidMeasure(<Tuple>)", "Returns a valid measure in a virtual cube by forcing inapplicable dimensions to their top level."), // // NUMERIC FUNCTIONS new FunDef(Exp.CatNumeric, "Aggregate", "Aggregate(<Set>[, <Numeric Expression>])", "Returns a calculated value using the appropriate aggregate function, based on the context of the query."), new FunDef(Exp.CatNumeric, "Avg", "Avg(<Set>[, <Numeric Expression>])", "Returns the average value of a numeric expression evaluated over a set."), new FunDef(Exp.CatNumeric, "CoalesceEmpty", "CoalesceEmpty(<Numeric Expression>[, <Numeric Expression>]...)", "Coalesces an empty cell value to a number."), new FunDef(Exp.CatNumeric, "Correlation", "Correlation(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Returns the correlation of two series evaluated over a set."), new FunDef(Exp.CatNumeric, "Count", "Count(<Set>[, EXCLUDEEMPTY | INCLUDEEMPTY])", "Returns the number of tuples in a set, empty cells included unless the optional EXCLUDEEMPTY flag is used."), new FunDef(Exp.CatNumeric, "Covariance", "Covariance(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Returns the covariance of two series evaluated over a set (biased)."), new FunDef(Exp.CatNumeric, "CovarianceN", "CovarianceN(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Returns the covariance of two series evaluated over a set (unbiased)."), new FunDef(Exp.CatNumeric, "IIf", "IIf(<Logical Expression>, <Numeric Expression1>, <Numeric Expression2>)", "Returns one of two numeric values determined by a logical test."), new FunDef(Exp.CatNumeric, "LinRegIntercept", "LinRegIntercept(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Calculates the linear regression of a set and returns the value of b in the regression line y = ax + b."), new FunDef(Exp.CatNumeric, "LinRegPoint", "LinRegPoint(<Numeric Expression>, <Set>, <Numeric Expression>[, <Numeric Expression>])", "Calculates the linear regression of a set and returns the value of y in the regression line y = ax + b."), new FunDef(Exp.CatNumeric, "LinRegR2", "LinRegR2(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Calculates the linear regression of a set and returns R2 (the coefficient of determination)."), new FunDef(Exp.CatNumeric, "LinRegSlope", "LinRegSlope(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Calculates the linear regression of a set and returns the value of a in the regression line y = ax + b."), new FunDef(Exp.CatNumeric, "LinRegVariance", "LinRegVariance(<Set>, <Numeric Expression>[, <Numeric Expression>])", "Calculates the linear regression of a set and returns the variance associated with the regression line y = ax + b."), new FunDef(Exp.CatNumeric, "Max", "Max(<Set>[, <Numeric Expression>])", "Returns the maximum value of a numeric expression evaluated over a set."), new FunDef(Exp.CatNumeric, "Median", "Median(<Set>[, <Numeric Expression>])", "Returns the median value of a numeric expression evaluated over a set."), new FunDef(Exp.CatNumeric, "Min", "Min(<Set>[, <Numeric Expression>])", "Returns the minimum value of a numeric expression evaluated over a set."), new FunDef(Exp.CatNumeric, "Ordinal", "<Level>.Ordinal", "Returns the zero-based ordinal value associated with a level.", FunDef.FlagProperty), new FunDef(Exp.CatNumeric, "Rank", "Rank(<Tuple>, <Set>)", "Returns the one-based rank of a tuple in a set."), new FunDef(Exp.CatNumeric, "Stddev", "Stddev(<Set>[, <Numeric Expression>])", "Alias for Stdev."), new FunDef(Exp.CatNumeric, "StddevP", "StddevP(<Set>[, <Numeric Expression>])", "Alias for StdevP."), new FunDef(Exp.CatNumeric, "Stdev", "Stdev(<Set>[, <Numeric Expression>])", "Returns the standard deviation of a numeric expression evaluated over a set (unbiased)."), new FunDef(Exp.CatNumeric, "StdevP", "StdevP(<Set>[, <Numeric Expression>])", "Returns the standard deviation of a numeric expression evaluated over a set (biased)."), new FunDef(Exp.CatNumeric, "Sum", "Sum(<Set>[, <Numeric Expression>])", "Returns the sum of a numeric expression evaluated over a set.") { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector members = (Vector) getArg(evaluator, args, 0); ExpBase exp = (ExpBase) getArg(evaluator, args, 1); return sum(evaluator.push(new Member[0]), members, exp); } }, new FunDef(Exp.CatNumeric, "Value", "<Measure>.Value", "Returns the value of a measure.", FunDef.FlagProperty), new FunDef(Exp.CatNumeric, "Var", "Var(<Set>[, <Numeric Expression>])", "Returns the variance of a numeric expression evaluated over a set (unbiased)."), new FunDef(Exp.CatNumeric, "Variance", "Variance(<Set>[, <Numeric Expression>])", "Alias for Var."), new FunDef(Exp.CatNumeric, "VarianceP", "VarianceP(<Set>[, <Numeric Expression>])", "Alias for VarP."), new FunDef(Exp.CatNumeric, "VarP", "VarP(<Set>[, <Numeric Expression>])", "Returns the variance of a numeric expression evaluated over a set (biased)."), // // SET FUNCTIONS new FunDef(Exp.CatSet, "AddCalculatedMembers", "AddCalculatedMembers(<Set>)", "Adds calculated members to a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "BottomCount", "BottomCount(<Set>, <Count>[, <Numeric Expression>])", "Returns a specified number of items from the bottom of a set, optionally ordering the set first.", FunDef.FlagNone), new FunDef(Exp.CatSet, "BottomPercent", "BottomPercent(<Set>, <Percentage>, <Numeric Expression>)", "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified percentage.", FunDef.FlagNone), new FunDef(Exp.CatSet, "BottomSum", "BottomSum(<Set>, <Value>, <Numeric Expression>)", "Sorts a set and returns the bottom N elements whose cumulative total is at least a specified value.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Children", "<Member>.Children", "Returns the children of a member.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Member member = getMemberArg(evaluator, args, 0, true); Member[] children = evaluator.getCube().getMemberChildren( new Member[]{member}); return toVector(children); } }, new FunDef(Exp.CatSet, "Crossjoin", "Crossjoin(<Set1>, <Set2>)", "Returns the cross product of two sets.", FunDef.FlagDimDeriv) { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector set0 = (Vector) getArg(evaluator, args, 0), set1 = (Vector) getArg(evaluator, args, 1), result = new Vector(); for (int i = 0, m = set0.size(); i < m; i++) { Object o0 = set0.elementAt(i); for (int j = 0, n = set1.size(); j < n; j++) { Object o1 = set1.elementAt(j); result.addElement(new Object[] {o0, o1}); } } return result; } }, new FunDef(Exp.CatSet, "Descendants", "Descendants(<Member>, <Level>[, <Desc_flag>])", "Returns the set of descendants of a member at a specified level, optionally including or excluding descendants in other levels.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { Member member = getMemberArg(evaluator, args, 0, true); Level level = getLevelArg(args, 1, true); // String descFlag = getStringArg(evaluator, args, 2, ??); if (member.getLevel().getDepth() > level.getDepth()) { return new Member[0]; } // Expand member to its children, until we get to the right // level. We assume that all children are in the same // level. Member[] children = {member}; while (children.length > 0 && children[0].getLevel().getDepth() < level.getDepth()) { children = evaluator.getCube().getMemberChildren( children); } return Util.toVector(children); } }, new FunDef(Exp.CatSet, "Distinct", "Distinct(<Set>)", "Eliminates duplicate tuples from a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownLevel", "DrilldownLevel(<Set>[, <Level>]) or DrilldownLevel(<Set>, , <Index>)", "Drills down the members of a set, at a specified level, to one level below. Alternatively, drills down on a specified dimension in the set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownLevelBottom", "DrilldownLevelBottom(<Set>, <Count>[, [<Level>][, <Numeric Expression>]])", "Drills down the bottom N members of a set, at a specified level, to one level below.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownLevelTop", "DrilldownLevelTop(<Set>, <Count>[, [<Level>][, <Numeric Expression>]])", "Drills down the top N members of a set, at a specified level, to one level below.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownMember", "DrilldownMember(<Set1>, <Set2>[, RECURSIVE])", "Drills down the members in a set that are present in a second specified set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownMemberBottom", "DrilldownMemberBottom(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", "Like DrilldownMember except that it includes only the bottom N children.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrilldownMemberTop", "DrilldownMemberTop(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", "Like DrilldownMember except that it includes only the top N children.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrillupLevel", "DrillupLevel(<Set>[, <Level>])", "Drills up the members of a set that are below a specified level.", FunDef.FlagNone), new FunDef(Exp.CatSet, "DrillupMember", "DrillupMember(<Set1>, <Set2>)", "Drills up the members in a set that are present in a second specified set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Except", "Except(<Set1>, <Set2>[, ALL])", "Finds the difference between two sets, optionally retaining duplicates.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { // todo: implement ALL Hashtable set2 = toHashtable( (Vector) getArg(evaluator, args, 1)); Vector set1 = (Vector) getArg(evaluator, args, 0); Vector result = new Vector(); for (int i = 0, count = set1.size(); i < count; i++) { Object o = set1.elementAt(i); if (set2.get(o) == null) { result.addElement(o); } } return result; } }, new FunDef(Exp.CatSet, "Extract", "Extract(<Set>, <Dimension>[, <Dimension>...])", "Returns a set of tuples from extracted dimension elements. The opposite of Crossjoin.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Filter", "Filter(<Set>, <Search Condition>)", "Returns the set resulting from filtering a set based on a search condition.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Generate", "Generate(<Set1>, <Set2>[, ALL])", "Applies a set to each member of another set and joins the resulting sets by union.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Head", "Head(<Set>[, < Numeric Expression >])", "Returns the first specified number of elements in a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Hierarchize", "Hierarchize(<Set>)", "Orders the members of a set in a hierarchy.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Intersect", "Intersect(<Set1>, <Set2>[, ALL])", "Returns the intersection of two input sets, optionally retaining duplicates.", FunDef.FlagNone), new FunDef(Exp.CatSet, "LastPeriods", "LastPeriods(<Index>[, <Member>])", "Returns a set of members prior to and including a specified member.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Members", "<Dimension>.Members", "Returns the set of all members in a dimension.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Dimension dimension = (Dimension) getArg(evaluator, args, 0); Hierarchy hierarchy = dimension.getHierarchy(); return addMembers(new Vector(), hierarchy); } }, new FunDef(Exp.CatSet, "Members", "<Hierarchy>.Members", "Returns the set of all members in a hierarchy.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Hierarchy hierarchy = (Hierarchy) getArg(evaluator, args, 0); return addMembers(new Vector(), hierarchy); } }, new FunDef(Exp.CatSet, "Members", "<Level>.Members", "Returns the set of all members in a level.", FunDef.FlagProperty) { public Object evaluate(Evaluator evaluator, Exp[] args) { Level level = (Level) getArg(evaluator, args, 0); return toVector(level.getMembers()); } }, new FunDef(Exp.CatSet, "Mtd", "Mtd([<Member>])", "A shortcut function for the PeriodsToDate function that specifies the level to be Month.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { return periodsToDate( evaluator, evaluator.getCube().getMonthLevel(), getMemberArg(evaluator, args, 0, false)); } }, new FunDef(Exp.CatSet, "Order", "Order(<Set>, {<String Expression> | <Numeric Expression>}[, ASC | DESC | BASC | BDESC])", "Arranges members of a set, optionally preserving or breaking the hierarchy.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector members = (Vector) getArg(evaluator, args, 0); ExpBase exp = (ExpBase) getArg(evaluator, args, 1); String order = (String) getArg(evaluator, args, 2, "ASC"); sort( evaluator, members, exp, order.equals("DESC") || order.equals("BDESC"), order.equals("BASC") || order.equals("BDESC")); return members; } }, new FunDef(Exp.CatSet, "PeriodsToDate", "PeriodsToDate([<Level>[, <Member>]])", "Returns a set of periods (members) from a specified level starting with the first period and ending with a specified member.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { Level level = getLevelArg(args, 0, false); Member member = getMemberArg(evaluator, args, 1, false); return periodsToDate(evaluator, level, member); } }, new FunDef(Exp.CatSet, "Qtd", "Qtd([<Member>])", "A shortcut function for the PeriodsToDate function that specifies the level to be Quarter.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { return periodsToDate( evaluator, evaluator.getCube().getQuarterLevel(), getMemberArg(evaluator, args, 0, false)); } }, new FunDef(Exp.CatSet, "StripCalculatedMembers", "StripCalculatedMembers(<Set>)", "Removes calculated members from a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "StrToSet", "StrToSet(<String Expression>)", "Constructs a set from a string expression.", FunDef.FlagDimDeriv), new FunDef(Exp.CatSet, "Subset", "Subset(<Set>, <Start>[, <Count>])", "Returns a subset of elements from a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Tail", "Tail(<Set>[, <Count>])", "Returns a subset from the end of a set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "ToggleDrillState", "ToggleDrillState(<Set1>, <Set2>[, RECURSIVE])", "Toggles the drill state of members. This function is a combination of DrillupMember and DrilldownMember.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector v0 = (Vector) getArg(evaluator, args, 0), v1 = (Vector) getArg(evaluator, args, 1); if (args.length > 2) { throw Util.newInternal( "ToggleDrillState(RECURSIVE) not supported"); } if (v1.isEmpty()) { return v0; } HashSet set1 = toHashSet(v1); Vector result = new Vector(); int i = 0, n = v0.size(); while (i < n) { Member m = (Member) v0.elementAt(i++); result.addElement(m); if (!set1.contains(m)) { continue; } boolean isDrilledDown = false; if (i < n) { Member next = (Member) v0.elementAt(i); boolean strict = true; if (Util.isAncestorOf(m, next, strict)) { isDrilledDown = true; } } if (isDrilledDown) { // skip descendants of this member while (i < n) { Member next = (Member) v0.elementAt(i++); boolean strict = true; if (!Util.isAncestorOf(m, next, strict)) { break; } } } else { Member[] children = evaluator.getCube().getMemberChildren( new Member[] {m}); for (int j = 0; j < children.length; j++) { result.addElement(children[j]); } } } return result; } }, new FunDef(Exp.CatSet, "TopCount", "TopCount(<Set>, <Count>[, <Numeric Expression>])", "Returns a specified number of items from the top of a set, optionally ordering the set first.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector set = (Vector) getArg(evaluator, args, 0); int n = getIntArg(evaluator, args, 1); ExpBase exp = (ExpBase) getArg(evaluator, args, 2, null); if (exp != null) { boolean desc = true, brk = true; sort(evaluator, set, exp, desc, brk); } if (n < set.size()) { set.setSize(n); } return set; } }, new FunDef(Exp.CatSet, "TopPercent", "TopPercent(<Set>, <Percentage>, <Numeric Expression>)", "Sorts a set and returns the top N elements whose cumulative total is at least a specified percentage.", FunDef.FlagNone), new FunDef(Exp.CatSet, "TopSum", "TopSum(<Set>, <Value>, <Numeric Expression>)", "Sorts a set and returns the top N elements whose cumulative total is at least a specified value.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Union", "Union(<Set1>, <Set2>[, ALL])", "Returns the union of two sets, optionally retaining duplicates.", FunDef.FlagNone), new FunDef(Exp.CatSet, "VisualTotals", "VisualTotals(<Set>, <Pattern>)", "Dynamically totals child members specified in a set using a pattern for the total label in the result set.", FunDef.FlagNone), new FunDef(Exp.CatSet, "Wtd", "Wtd([<Member>])", "A shortcut function for the PeriodsToDate function that specifies the level to be Week.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { return periodsToDate( evaluator, evaluator.getCube().getWeekLevel(), getMemberArg(evaluator, args, 0, false)); } }, new FunDef(Exp.CatSet, "Ytd", "Ytd([<Member>])", "A shortcut function for the PeriodsToDate function that specifies the level to be Year.", FunDef.FlagNone) { public Object evaluate(Evaluator evaluator, Exp[] args) { return periodsToDate( evaluator, evaluator.getCube().getYearLevel(), getMemberArg(evaluator, args, 0, false)); } }, new FunDef(Exp.CatSet, "_Range", "<Member>:<Member>", "Infix colon operator returns the set of members between a given pair of members.", FunDef.FlagInfix), new FunDef(Exp.CatSet, "_Set", "{<Member> [, <Member>]...}", "Brace operator constructs a set.", FunDef.FlagDimDeriv) { public Object evaluate(Evaluator evaluator, Exp[] args) { Vector vector = null; for (int i = 0; i < args.length; i++) { ExpBase arg = (ExpBase) args[i]; Object o; if (arg instanceof Member) { o = arg; } else { Member[] members = arg.isConstantTuple(); if (members != null) { o = members; } else { o = arg.evaluate(evaluator); } } if (o instanceof Vector) { Vector vector2 = (Vector) o; if (vector == null) { vector = vector2; } else { for (int j = 0, count = vector2.size(); j < count; j++) { vector.addElement(vector2.elementAt(j)); } } } else { if (vector == null) { vector = new Vector(); } vector.addElement(o); } } return vector; } }, // // STRING FUNCTIONS new FunDef(Exp.CatString, "CoalesceEmpty", "CoalesceEmpty(<String Expression>[, <String Expression>]...)", "Coalesces an empty cell value to a string."), new FunDef(Exp.CatString, "IIf", "IIf(<Logical Expression>, <String Expression1>, <String Expression2>)", "Returns one of two string values determined by a logical test."), new FunDef(Exp.CatString, "Name", "<Dimension>.Name", "Returns the name of a dimension.", FunDef.FlagProperty), new FunDef(Exp.CatString, "Name", "<Hierarchy>.Name", "Returns the name of a hierarchy.", FunDef.FlagProperty), new FunDef(Exp.CatString, "Name", "<Level>.Name", "Returns the name of a level.", FunDef.FlagProperty), new FunDef(Exp.CatString, "Name", "<Member>.Name", "Returns the name of a member.", FunDef.FlagProperty), new FunDef(Exp.CatString, "SetToStr", "SetToStr(<Set>)", "Constructs a string from a set."), new FunDef(Exp.CatString, "TupleToStr", "TupleToStr(<Tuple>)", "Constructs a string from a tuple."), new FunDef(Exp.CatString, "UniqueName", "<Dimension>.UniqueName", "Returns the unique name of a dimension.", FunDef.FlagProperty), new FunDef(Exp.CatString, "UniqueName", "<Level>.UniqueName", "Returns the unique name of a level.", FunDef.FlagProperty), new FunDef(Exp.CatString, "UniqueName", "<Member>.UniqueName", "Returns the unique name of a member.", FunDef.FlagProperty), // // TUPLE FUNCTIONS new FunDef(Exp.CatTuple, "Current", "<Set>.Current", "Returns the current tuple from a set during an iteration.", FunDef.FlagProperty), new FunDef(Exp.CatTuple, "Item", "<Set>.Item(<String Expression>[, <String Expression>...] | <Index>)", "Returns a tuple from a set.", FunDef.FlagMethod), new FunDef(Exp.CatTuple, "StrToTuple", "StrToTuple(<String Expression>)", "Constructs a tuple from a string.", FunDef.FlagDimDeriv), new FunDef(Exp.CatTuple, "_Tuple", "(<Member> [, <Member>]...)", "Parenthesis operator constructs a tuple. If there is only one member, the expression is equivalent to the member expression.", FunDef.FlagDimDeriv) { public Object evaluate(Evaluator evaluator, Exp[] args) { Member[] members = new Member[args.length]; for (int i = 0; i < args.length; i++) { members[i] = getMemberArg(evaluator, args, i, true); } return members; } }, // // PARAMETER FUNCTIONS new FunDef(Exp.CatParameter, "Parameter", "Parameter(<Name>, <Type>, <DefaultValue>, <Description>)", "Returns default value of parameter."), new FunDef(Exp.CatParameter, "ParamRef", "ParamRef(<CurrentValue>)", "Returns current value of parameter. If it's null, returns default."), // // OPERATORS new FunDef(Exp.CatNumeric, "+", "<Numeric Expression> + <Numeric Expression>", "Adds two numbers.", FunDef.FlagInfix), new FunDef(Exp.CatNumeric, "-", "<Numeric Expression> - <Numeric Expression>", "Subtracts two numbers.", FunDef.FlagInfix) { public Object evaluate(Evaluator evaluator, Exp[] args) { Double o0 = getDoubleArg(evaluator, args, 0), o1 = getDoubleArg(evaluator, args, 1); return new Double(o0.doubleValue() - o1.doubleValue()); } }, new FunDef(Exp.CatNumeric, "*", "<Numeric Expression> * <Numeric Expression>", "Multiplies two numbers.", FunDef.FlagInfix), new FunDef(Exp.CatNumeric, "/", "<Numeric Expression> / <Numeric Expression>", "Divides two numbers.", FunDef.FlagInfix) { public Object evaluate(Evaluator evaluator, Exp[] args) { Double o0 = getDoubleArg(evaluator, args, 0), o1 = getDoubleArg(evaluator, args, 1); Double result = new Double(o0.doubleValue() / o1.doubleValue()); return result; } }, new FunDef(Exp.CatNumeric, "_Uminus", "- <Numeric Expression>", "Returns the negative of a number.", FunDef.FlagPrefix), new FunDef(Exp.CatString, "||", "<String Expression> || <String Expression>", "Concatenates two strings.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "AND", "<Logical Expression> AND <Logical Expression>", "Returns the conjunction of two conditions.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "OR", "<Logical Expression> OR <Logical Expression>", "Returns the disjunction of two conditions.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "XOR", "<Logical Expression> XOR <Logical Expression>", "Returns whether two conditions are mutually exclusive.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "NOT", "NOT <Logical Expression>", "Returns the negation of a condition.", FunDef.FlagPrefix), new FunDef(Exp.CatLogical, "=", "<Numeric Expression> = <Numeric Expression>", "Returns whether two expressions are equal.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "<>", "<Numeric Expression> = <Numeric Expression>", "Returns whether two expressions are not equal.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "<", "<Numeric Expression> = <Numeric Expression>", "Returns whether an expression is less than another.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, "<=", "<Numeric Expression> = <Numeric Expression>", "Returns whether an expression is less than or equal to another.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, ">", "<Numeric Expression> = <Numeric Expression>", "Returns whether an expression is greater than another.", FunDef.FlagInfix), new FunDef(Exp.CatLogical, ">=", "<Numeric Expression> = <Numeric Expression>", "Returns whether an expression is greater than or equal to another.", FunDef.FlagInfix), new FunDef(Exp.CatTuple, "_Parentheses", "(<Expression>)", "Parenthesis enclose an expression and indicate precedence.", FunDef.FlagDimDeriv) { public Object evaluate(Evaluator evaluator, Exp[] args) { return args[0].evaluate(evaluator); } }, }; }; // End FunDef.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 1603 | Julian Hyde |
mondrian: Add Andreas' taglib; Rename 'mondrian.rolap.Util.assert' to 'assertTrue', because 'assert' is a keyword in jdk 1.4; Fix 'NON EMPTY'; JUnit framework for tests; Add Oracle dataset. |
||
#3 | 1576 | Julian Hyde |
mondrian: fix dataset (add column customer.ordinal); create dataset for oracle; get queries working on oracle; get format strings working; refactor out new packages mondrian.rolap.agg and mondrian.rolap.sql. |
||
#2 | 1499 | Julian Hyde |
Mondrian: Re-organize functions and type-checking Add mondrian.olap.fun package |
||
#1 | 1453 | Julian Hyde | mondrian: first source check-in |