From 4b0a021257e6a2fb6d9634aebd345cee4b3c0118 Mon Sep 17 00:00:00 2001
From: Julian Hyde
Date: Thu, 14 Oct 2010 21:24:51 +0000
Subject: [PATCH] Change IdentifierNode.parseIdentifier(String) to return an
IdentifierNode; it previously returned List.
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
---
src/org/olap4j/mdx/IdentifierNode.java | 31 +++++++------
src/org/olap4j/mdx/Syntax.java | 21 ++++++---
src/org/olap4j/query/QueryDimension.java | 3 +-
testsrc/org/olap4j/ConnectionTest.java | 9 ++--
testsrc/org/olap4j/impl/Olap4jUtilTest.java | 22 ++++-----
testsrc/org/olap4j/mdx/MdxTest.java | 9 ++--
testsrc/org/olap4j/test/ParserTest.java | 51 ++++++++++++++++++++-
7 files changed, 102 insertions(+), 44 deletions(-)
diff --git a/src/org/olap4j/mdx/IdentifierNode.java b/src/org/olap4j/mdx/IdentifierNode.java
index b66a45e..05844a4 100644
--- a/src/org/olap4j/mdx/IdentifierNode.java
+++ b/src/org/olap4j/mdx/IdentifierNode.java
@@ -176,9 +176,11 @@ public IdentifierNode deepCopy() {
}
/**
- * Parses an MDX identifier into a list of segments.
+ * Parses an MDX identifier string into an
+ * {@link org.olap4j.mdx.IdentifierNode}.
*
- * Each segment is a name combined with a description of how the name
+ *
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,
*
*
@@ -186,27 +188,27 @@ public IdentifierNode deepCopy() {
* "[Customers].USA.[South Dakota].[Sioux Falls].&[1245]")
*
*
- * returns
+ * returns an IdentifierNode consisting of the following segments:
*
- *
- * { Segment("Customers", QUOTED),
- * Segment("USA", UNQUOTED),
- * Segment("South Dakota", QUOTED),
- * Segment("Sioux Falls", QUOTED),
- * Segment("1245", KEY) }
- *
+ *
+ * - Segment("Customers", QUOTED),
+ *
- Segment("USA", UNQUOTED),
+ *
- Segment("South Dakota", QUOTED),
+ *
- Segment("Sioux Falls", QUOTED),
+ *
- Segment("1245", KEY)
+ *
*
* @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 parseIdentifier(String identifier) {
- return IdentifierParser.parseIdentifier(identifier);
+ public static IdentifierNode parseIdentifier(String identifier) {
+ return new IdentifierNode(IdentifierParser.parseIdentifier(identifier));
}
/**
@@ -279,7 +281,8 @@ static String unparseIdentifierList(List extends Segment> segments) {
* {@link org.olap4j.mdx.IdentifierNode.KeySegment KeySegment}.
*
* To parse an identifier into a list of segments, use the method
- * {@link IdentifierNode#parseIdentifier(String)}.
+ * {@link IdentifierNode#parseIdentifier(String)} and then call
+ * {@link IdentifierNode#getSegmentList()} on the resulting node.
*/
public interface Segment {
diff --git a/src/org/olap4j/mdx/Syntax.java b/src/org/olap4j/mdx/Syntax.java
index 60edb7d..800c51a 100644
--- a/src/org/olap4j/mdx/Syntax.java
+++ b/src/org/olap4j/mdx/Syntax.java
@@ -192,12 +192,21 @@ public void unparse(
List 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,
+ "(",
+ ", ",
+ ")");
+ }
}
},
diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java
index 3b52cd5..172dca6 100644
--- a/src/org/olap4j/query/QueryDimension.java
+++ b/src/org/olap4j/query/QueryDimension.java
@@ -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;
@@ -344,7 +345,7 @@ public void clearExclusions() {
}
public static String[] getNameParts(String sel) {
- List list = IdentifierNode.parseIdentifier(sel);
+ List list = IdentifierParser.parseIdentifier(sel);
String nameParts[] = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
nameParts[i] = list.get(i).getName();
diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java
index 9f44d3d..fd1b391 100644
--- a/testsrc/org/olap4j/ConnectionTest.java
+++ b/testsrc/org/olap4j/ConnectionTest.java
@@ -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);
}
@@ -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();
diff --git a/testsrc/org/olap4j/impl/Olap4jUtilTest.java b/testsrc/org/olap4j/impl/Olap4jUtilTest.java
index eed5892..72a57d1 100644
--- a/testsrc/org/olap4j/impl/Olap4jUtilTest.java
+++ b/testsrc/org/olap4j/impl/Olap4jUtilTest.java
@@ -228,7 +228,7 @@ public void testUnmodifiableArrayList() {
assertEquals("y", copyList.get(1));
// test the of(Collection) method
- final ArrayList arrayList = new ArrayList();
+ final List arrayList = new ArrayList();
arrayList.add("foo");
arrayList.add("bar");
final UnmodifiableArrayList list3 =
@@ -348,24 +348,24 @@ private void checkParseFormattedCellValue(
*/
public void testParseIdentifier() {
List 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());
@@ -373,7 +373,7 @@ public void testParseIdentifier() {
// 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());
@@ -381,7 +381,7 @@ public void testParseIdentifier() {
// 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(
@@ -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(
@@ -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(
@@ -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);
@@ -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"
- segments = IdentifierNode.parseIdentifier(
+ segments = IdentifierParser.parseIdentifier(
"[Customers].[City].&[San Francisco]&CA&USA.&[cust1234]");
assertEquals(4, segments.size());
final IdentifierNode.Segment s0 = segments.get(0);
diff --git a/testsrc/org/olap4j/mdx/MdxTest.java b/testsrc/org/olap4j/mdx/MdxTest.java
index cbe222e..bf3c0df 100644
--- a/testsrc/org/olap4j/mdx/MdxTest.java
+++ b/testsrc/org/olap4j/mdx/MdxTest.java
@@ -79,7 +79,7 @@ public void testImplode() {
public void testParseIdentifier() {
List 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",
@@ -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,
@@ -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(
diff --git a/testsrc/org/olap4j/test/ParserTest.java b/testsrc/org/olap4j/test/ParserTest.java
index 1ff6664..55d31ce 100644
--- a/testsrc/org/olap4j/test/ParserTest.java
+++ b/testsrc/org/olap4j/test/ParserTest.java
@@ -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;
@@ -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)"
@@ -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.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.