Skip to content

Commit

Permalink
MONDRIAN: Add sufficient doc to CurrentDateMember and CurrentDateStri…
Browse files Browse the repository at this point in the history
…ng UDFs so that they can be generated with the other functions in mdx.html.

[git-p4: depot-paths = "//open/mondrian/": change = 7256]
  • Loading branch information
julianhyde committed Jul 26, 2006
1 parent 2595f26 commit b9b76cf
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 78 deletions.
51 changes: 36 additions & 15 deletions doc/mdx.html
Expand Up @@ -4,7 +4,7 @@
== 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) 2005-2005 Julian Hyde
== Copyright (C) 2005-2006 Julian Hyde
== All Rights Reserved.
== You must accept the terms of that agreement to use this software.
-->
Expand Down Expand Up @@ -91,26 +91,43 @@ <h3>Current Date Functions</h3>
to escape any characters that
correspond to Visual Basic formatting characters.</p>

<p>E.g., to find a member in the [Time] dimension corresponding to the current
<p>For example, to find a member in the <code>[Time]</code> dimension corresponding to the current
month, you would specify:

<blockquote>
<pre><code>CurrentDateMember([Time], "[Ti\me]\.[yyyy]\.[Qq]\.[m]")</code></pre>
</blockquote>

<p>escaping the "m" in "Time" and the "."s that separate each member,
since "m" and "." are formatting characters.</p>
since "m" and "." are formatting characters. If you prefer, you can also enclose
constant parts of the format string in double-quotes (&quot;):</p>

<p>CurrentDateMember() optionally takes a symbol parameter whose value is
either EXACT, BEFORE, or AFTER.
The default value, if that parameter is not specified, is EXACT.
In the case of EXACT, there needs to be an
<blockquote>
<pre>CurrentDateMember([Time], '"[Time].[&quot;yyyy&quot;].[Q&quot;q&quot;].[&quot;m&quot;]"')</pre>
</blockquote>

<p><code>CurrentDateMember()</code> optionally takes a symbol parameter whose value is
either <code>EXACT</code>, <code>BEFORE</code>, or <code>AFTER</code>.
The default value, if that parameter is not specified, is <code>EXACT</code>.
In the case of <code>EXACT</code>, there needs to be an
existing member corresponding to the current date. Otherwise, NULL is returned.
If BEFORE is specified, and there is no matching member, then the closest
available member in the past is returned.
If AFTER is specified, and there is no matching member, then the closest
available member in the future is returned.</p>

<p>For example, suppose that today is 29th February, 2000, and we have forgot
that 2000 was a leap year, so our time dimension does not contain a member <code>
[Time].[2000].[2].[29]</code>. Consider the 3 expressions:</p>
<ol>
<li><code>CurrentDateMember([Time], '"[Time].[&quot;yyyy&quot;].[&quot;m&quot;].[&quot;d&quot;]"', EXACT)</code>
returns the null member;</li>
<li><code>CurrentDateMember([Time], '"[Time].[&quot;yyyy&quot;].[&quot;m&quot;].[&quot;d&quot;]"', BEFORE)</code>
returns <code>[Time].[2000].[2].[28]</code>;</li>
<li><code>CurrentDateMember([Time], '"[Time].[&quot;yyyy&quot;].[&quot;m&quot;].[&quot;d&quot;]"', AFTER)</code>
returns <code>[Time].[2000].[3].[1]</code>.</li>
</ol>

<h2><a name="Comments">Comments</a></h2>

