Skip to content

Commit

Permalink
Change IdentifierNode.parseIdentifier(String) to return an Identifier…
Browse files Browse the repository at this point in the history
…Node; it

previously returned List<IdentifierNode.Segment>.

Add example of adding a WITH MEMBER node to a parse tree model.

Cut out spurious parentheses if child of parentheses node is going to
defensively parenthesize itself.


git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@359 c6a108a4-781c-0410-a6c6-c2d559e19af0
  • Loading branch information
julianhyde committed Oct 14, 2010
1 parent f8e0a0a commit 4b0a021
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 44 deletions.
31 changes: 17 additions & 14 deletions src/org/olap4j/mdx/IdentifierNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,37 +176,39 @@ public IdentifierNode deepCopy() {
}

/**
* Parses an MDX identifier into a list of segments.
* Parses an MDX identifier string into an
* {@link org.olap4j.mdx.IdentifierNode}.
*
* <p>Each segment is a name combined with a description of how the name
* <p>It contains a list of {@link IdentifierNode.Segment segments}, each
* of which is a name combined with a description of how the name
* was {@link Quoting quoted}. For example,
*
* <blockquote><code>
* parseIdentifier(
* "[Customers].USA.[South Dakota].[Sioux Falls].&amp;[1245]")
* </code></blockquote>
*
* returns
* returns an IdentifierNode consisting of the following segments:
*
* <blockquote><code>
* { Segment("Customers", QUOTED),
* Segment("USA", UNQUOTED),
* Segment("South Dakota", QUOTED),
* Segment("Sioux Falls", QUOTED),
* Segment("1245", KEY) }
* </code></blockquote>
* <code><ul>
* <li>Segment("Customers", QUOTED),
* <li>Segment("USA", UNQUOTED),
* <li>Segment("South Dakota", QUOTED),
* <li>Segment("Sioux Falls", QUOTED),
* <li>Segment("1245", KEY)
* </ul></code>
*
* @see org.olap4j.metadata.Cube#lookupMember(String...)
*
* @param identifier MDX identifier string
*
* @return List of name segments
* @return Identifier parse tree node
*
* @throws IllegalArgumentException if the format of the identifier is
* invalid
*/
public static List<Segment> parseIdentifier(String identifier) {
return IdentifierParser.parseIdentifier(identifier);
public static IdentifierNode parseIdentifier(String identifier) {
return new IdentifierNode(IdentifierParser.parseIdentifier(identifier));
}

/**
Expand Down Expand Up @@ -279,7 +281,8 @@ static String unparseIdentifierList(List<? extends Segment> segments) {
* {@link org.olap4j.mdx.IdentifierNode.KeySegment KeySegment}.
*
* <p>To parse an identifier into a list of segments, use the method
* {@link IdentifierNode#parseIdentifier(String)}.</p>
* {@link IdentifierNode#parseIdentifier(String)} and then call
* {@link IdentifierNode#getSegmentList()} on the resulting node.</p>
*/
public interface Segment {

Expand Down
21 changes: 15 additions & 6 deletions src/org/olap4j/mdx/Syntax.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,21 @@ public void unparse(
List<ParseTreeNode> argList,
ParseTreeWriter writer)
{
unparseList(
writer,
argList,
"(",
", ",
")");
if (argList.size() == 1
&& argList.get(0) instanceof CallNode
&& needParen(((CallNode) argList.get(0)).getArgList()))
{
// The parenthesized expression is going to defensively
// parenthesize itself. So, don't add another layer.
argList.get(0).unparse(writer);
} else {
unparseList(
writer,
argList,
"(",
", ",
")");
}
}
},

Expand Down
3 changes: 2 additions & 1 deletion src/org/olap4j/query/QueryDimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.olap4j.query;

import org.olap4j.OlapException;
import org.olap4j.impl.IdentifierParser;
import org.olap4j.impl.Olap4jUtil;
import org.olap4j.mdx.IdentifierNode;
import org.olap4j.mdx.IdentifierNode.Segment;
Expand Down Expand Up @@ -344,7 +345,7 @@ public void clearExclusions() {
}

public static String[] getNameParts(String sel) {
List<Segment> list = IdentifierNode.parseIdentifier(sel);
List<Segment> list = IdentifierParser.parseIdentifier(sel);
String nameParts[] = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
nameParts[i] = list.get(i).getName();
Expand Down
9 changes: 3 additions & 6 deletions testsrc/org/olap4j/ConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2588,8 +2588,7 @@ private void buildQuery(
SelectNode query = new SelectNode();
ParseTreeNode cubeNode;
if (useCubeObject) {
cubeNode = new IdentifierNode(
IdentifierNode.parseIdentifier(cube.getUniqueName()));
cubeNode = IdentifierNode.parseIdentifier(cube.getUniqueName());
} else {
cubeNode = new CubeNode(null, cube);
}
Expand All @@ -2599,15 +2598,13 @@ private void buildQuery(
null, false, Axis.COLUMNS, null,
new CallNode(
null, "MEMBERS", Syntax.Property,
new IdentifierNode(
IdentifierNode.parseIdentifier("[Gender]"))));
IdentifierNode.parseIdentifier("[Gender]")));
AxisNode rowAxis =
new AxisNode(
null, false, Axis.ROWS, null,
new CallNode(
null, "CHILDREN", Syntax.Property,
new IdentifierNode(
IdentifierNode.parseIdentifier("[Customers].[USA]"))));
IdentifierNode.parseIdentifier("[Customers].[USA]")));
query.getAxisList().add(columnAxis);
query.getAxisList().add(rowAxis);
OlapStatement statement = olapConnection.createStatement();
Expand Down
22 changes: 11 additions & 11 deletions testsrc/org/olap4j/impl/Olap4jUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public void testUnmodifiableArrayList() {
assertEquals("y", copyList.get(1));

// test the of(Collection) method
final ArrayList<String> arrayList = new ArrayList<String>();
final List<String> arrayList = new ArrayList<String>();
arrayList.add("foo");
arrayList.add("bar");
final UnmodifiableArrayList<String> list3 =
Expand Down Expand Up @@ -348,40 +348,40 @@ private void checkParseFormattedCellValue(
*/
public void testParseIdentifier() {
List<IdentifierNode.Segment> segments =
IdentifierNode.parseIdentifier(
IdentifierParser.parseIdentifier(
"[string].[with].[a [bracket]] in it]");
assertEquals(3, segments.size());
assertEquals("a [bracket] in it", segments.get(2).getName());

segments =
IdentifierNode.parseIdentifier(
IdentifierParser.parseIdentifier(
"[Worklog].[All].[calendar-[LANGUAGE]].js]");
assertEquals(3, segments.size());
assertEquals("calendar-[LANGUAGE].js", segments.get(2).getName());

// allow spaces before, after and between
segments = IdentifierNode.parseIdentifier(" [foo] . [bar].[baz] ");
segments = IdentifierParser.parseIdentifier(" [foo] . [bar].[baz] ");
assertEquals(3, segments.size());
assertEquals("foo", segments.get(0).getName());

// first segment not quoted
segments = IdentifierNode.parseIdentifier("Time.1997.[Q3]");
segments = IdentifierParser.parseIdentifier("Time.1997.[Q3]");
assertEquals(3, segments.size());
assertEquals("Time", segments.get(0).getName());
assertEquals("1997", segments.get(1).getName());
assertEquals("Q3", segments.get(2).getName());

// spaces ignored after unquoted segment
segments =
IdentifierNode.parseIdentifier("[Time . Weekly ] . 1997 . [Q3]");
IdentifierParser.parseIdentifier("[Time . Weekly ] . 1997 . [Q3]");
assertEquals(3, segments.size());
assertEquals("Time . Weekly ", segments.get(0).getName());
assertEquals("1997", segments.get(1).getName());
assertEquals("Q3", segments.get(2).getName());

// identifier ending in '.' is invalid
try {
segments = IdentifierNode.parseIdentifier("[foo].[bar].");
segments = IdentifierParser.parseIdentifier("[foo].[bar].");
fail("expected exception, got " + segments);
} catch (IllegalArgumentException e) {
assertEquals(
Expand All @@ -391,7 +391,7 @@ public void testParseIdentifier() {
}

try {
segments = IdentifierNode.parseIdentifier("[foo].[bar");
segments = IdentifierParser.parseIdentifier("[foo].[bar");
fail("expected exception, got " + segments);
} catch (IllegalArgumentException e) {
assertEquals(
Expand All @@ -400,7 +400,7 @@ public void testParseIdentifier() {
}

try {
segments = IdentifierNode.parseIdentifier("[Foo].[Bar], [Baz]");
segments = IdentifierParser.parseIdentifier("[Foo].[Bar], [Baz]");
fail("expected exception, got " + segments);
} catch (IllegalArgumentException e) {
assertEquals(
Expand All @@ -409,7 +409,7 @@ public void testParseIdentifier() {
}

// test case for bug 3036629, "Patch 328 breaks test".
segments = IdentifierNode.parseIdentifier(
segments = IdentifierParser.parseIdentifier(
"[ProductFilterDim].[Product Main Group Name].&[Maingroup (xyz)]");
assertEquals(3, segments.size());
final IdentifierNode.Segment s0 = segments.get(0);
Expand Down Expand Up @@ -447,7 +447,7 @@ public void testParseIdentifierAdvanced() {
// ** Sub-segment #2 is UNQUOTED, name "USA"
// * Segment #3 is a KEY. It has 1 sub-segment:
// ** Sub-segment #0 is QUOTED, name "cust1234"</li>
segments = IdentifierNode.parseIdentifier(
segments = IdentifierParser.parseIdentifier(
"[Customers].[City].&[San Francisco]&CA&USA.&[cust1234]");
assertEquals(4, segments.size());
final IdentifierNode.Segment s0 = segments.get(0);
Expand Down
9 changes: 5 additions & 4 deletions testsrc/org/olap4j/mdx/MdxTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void testImplode() {
public void testParseIdentifier() {
List<IdentifierNode.Segment> segments =
IdentifierNode.parseIdentifier(
"[string].[with].[a [bracket]] in it]");
"[string].[with].[a [bracket]] in it]").getSegmentList();
assertEquals(3, segments.size());
assertEquals(
"a [bracket] in it",
Expand All @@ -89,13 +89,13 @@ public void testParseIdentifier() {
segments.get(2).getQuoting());

segments = IdentifierNode.parseIdentifier(
"[Worklog].[All].[calendar-[LANGUAGE]].js]");
"[Worklog].[All].[calendar-[LANGUAGE]].js]").getSegmentList();
assertEquals(3, segments.size());
assertEquals(
"calendar-[LANGUAGE].js",
segments.get(2).getName());

segments = IdentifierNode.parseIdentifier("[foo].bar");
segments = IdentifierNode.parseIdentifier("[foo].bar").getSegmentList();
assertEquals(2, segments.size());
assertEquals(
IdentifierNode.Quoting.QUOTED,
Expand All @@ -105,7 +105,8 @@ public void testParseIdentifier() {
segments.get(1).getQuoting());

try {
segments = IdentifierNode.parseIdentifier("[foo].[bar");
segments =
IdentifierNode.parseIdentifier("[foo].[bar").getSegmentList();
fail("expected exception, got " + segments);
} catch (RuntimeException e) {
assertEquals(
Expand Down
51 changes: 49 additions & 2 deletions testsrc/org/olap4j/test/ParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.sql.SQLException;
import java.sql.Connection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -543,7 +544,7 @@ public void testIsNull() {

assertParseExpr(
"(x is null) + 56 > 6",
"((((x IS NULL)) + 56.0) > 6.0)");
"(((x IS NULL) + 56.0) > 6.0)");

// FIXME: Should be:
// "(((((x IS NULL) AND (a = b)) OR ((c = (d + 5.0))) IS NULL) + 5.0)"
Expand Down Expand Up @@ -835,11 +836,57 @@ public void testInnerSelect() {
"SELECT\n"
+ "FROM (\n"
+ " SELECT\n"
+ " ({[ProductDim].[Product Group].&[Mobile Phones]}) ON COLUMNS\n"
+ " {[ProductDim].[Product Group].&[Mobile Phones]} ON COLUMNS\n"
+ " FROM [cube])\n"
+ "CELL PROPERTIES VALUE");
}

/**
* Test case for adding to WITH clause.
*/
public void testWithAdd() {
SelectNode selectNode = new SelectNode();
IdentifierNode startDate =
new IdentifierNode(
new IdentifierNode.NameSegment("Date"),
new IdentifierNode.NameSegment("2010-01-03"));
IdentifierNode endDate =
new IdentifierNode(
new IdentifierNode.NameSegment("Date"),
new IdentifierNode.NameSegment("2010-10-03"));
IdentifierNode name =
new IdentifierNode(
new IdentifierNode.NameSegment("Date"),
new IdentifierNode.NameSegment("Date Range"));
CallNode cn = new CallNode(null, ":", Syntax.Infix, startDate, endDate);
ParseTreeNode exp =
new CallNode(
null,
"Aggregate",
Syntax.Function,
new CallNode(
null,
"{}",
Syntax.Braces,
cn));
WithMemberNode withMemberNode =
new WithMemberNode(
null, name, exp, Collections.<PropertyValueNode>emptyList());
selectNode.setFrom(
IdentifierNode.parseIdentifier("Sales"));
selectNode.getWithList().add(withMemberNode);
final String queryString = selectNode.toString();
TestContext.assertEqualsVerbose(
"WITH\n"
+ "MEMBER [Date].[Date Range] AS\n"
+ " Aggregate({([Date].[2010-01-03] : [Date].[2010-10-03])})\n"
+ "SELECT\n"
+ "FROM Sales",
queryString);
// check that unparsed string is valid
assertParseQuery(queryString, TestContext.unfold(queryString));
}

/**
* Parses an MDX query and asserts that the result is as expected when
* unparsed.
Expand Down

0 comments on commit 4b0a021

Please sign in to comment.