Skip to content

Commit

Permalink
MONDRIAN: add IN and MATCHES UDFs
Browse files Browse the repository at this point in the history
[git-p4: depot-paths = "//open/mondrian/": change = 7596]
  • Loading branch information
skchoi56 committed Sep 8, 2006
1 parent ddde37b commit 944cb9d
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 6 deletions.
33 changes: 33 additions & 0 deletions doc/mdx.html
Expand Up @@ -128,6 +128,15 @@ <h3>Current Date Functions</h3>
returns <code>[Time].[2000].[3].[1]</code>.</li>
</ol>

<h3><code>IN</code> and <code>NOT IN</code></h3>

<p><code>IN</code> and <code>NOT IN</code> are Mondrian-specific functions.</p>

<h3><code>MATCHES</code> and <code>NOT MATCHES</code></h3>

<p><code>MATCHES</code> and <code>NOT MATCHES</code> are Mondrian-specific functions which take as one of its arguments a <A href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html">java regular expression</A>.</p>


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

<p>MDX statements can contain comments. There are 3 syntactic forms for
Expand Down Expand Up @@ -733,6 +742,12 @@ <h2><a name="Function_list">Function list</a></h2>
<code>&lt;String&gt; IIf(&lt;Logical Expression&gt;, &lt;String&gt;, &lt;String&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>IN</td>
<td>Returns whether a member is contained in a set. <p><b>Syntax</b></p>
<code>&lt;Member&gt; IN &lt;Set&gt;</code><br/>
</td>
</tr>
<tr>
<td valign=top>IS</td>
<td>Returns whether two objects are the same (idempotent) <p><b>Syntax</b></p>
Expand Down Expand Up @@ -864,6 +879,12 @@ <h2><a name="Function_list">Function list</a></h2>
<code>&lt;Numeric Expression&gt; LinRegVariance(&lt;Set&gt;, &lt;Numeric Expression&gt;, &lt;Numeric Expression&gt;)</code><br/>
</td>
</tr>
<tr>
<td valign=top>MATCHES</td>
<td>Returns whether an expression matches a regular expression. <p><b>Syntax</b></p>
<code>&lt;String&gt; MATCHES &lt;String&gt;</code><br/>
</td>
</tr>
<tr>
<td valign=top>Max</td>
<td>Returns the maximum value of a numeric expression evaluated over a set. <p><b>Syntax</b></p>
Expand Down Expand Up @@ -922,6 +943,18 @@ <h2><a name="Function_list">Function list</a></h2>
<code>NOT &lt;Logical Expression&gt;</code><br/>
</td>
</tr>
<tr>
<td valign=top>NOT IN</td>
<td>Returns whether a member is not contained in a set. <p><b>Syntax</b></p>
<code>&lt;Member&gt; NOT IN &lt;Set&gt;</code><br/>
</td>
</tr>
<tr>
<td valign=top>NOT MATCHES</td>
<td>Returns whether an expression does not match a regular expression. <p><b>Syntax</b></p>
<code>&lt;String&gt; NOT MATCHES &lt;String&gt;</code><br/>
</td>
</tr>
<tr>
<td valign=top>Name</td>
<td>Returns the name of a dimension. <p><b>Syntax</b></p>
Expand Down
2 changes: 2 additions & 0 deletions src/main/META-INF/services/mondrian.spi.UserDefinedFunction
Expand Up @@ -4,3 +4,5 @@ mondrian.udf.LastNonEmptyUdf
mondrian.udf.CurrentDateStringUdf
mondrian.udf.CurrentDateMemberUdf
mondrian.udf.CurrentDateMemberExactUdf
mondrian.udf.MatchesUdf
mondrian.udf.InUdf
18 changes: 18 additions & 0 deletions src/main/mondrian/olap/Parser.cup
Expand Up @@ -284,7 +284,9 @@ terminal
EMPTY,
END,
FROM,
IN,
IS,
MATCHES,
MEMBER,
NON,
NOT,
Expand Down Expand Up @@ -694,6 +696,22 @@ term3 ::=
| term3:x comp_op:op term2:y {: // e.g. 1 < 5
RESULT = new UnresolvedFunCall(op, Syntax.Infix, new Exp[] {x, y});
:}
| term3:x MATCHES term2:y {:
RESULT = new UnresolvedFunCall("MATCHES", Syntax.Infix, new Exp[] {x, y});
:}
| term3:x NOT MATCHES term2:y {:
RESULT = new UnresolvedFunCall(
"NOT", Syntax.Prefix, new Exp[]
{new UnresolvedFunCall("MATCHES", Syntax.Infix, new Exp[] {x, y})});
:}
| term3:x IN term2:y {:
RESULT = new UnresolvedFunCall("IN", Syntax.Infix, new Exp[] {x, y});
:}
| term3:x NOT IN term2:y {:
RESULT = new UnresolvedFunCall(
"NOT", Syntax.Prefix, new Exp[]
{new UnresolvedFunCall("IN", Syntax.Infix, new Exp[] {x, y})});
:}
;

term2 ::=
Expand Down
2 changes: 2 additions & 0 deletions src/main/mondrian/olap/Scanner.java
Expand Up @@ -249,10 +249,12 @@ private void initReswords() {
// initResword(ParserSym.FORMAT_STRING ,"FORMAT_STRING");
initResword(ParserSym.FROM ,"FROM");
initResword(ParserSym.IS ,"IS");
initResword(ParserSym.IN ,"IN");
// initResword(ParserSym.LAG ,"LAG");
// initResword(ParserSym.LASTCHILD ,"LASTCHILD");
// initResword(ParserSym.LASTSIBLING ,"LASTSIBLING");
// initResword(ParserSym.LEAD ,"LEAD");
initResword(ParserSym.MATCHES ,"MATCHES");
initResword(ParserSym.MEMBER ,"MEMBER");
// initResword(ParserSym.MEMBERS ,"MEMBERS");
// initResword(ParserSym.NEXTMEMBER ,"NEXTMEMBER");
Expand Down
72 changes: 72 additions & 0 deletions src/main/mondrian/udf/InUdf.java
@@ -0,0 +1,72 @@
/*
// $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) 2006-2006 Julian Hyde and others
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.udf;

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

import java.util.*;
import java.util.regex.*;

/**
* User-defined function <code>IN</code>.
*
* @author schoi
* @version $Id$
*/
public class InUdf implements UserDefinedFunction {

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

Object arg0 = arguments[0].evaluate(evaluator);
List arg1 = (List) arguments[1].evaluate(evaluator);

for (int i = 0; i < arg1.size(); i++) {
if (((Member)arg0).getUniqueName().equals(
((Member)arg1.get(i)).getUniqueName())) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}

public String getDescription() {
return "Returns true if the member argument is contained in the set argument.";
}

public String getName() {
return "IN";
}

public Type[] getParameterTypes() {
return new Type[] {
MemberType.Unknown,
new SetType(MemberType.Unknown)
};
}

public String[] getReservedWords() {
// This function does not require any reserved words.
return null;
}

public Type getReturnType(Type[] parameterTypes) {
return new BooleanType();
}

public Syntax getSyntax() {
return Syntax.Infix;
}

}

// End InUdf.java
66 changes: 66 additions & 0 deletions src/main/mondrian/udf/MatchesUdf.java
@@ -0,0 +1,66 @@
/*
// $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) 2006-2006 Julian Hyde and others
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.udf;

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

import java.util.*;
import java.util.regex.*;

/**
* User-defined function <code>MATCHES</code>.
*
* @author schoi
* @version $Id$
*/
public class MatchesUdf implements UserDefinedFunction {

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

Object arg0 = arguments[0].evaluateScalar(evaluator);
Object arg1 = arguments[1].evaluateScalar(evaluator);

return Boolean.valueOf(Pattern.matches((String)arg1, (String)arg0));
}

public String getDescription() {
return "Returns true if the string matches the regular expression.";
}

public String getName() {
return "MATCHES";
}

public Type[] getParameterTypes() {
return new Type[] {
new StringType(),
new StringType()
};
}

public String[] getReservedWords() {
// This function does not require any reserved words.
return null;
}

public Type getReturnType(Type[] parameterTypes) {
return new BooleanType();
}

public Syntax getSyntax() {
return Syntax.Infix;
}

}

// End MatchesUdf.java
10 changes: 5 additions & 5 deletions testsrc/main/mondrian/test/TestCalculatedMembers.java
Expand Up @@ -457,7 +457,7 @@ public void testBracketInCubeCalcMemberName() {
" <Measure name=\"Unit Sales\" column=\"unit_sales\" aggregator=\"sum\"\n" +
" formatString=\"Standard\" visible=\"false\"/>\n" +
" <CalculatedMember\n" +
" name=\"With a [bracket] in it\"\n" +
" name=\"With a [bracket] inside it\"\n" +
" dimension=\"Measures\"\n" +
" visible=\"false\"\n" +
" formula=\"[Measures].[Unit Sales] * 10\">\n" +
Expand All @@ -467,21 +467,21 @@ public void testBracketInCubeCalcMemberName() {

getTestContext(cubeName).assertThrows(
fold(
"select {[Measures].[With a [bracket] in it]} on columns,\n" +
"select {[Measures].[With a [bracket] inside it]} on columns,\n" +
" {[Gender].Members} on rows\n" +
"from [" + cubeName + "]"),
"Syntax error at line 1, column 38, token 'in'");
"Syntax error at line 1, column 38, token 'inside'");

getTestContext(cubeName).assertQueryReturns(
fold(
"select {[Measures].[With a [bracket]] in it]} on columns,\n" +
"select {[Measures].[With a [bracket]] inside it]} on columns,\n" +
" {[Gender].Members} on rows\n" +
"from [" + cubeName + "]"),
fold(
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[With a [bracket]] in it]}\n" +
"{[Measures].[With a [bracket]] inside it]}\n" +
"Axis #2:\n" +
"{[Gender].[F]}\n" +
"{[Gender].[M]}\n" +
Expand Down

0 comments on commit 944cb9d

Please sign in to comment.