<p>MDX statements can contain comments. There are 3 syntactic forms for
Expand Down Expand Up @@ -421,6 +438,12 @@ <h2><a name="Function_list">Function list</a></h2>
<code>&lt;Set&gt; BottomSum(&lt;Set&gt;, &lt;Numeric Expression&gt;, &lt;Numeric Expression&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>CalculatedChild</td>
<td>Returns an existing calculated child member with name &lt;String&gt; from the specified &lt;Member&gt;. <p><b>Syntax</b></p>
<code>&lt;Member&gt; &lt;Member&gt;.CalculatedChild(&lt;String&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>Caption</td>
<td>Returns the caption of a dimension. <p><b>Syntax</b></p>
Expand Down Expand Up @@ -514,22 +537,20 @@ <h2><a name="Function_list">Function list</a></h2>
</tr>
<tr>
<td valign=top>CurrentDateMember</td>
<td>Returns the closest or exact member within the specified dimension, corresponding to the current date, in the format specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;Member&gt; CurrentDateMember(&lt;Dimension&gt;, &lt;FormatString&gt;)</code><br/>
<code>&lt;Member&gt; CurrentDateMember(&lt;Dimension&gt;, &lt;FormatString&gt; ,&lt;FindSymbol&gt;)</code><br/>
<td>Returns the member within the specified dimension corresponding to the current date, in the format specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;Member&gt; CurrentDateMember(&lt;Hierarchy&gt;, &lt;String&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>CurrentDateMember</td>
<td>Returns the closest or exact member within the specified hierarchy, corresponding to the current date, in the format specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;Member&gt; CurrentDateMember(&lt;Hierarchy&gt;, &lt;FormatString&gt;)</code><br/>
<code>&lt;Member&gt; CurrentDateMember(&lt;Hierarchy&gt;, &lt;FormatString&gt; ,&lt;FindSymbol&gt;)</code><br/>
<td>Returns the closest or exact member within the specified dimension corresponding to the current date, in the format specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;Member&gt; CurrentDateMember(&lt;Hierarchy&gt;, &lt;String&gt;, &lt;Symbol&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>CurrentDateString</td>
<td>Returns a string representing the current date in the format specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;String&gt; CurrentDateString(&lt;FormatString&gt;)</code><br/>
<td>Returns the current date formatted as specified by the format parameter. <p><b>Syntax</b></p>
<code>&lt;String&gt; CurrentDateString(&lt;String&gt;)</code><br/>
</td>
</tr>
<tr>
Expand Down
46 changes: 13 additions & 33 deletions src/main/mondrian/olap/fun/UdfResolver.java
Expand Up @@ -11,8 +11,6 @@

import mondrian.olap.*;
import mondrian.olap.type.*;
import mondrian.olap.type.DimensionType;
import mondrian.olap.type.LevelType;
import mondrian.spi.UserDefinedFunction;
import mondrian.calc.*;
import mondrian.calc.impl.GenericCalc;
Expand Down Expand Up @@ -41,7 +39,17 @@ public String getDescription() {
}

public String getSignature() {
return null;
Type[] parameterTypes = udf.getParameterTypes();
int[] parameterCategories = new int[parameterTypes.length];
for (int i = 0; i < parameterCategories.length; i++) {
parameterCategories[i] = TypeUtil.typeToCategory(parameterTypes[i]);
}
Type returnType = udf.getReturnType(parameterTypes);
int returnCategory = TypeUtil.typeToCategory(returnType);
return getSyntax().getSignature(
getName(),
returnCategory,
parameterCategories);
}

public Syntax getSyntax() {
Expand All @@ -63,46 +71,18 @@ public FunDef resolve(
if (parameterType.equals(argType)) {
continue;
}
final int parameterCategory = typeToCategory(parameterType);
final int parameterCategory = TypeUtil.typeToCategory(parameterType);
if (!validator.canConvert(
arg, parameterCategory, conversionCount)) {
return null;
}
parameterCategories[i] = parameterCategory;
}
final Type returnType = udf.getReturnType(argTypes);
final int returnCategory = typeToCategory(returnType);
final int returnCategory = TypeUtil.typeToCategory(returnType);
return new UdfFunDef(returnCategory, parameterCategories);
}

private static int typeToCategory(Type type) {
if (type instanceof NumericType) {
return Category.Numeric;
} else if (type instanceof BooleanType) {
return Category.Logical;
} else if (type instanceof DimensionType) {
return Category.Dimension;
} else if (type instanceof HierarchyType) {
return Category.Hierarchy;
} else if (type instanceof MemberType) {
return Category.Member;
} else if (type instanceof LevelType) {
return Category.Level;
} else if (type instanceof SymbolType) {
return Category.Symbol;
} else if (type instanceof ScalarType) {
return Category.Value;
} else if (type instanceof SetType) {
return Category.Set;
} else if (type instanceof StringType) {
return Category.String;
} else if (type instanceof TupleType) {
return Category.Tuple;
} else {
throw Util.newInternal("Unknown type " + type);
}
}

public boolean requiresExpression(int k) {
return false;
}
Expand Down
18 changes: 10 additions & 8 deletions src/main/mondrian/udf/CurrentDateMemberExactUdf.java
Expand Up @@ -9,30 +9,32 @@
*/
package mondrian.udf;

import mondrian.olap.*;
import mondrian.olap.type.*;
import mondrian.util.*;

/**
* User-defined function CurrentDateMember. Arguments to the function are
* as follows:
* User-defined function <code>CurrentDateMember</code>. Arguments to the
* function are as follows:
*
* <blockquote>
* <code>
* CurrentDataMember(<Hierarchy>, <FormatString>) returns <Member>
* CurrentDataMember(&lt;Hierarchy&gt;, &lt;FormatString&gt;) returns &lt;Member&gt;
* </code>
* </blockquote>
*
* The function returns the member from the specified hierarchy that matches
* the current date, to the granularity specified by the <FormatString>.
* the current date, to the granularity specified by the &lt;FormatString&gt;.
*
* The format string conforms to the format string implemented by
* {@link Format}.
*
*
* @author Zelaine Fong
* @version $Id$
*/
public class CurrentDateMemberExactUdf extends CurrentDateMemberUdf {

public String getDescription() {
return "Returns the member corresponding to the current date";
return "Returns the member within the specified dimension corresponding to the current date, in the format specified by the format parameter.";
}

public Type[] getParameterTypes() {
Expand Down
26 changes: 15 additions & 11 deletions src/main/mondrian/udf/CurrentDateMemberUdf.java
Expand Up @@ -17,36 +17,40 @@
import java.util.*;

/**
* User-defined function CurrentDateMember. Arguments to the function are
* as follows:
* User-defined function <code>CurrentDateMember</code>. Arguments to the
* function are as follows:
*
* <blockquote>
* <code>
* CurrentDataMember(<Hierarchy>, <FormatString>[, <Find>) returns <Member>
* CurrentDataMember(&lt;Hierarchy&gt;, &lt;FormatString&gt;[, &lt;Find&gt;)
* returns &lt;Member&gt;
* </code>
* </blockquote>
*
* The function returns the member from the specified hierarchy that matches
* the current date, to the granularity specified by the <FormatString>.
* the current date, to the granularity specified by the &lt;FormatString&gt;.
*
* The format string conforms to the format string implemented by
* {@link Format}.
*
*
* @author Zelaine Fong
* @version $Id$
*/
public class CurrentDateMemberUdf implements UserDefinedFunction {

public Object execute(Evaluator evaluator, Argument[] arguments) {

// determine the current date
Object formatArg = arguments[1].evaluateScalar(evaluator);

if (!(formatArg instanceof String)) {
return null;
}
final Locale locale = Locale.getDefault();
final Format format = new Format((String) formatArg, locale);
Date currDate = new Date();
String currDateStr = format.format(currDate);

// determine the match type
int matchType;
if (arguments.length == 3) {
Expand All @@ -56,14 +60,14 @@ public Object execute(Evaluator evaluator, Argument[] arguments) {
} else {
matchType = MatchType.EXACT;
}

String[] uniqueNames = Util.explode(currDateStr);
return evaluator.getSchemaReader().getMemberByUniqueName(
uniqueNames, false, matchType);
}

public String getDescription() {
return "Returns the closest member corresponding to the current date";
return "Returns the closest or exact member within the specified dimension corresponding to the current date, in the format specified by the format parameter.";
}

public String getName() {
Expand Down
13 changes: 7 additions & 6 deletions src/main/mondrian/udf/CurrentDateStringUdf.java
Expand Up @@ -19,18 +19,19 @@
import java.util.*;

/**
* User-defined function CurrentDateString, which returns the current date
* value as a formatted string, based on a format string passed in as a
* parameter. The format string conforms to the format string implemented
* User-defined function <code>CurrentDateString<code>, which returns the
* current date value as a formatted string, based on a format string passed in
* as a parameter. The format string conforms to the format string implemented
* by {@link Format}.
*
*
* @author Zelaine Fong
* @version $Id$
*/
public class CurrentDateStringUdf implements UserDefinedFunction {

public Object execute(Evaluator evaluator, Argument[] arguments) {
Object arg = arguments[0].evaluateScalar(evaluator);

if (!(arg instanceof String)) {
return null;
}
Expand All @@ -41,7 +42,7 @@ public Object execute(Evaluator evaluator, Argument[] arguments) {
}

public String getDescription() {
return "Returns current date as a formatted string";
return "Returns the current date formatted as specified by the format parameter.";
}

public String getName() {
Expand Down
23 changes: 18 additions & 5 deletions testsrc/main/mondrian/olap/fun/FunctionTest.java
Expand Up @@ -15,11 +15,16 @@
import mondrian.test.*;
import mondrian.resource.MondrianResource;
import mondrian.calc.*;
import mondrian.udf.CurrentDateMemberExactUdf;
import mondrian.udf.CurrentDateMemberUdf;
import mondrian.udf.CurrentDateStringUdf;

import org.eigenbase.xom.StringEscaper;

import java.io.*;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;

/**
* <code>FunctionTest</code> tests the functions defined in
Expand Down Expand Up @@ -6439,8 +6444,8 @@ public void testVisualTotalsCrossjoin() {
}

public void testCalculatedChild() {
// Construct calculated children with the same name for both [Drink] and [Non-Consumable]
// Then, create a metric to select the calculated child based on current product member
// Construct calculated children with the same name for both [Drink] and [Non-Consumable]
// Then, create a metric to select the calculated child based on current product member
assertQueryReturns(fold(new String[] {
"with",
" member [Product].[All Products].[Drink].[Calculated Child] as '[Product].[All Products].[Drink].[Alcoholic Beverages]'",
Expand All @@ -6463,8 +6468,8 @@ public void testCalculatedChild() {
}

public void testCalculatedChildUsingItem() {
// Construct calculated children with the same name for both [Drink] and [Non-Consumable]
// Then, create a metric to select the first calculated child
// Construct calculated children with the same name for both [Drink] and [Non-Consumable]
// Then, create a metric to select the first calculated child
assertQueryReturns(fold(new String[] {
"with",
" member [Product].[All Products].[Drink].[Calculated Child] as '[Product].[All Products].[Drink].[Alcoholic Beverages]'",
Expand Down Expand Up @@ -6504,7 +6509,15 @@ public void testCalculatedChildOnNullMember() {
* specification</a>.
*/
public void testDumpFunctions() throws IOException {
final List funInfoList = BuiltinFunTable.instance().getFunInfoList();
final List funInfoList = new ArrayList();
funInfoList.addAll(BuiltinFunTable.instance().getFunInfoList());

// Add some UDFs.
funInfoList.add(new FunInfo(new UdfResolver(new CurrentDateMemberExactUdf())));
funInfoList.add(new FunInfo(new UdfResolver(new CurrentDateMemberUdf())));
funInfoList.add(new FunInfo(new UdfResolver(new CurrentDateStringUdf())));
Collections.sort(funInfoList);

final File file = new File("functions.html");
final FileOutputStream os = new FileOutputStream(file);
final PrintWriter pw = new PrintWriter(os);
Expand Down

0 comments on commit b9b76cf

Please sign in to comment.