From 81a26e588a27a3ecdc70eaeb520b7193844a23c0 Mon Sep 17 00:00:00 2001 From: Will Gorman Date: Wed, 13 Feb 2008 20:36:10 +0000 Subject: [PATCH] Completed the implementation of the org.olap4j.query API git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@74 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- src/org/olap4j/mdx/SelectNode.java | 9 + src/org/olap4j/query/Query.java | 235 ++++++++++++++++- src/org/olap4j/query/QueryAxis.java | 9 +- src/org/olap4j/query/QueryDimension.java | 70 +++-- src/org/olap4j/query/Selection.java | 5 +- src/org/olap4j/query/SelectionFactory.java | 11 +- src/org/olap4j/query/SelectionImpl.java | 8 + testsrc/org/olap4j/OlapTest.java | 292 ++++++++++++++++++++- 8 files changed, 606 insertions(+), 33 deletions(-) diff --git a/src/org/olap4j/mdx/SelectNode.java b/src/org/olap4j/mdx/SelectNode.java index 5eb48ae..d9a302a 100644 --- a/src/org/olap4j/mdx/SelectNode.java +++ b/src/org/olap4j/mdx/SelectNode.java @@ -12,6 +12,7 @@ import org.olap4j.type.Type; import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; @@ -86,6 +87,14 @@ public Type getType() { return null; } + public String toString() { + StringWriter sw = new StringWriter(); + ParseTreeWriter pw = new ParseTreeWriter(new PrintWriter(sw)); + unparse(pw); + sw.flush(); + return sw.toString(); + } + public void unparse(ParseTreeWriter writer) { final PrintWriter pw = writer.getPrintWriter(); if (!withList.isEmpty()) { diff --git a/src/org/olap4j/query/Query.java b/src/org/olap4j/query/Query.java index 3651000..b3b6f96 100644 --- a/src/org/olap4j/query/Query.java +++ b/src/org/olap4j/query/Query.java @@ -13,7 +13,14 @@ import org.olap4j.metadata.Dimension; import org.olap4j.metadata.Member; import org.olap4j.*; +import org.olap4j.mdx.AxisNode; +import org.olap4j.mdx.CallNode; +import org.olap4j.mdx.CubeNode; +import org.olap4j.mdx.IdentifierNode; +import org.olap4j.mdx.MemberNode; +import org.olap4j.mdx.ParseTreeNode; import org.olap4j.mdx.SelectNode; +import org.olap4j.mdx.Syntax; import java.util.*; import java.sql.SQLException; @@ -67,7 +74,7 @@ public Query(String name, Cube cube) throws SQLException { * Returns the MDX parse tree behind this Query. */ public SelectNode getSelect() { - throw new UnsupportedOperationException(); + return new Olap4jNodeConverter().toOlap4j(this); } public Cube getCube() { @@ -86,14 +93,17 @@ public void swapAxes() { if (axes.size() != 4) { throw new IllegalArgumentException(); } - List tmp = new ArrayList(); - QueryAxis columnsAxis = axes.get(Axis.COLUMNS); - QueryAxis rowsAxis = axes.get(Axis.ROWS); - tmp.addAll(this.across.getDimensions()); - columnsAxis.getDimensions().clear(); - columnsAxis.getDimensions().addAll(rowsAxis.getDimensions()); - rowsAxis.getDimensions().clear(); - rowsAxis.getDimensions().addAll(tmp); + List tmpAcross = new ArrayList(); + tmpAcross.addAll(across.getDimensions()); + + List tmpDown = new ArrayList(); + tmpDown.addAll(down.getDimensions()); + + across.getDimensions().clear(); + down.getDimensions().clear(); + + across.getDimensions().addAll(tmpDown); + down.getDimensions().addAll(tmpAcross); } public Map getAxes() { @@ -128,9 +138,8 @@ public boolean validate() throws OlapException { public CellSet execute() throws OlapException { SelectNode mdx = getSelect(); - String mdxString = mdx.toString(); OlapStatement olapStatement = connection.createStatement(); - return olapStatement.executeOlapQuery(mdxString); + return olapStatement.executeOlapQuery(mdx); } public String getName() { @@ -144,6 +153,210 @@ public Locale getLocale() { public SelectionFactory getSelectionFactory() { return selectionFactory; } + + private static class Olap4jNodeConverter { + + public SelectNode toOlap4j(Query query) { + List list = Collections.emptyList(); + List withList = Collections.emptyList(); + List axisList = new ArrayList(); + axisList.add(query.getAxes().get(Axis.COLUMNS)); + axisList.add(query.getAxes().get(Axis.ROWS)); + + return new SelectNode( + null, + withList, + toOlap4j(axisList), + new CubeNode( + null, + query.getCube()), + query.getAxes().containsKey(Axis.FILTER) + ? null + : toOlap4j(query.getAxes().get(Axis.FILTER)), + list); + } + + private CallNode generateSetCall(ParseTreeNode... args) { + final CallNode callNode = new CallNode( + null, + "{}", + Syntax.Braces, + args + ); + + return callNode; + } + + private CallNode generateListSetCall(List cnodes) { + final CallNode callNode = new CallNode( + null, + "{}", + Syntax.Braces, + cnodes + ); + return callNode; + } + + private CallNode generateListTupleCall(List cnodes) { + final CallNode callNode = new CallNode( + null, + "()", + Syntax.Parentheses, + cnodes + ); + return callNode; + } + + protected CallNode getMemberSet(QueryDimension dimension) { + final CallNode cnode = new CallNode( + null, + "{}", + Syntax.Braces, + toOlap4j(dimension) + ); + return cnode; + } + + protected CallNode crossJoin(QueryDimension dim1, QueryDimension dim2) { + return new CallNode( + null, + "CrossJoin", + Syntax.Function, + getMemberSet(dim1), + getMemberSet(dim2)); + } + + // + // This method merges the selections into a single + // MDX axis selection. Right now we do a simple + // crossjoin + // + private AxisNode toOlap4j(QueryAxis axis) { + CallNode callNode = null; + int numDimensions = axis.getDimensions().size(); + if( axis.getLocation() == Axis.FILTER ) { + // need a tuple + // need a crossjoin + List members = new ArrayList(); + for( int dimNo = 0; dimNo < numDimensions; dimNo++ ) { + QueryDimension dimension = + axis.getDimensions().get( dimNo ); + if( dimension.getSelections().size() == 1 ) { + members.addAll(toOlap4j(dimension)); + } + } + callNode = generateListTupleCall(members); + } else if( numDimensions == 1 ) { + QueryDimension dimension = axis.getDimensions().get( 0 ); + List members = toOlap4j(dimension); + callNode = generateListSetCall(members); + } else if( numDimensions == 2 ) { + callNode = + crossJoin( axis.getDimensions().get(0), + axis.getDimensions().get(1)); + } else { + // need a longer crossjoin + // start from the back of the list; + List dims = axis.getDimensions(); + callNode = getMemberSet(dims.get(dims.size() - 1)); + for( int i = dims.size() - 2; i >= 0; i-- ) { + CallNode memberSet = getMemberSet(dims.get(i)); + callNode = new CallNode( + null, + "CrossJoin", + Syntax.Function, + memberSet, + callNode); + } + } + return new AxisNode( + null, + false, + axis.getLocation(), + new ArrayList(), + callNode); + + } + + private List toOlap4j(QueryDimension dimension) { + List members = new ArrayList(); + for (Selection selection : dimension.getSelections()) { + members.add(toOlap4j(selection)); + } + return members; + } + + private ParseTreeNode toOlap4j(Selection selection) { + try { + return toOlap4j(selection.getMember(), selection.getOperator()); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private ParseTreeNode toOlap4j(Member member, Selection.Operator oper) { + ParseTreeNode node = null; + try { + switch(oper) { + case MEMBER: + node = new MemberNode(null, member); + break; + case SIBLINGS: + node = new CallNode( + null, + "Siblings", + Syntax.Property, + new MemberNode(null, member) + ); + break; + case CHILDREN: + node = new CallNode( + null, + "Children", + Syntax.Property, + new MemberNode(null, member) + ); + break; + case INCLUDE_CHILDREN: + node = generateSetCall( + new MemberNode(null, member), + toOlap4j(member, Selection.Operator.CHILDREN) + ); + break; + case DESCENDANTS: + node = new CallNode( + null, + "Descendants", + Syntax.Function, + new MemberNode(null, member) + ); + break; + case ANCESTORS: + node = new CallNode( + null, + "Ascendants", + Syntax.Function, + new MemberNode(null, member) + ); + break; + default: + System.out.println("NOT IMPLEMENTED: " + oper); + } + } catch (Exception e) { + e.printStackTrace(); + } + return node; + } + + private List toOlap4j(List axes) { + final ArrayList axisList = new ArrayList(); + for (QueryAxis axis : axes) { + axisList.add(toOlap4j(axis)); + } + return axisList; + } + } } // End Query.java diff --git a/src/org/olap4j/query/QueryAxis.java b/src/org/olap4j/query/QueryAxis.java index d474e86..3939005 100644 --- a/src/org/olap4j/query/QueryAxis.java +++ b/src/org/olap4j/query/QueryAxis.java @@ -92,12 +92,19 @@ public QueryDimension set(int index, QueryDimension dimension) { } public void add(int index, QueryDimension dimension) { + if (this.contains(dimension)) { + throw new IllegalStateException("dimension already on this axis"); + } if (dimension.getAxis() != null) { // careful! potential for loop dimension.getAxis().getDimensions().remove(dimension); } dimension.setAxis(QueryAxis.this); - list.add(index, dimension); + if (index >= list.size()) { + list.add(dimension); + } else { + list.add(index, dimension); + } } public QueryDimension remove(int index) { diff --git a/src/org/olap4j/query/QueryDimension.java b/src/org/olap4j/query/QueryDimension.java index f9d9117..dbbf2f5 100644 --- a/src/org/olap4j/query/QueryDimension.java +++ b/src/org/olap4j/query/QueryDimension.java @@ -9,11 +9,16 @@ */ package org.olap4j.query; +import org.olap4j.OlapException; +import org.olap4j.mdx.IdentifierNode; +import org.olap4j.mdx.IdentifierNode.Segment; import org.olap4j.metadata.*; import java.util.List; import java.util.ArrayList; import java.util.AbstractList; +import java.util.Set; +import java.util.TreeSet; /** * Usage of a dimension for an OLAP query. @@ -69,23 +74,55 @@ public Selection createSelection( member, operator); } - public List resolve(Selection selection) + public static String[] getNameParts(String sel) { + List list = IdentifierNode.parseIdentifier(sel); + String nameParts[] = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + nameParts[i] = list.get(i).getName(); + } + return nameParts; + } + + public List resolve(Selection selection) throws OlapException { assert selection != null; - + final Member.TreeOp op; + Member.TreeOp secondOp = null; switch (selection.getOperator()) { - case CHILDREN: - /* - * TODO: implement CHILDREN operator. - * - * need to implement getChildren method or something similar - maybe - * generate MDX - return dimension.getChildren(selection.getHierarchyName(), selection.getLevelName(), selection.getName()); - */ - throw new UnsupportedOperationException(); - default: - // TODO implement other operators - throw new UnsupportedOperationException(); + case CHILDREN: + op = Member.TreeOp.CHILDREN; + break; + + case SIBLINGS: + op = Member.TreeOp.SIBLINGS; + break; + + case INCLUDE_CHILDREN: + op = Member.TreeOp.SELF; + secondOp = Member.TreeOp.CHILDREN; + break; + + case MEMBER: + op = Member.TreeOp.SELF; + break; + + default: + throw new OlapException("Operation not supported: " + selection.getOperator()); + + } + Set set = new TreeSet(); + set.add(op); + if (secondOp != null) { + set.add(secondOp); + } + try { + return + query.getCube().lookupMembers( + set, + getNameParts(selection.getName()) + ); + } catch (Exception e) { + throw new OlapException("Error while resolving selection " + selection.toString(), e); } } @@ -127,9 +164,8 @@ public Selection set(int index, Selection selection) { } public void add(int index, Selection selection) { - if (selection.getDimension() != dimension) { - // TODO raise an exception - return; + if (this.contains(selection)) { + throw new IllegalStateException("dimension already contains selection"); } list.add(index, selection); } diff --git a/src/org/olap4j/query/Selection.java b/src/org/olap4j/query/Selection.java index fe97fb7..6f5fcbc 100644 --- a/src/org/olap4j/query/Selection.java +++ b/src/org/olap4j/query/Selection.java @@ -10,6 +10,7 @@ package org.olap4j.query; import org.olap4j.metadata.Dimension; +import org.olap4j.metadata.Member; /** * A selection of members from an OLAP dimension hierarchy. @@ -32,6 +33,8 @@ public interface Selection { void setName(String name); + Member getMember(); + Dimension getDimension(); String getHierarchyName(); @@ -44,7 +47,7 @@ public interface Selection { void setOperator(Operator operator); public enum Operator { - MEMBER, CHILDREN, INCLUDE_CHILDREN, SIBLINGS; + MEMBER, CHILDREN, INCLUDE_CHILDREN, SIBLINGS, ANCESTORS, DESCENDANTS; } } diff --git a/src/org/olap4j/query/SelectionFactory.java b/src/org/olap4j/query/SelectionFactory.java index 498d362..7c75a98 100644 --- a/src/org/olap4j/query/SelectionFactory.java +++ b/src/org/olap4j/query/SelectionFactory.java @@ -33,7 +33,16 @@ public class SelectionFactory { } Selection createMemberSelection(Member member, Selection.Operator operator) { - throw new UnsupportedOperationException(); + SelectionImpl selectionImpl = + new SelectionImpl( + member, + member.getDimension(), + member.getHierarchy().getUniqueName(), + member.getLevel().getUniqueName(), + member.getUniqueName(), + operator + ) {}; + return selectionImpl; } } diff --git a/src/org/olap4j/query/SelectionImpl.java b/src/org/olap4j/query/SelectionImpl.java index 55ba7fc..22a34cf 100644 --- a/src/org/olap4j/query/SelectionImpl.java +++ b/src/org/olap4j/query/SelectionImpl.java @@ -10,6 +10,7 @@ package org.olap4j.query; import org.olap4j.metadata.Dimension; +import org.olap4j.metadata.Member; /** * Abstract implementation of {@link Selection}. @@ -20,6 +21,7 @@ */ abstract class SelectionImpl implements Selection { + protected Member member; protected String dimensionName; protected String hierarchyName; protected String levelName; @@ -33,6 +35,7 @@ abstract class SelectionImpl implements Selection { * @pre operator != null */ public SelectionImpl( + Member member, Dimension dimension, String hierarchyName, String levelName, @@ -40,6 +43,7 @@ public SelectionImpl( Operator operator) { super(); + this.member = member; this.dimension = dimension; this.hierarchyName = hierarchyName; this.levelName = levelName; @@ -63,6 +67,10 @@ public void setDimension(Dimension dimension) { this.dimension = dimension; } + public Member getMember() { + return member; + } + public String getDimensionName() { return dimensionName; } diff --git a/testsrc/org/olap4j/OlapTest.java b/testsrc/org/olap4j/OlapTest.java index 911e976..3e7be9b 100644 --- a/testsrc/org/olap4j/OlapTest.java +++ b/testsrc/org/olap4j/OlapTest.java @@ -8,6 +8,7 @@ */ package org.olap4j; +import org.olap4j.mdx.SelectNode; import org.olap4j.metadata.*; import org.olap4j.query.*; import org.olap4j.test.TestContext; @@ -42,6 +43,51 @@ public OlapTest() { super(); } + public Cube getFoodmartCube(String cubeName) { + try { + Connection jdbcConnection = tester.createConnection(); + OlapConnection connection = + ((OlapWrapper) jdbcConnection).unwrap(OlapConnection.class); + final String catalogName; + switch (tester.getFlavor()) { + case MONDRIAN: + catalogName = "LOCALDB"; + break; + case XMLA: + default: + catalogName = "FoodMart"; + break; + } + Catalog catalog = connection.getCatalogs().get(catalogName); + NamedList schemas = catalog.getSchemas(); + if (schemas.size() == 0) { + System.out.println("No Schemas found in catalog"); + return null; + } + + // Use the first schema + Schema schema = schemas.get(0); + System.out.println("using schema name=" + schema.getName()); + + // Get a list of cube objects and dump their names + NamedList cubes = schema.getCubes(); + + if (cubes.size() == 0) { + // no cubes where present + System.out.println("No Cubes found in schema"); + return null; + } + + // take the first cube + return cubes.get(cubeName); + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + + } + public void testModel() { try { Connection jdbcConnection; @@ -189,7 +235,7 @@ public void testModel() { query.validate(); CellSet result = query.execute(); - System.out.println(result.toString()); + System.out.println(TestContext.toString(result)); // Create an XML doc to represent the results and print it out // This XML would be used by a remote client application to get the results @@ -206,10 +252,252 @@ public void testModel() { } catch (Throwable t) { t.printStackTrace(); + fail(); } } + public void testSelectionModes() { + try { + Cube cube = getFoodmartCube("Sales"); + if (cube == null) { + fail("Could not find Sales cube"); + } + Query query = new Query("my query", cube); + + // TEST CHILDREN SELECTION + + QueryDimension productDimension = query.getDimension("Product"); + Member drinkMember = cube.lookupMember("Product", "Drink"); + Selection drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.CHILDREN); + productDimension.getSelections().add(drinkSelection); + + QueryDimension measuresDimension = query.getDimension("Measures"); + Member storeSalesMember = cube.lookupMember("Measures", "Store Sales"); + Selection storeSalesSelection = + measuresDimension.createSelection(storeSalesMember, + Selection.Operator.MEMBER); + measuresDimension.getSelections().add(storeSalesSelection); + + query.getAxes().get(Axis.ROWS).getDimensions().add(productDimension); + query.getAxes().get(Axis.COLUMNS).getDimensions().add(measuresDimension); + + query.validate(); + + SelectNode mdx = query.getSelect(); + String mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{[Product].[All Products].[Drink].Children} ON ROWS\n" + + "FROM [Sales]"); + + // TEST ANCESTORS SELECTION + + productDimension.getSelections().clear(); + drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.ANCESTORS); + productDimension.getSelections().add(drinkSelection); + + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{Ascendants([Product].[All Products].[Drink])} ON ROWS\n" + + "FROM [Sales]"); + + // TEST DESCENDANTS SELECTION + + productDimension.getSelections().clear(); + drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.DESCENDANTS); + productDimension.getSelections().add(drinkSelection); + + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{Descendants([Product].[All Products].[Drink])} ON ROWS\n" + + "FROM [Sales]"); + + // TEST INCLUDE_CHILDREN SELECTION + + productDimension.getSelections().clear(); + drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.INCLUDE_CHILDREN); + productDimension.getSelections().add(drinkSelection); + + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{{[Product].[All Products].[Drink], [Product].[All Products].[Drink].Children}} ON ROWS\n" + + "FROM [Sales]"); + + // TEST SIBLINGS SELECTION + + productDimension.getSelections().clear(); + drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.SIBLINGS); + productDimension.getSelections().add(drinkSelection); + + query.validate(); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{[Product].[All Products].[Drink].Siblings} ON ROWS\n" + + "FROM [Sales]"); + + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + public void testMultipleDimensionSelections() { + try { + Cube cube = getFoodmartCube("Sales"); + if (cube == null) { + fail("Could not find Sales cube"); + } + Query query = new Query("my query", cube); + + // create selections + + QueryDimension productDimension = query.getDimension("Product"); + Member drinkMember = cube.lookupMember("Product", "Drink"); + Selection drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.CHILDREN); + productDimension.getSelections().add(drinkSelection); + + QueryDimension storeDimension = query.getDimension("Store"); + Member usaMember = cube.lookupMember("Store", "USA"); + Selection usaSelection = + storeDimension.createSelection(usaMember, + Selection.Operator.INCLUDE_CHILDREN); + storeDimension.getSelections().add(usaSelection); + + QueryDimension timeDimension = query.getDimension("Time"); + Member year1997Member = cube.lookupMember("Time", "1997"); + Selection year1997Selection = + timeDimension.createSelection(year1997Member, + Selection.Operator.CHILDREN); + timeDimension.getSelections().add(year1997Selection); + + QueryDimension measuresDimension = query.getDimension("Measures"); + Member storeSalesMember = cube.lookupMember("Measures", "Store Sales"); + Selection storeSalesSelection = + measuresDimension.createSelection(storeSalesMember, + Selection.Operator.MEMBER); + measuresDimension.getSelections().add(storeSalesSelection); + + query.getAxes().get(Axis.ROWS).getDimensions().add(productDimension); + query.getAxes().get(Axis.ROWS).getDimensions().add(storeDimension); + query.getAxes().get(Axis.ROWS).getDimensions().add(timeDimension); + query.getAxes().get(Axis.COLUMNS).getDimensions().add(measuresDimension); + + query.validate(); + + SelectNode mdx = query.getSelect(); + String mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "CrossJoin({[Product].[All Products].[Drink].Children}, " + + "CrossJoin({{[Store].[All Stores].[USA], " + + "[Store].[All Stores].[USA].Children}}, " + + "{[Time].[1997].Children})) ON ROWS\n" + + "FROM [Sales]"); + + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + public void testSwapAxes() { + try { + Cube cube = getFoodmartCube("Sales"); + if (cube == null) { + fail("Could not find Sales cube"); + } + Query query = new Query("my query", cube); + + // create selections + + QueryDimension productDimension = query.getDimension("Product"); + Member drinkMember = cube.lookupMember("Product", "Drink"); + Selection drinkSelection = + productDimension.createSelection(drinkMember, + Selection.Operator.CHILDREN); + productDimension.getSelections().add(drinkSelection); + + QueryDimension measuresDimension = query.getDimension("Measures"); + Member storeSalesMember = cube.lookupMember("Measures", "Store Sales"); + Selection storeSalesSelection = + measuresDimension.createSelection(storeSalesMember, + Selection.Operator.MEMBER); + measuresDimension.getSelections().add(storeSalesSelection); + + query.getAxes().get(Axis.ROWS).getDimensions().add(productDimension); + query.getAxes().get(Axis.COLUMNS).getDimensions().add(measuresDimension); + + query.validate(); + + assertEquals(productDimension.getAxis().getLocation(), Axis.ROWS); + assertEquals(measuresDimension.getAxis().getLocation(), Axis.COLUMNS); + + SelectNode mdx = query.getSelect(); + String mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Measures].[Store Sales]} ON COLUMNS,\n" + + "{[Product].[All Products].[Drink].Children} ON ROWS\n" + + "FROM [Sales]"); + + query.swapAxes(); + + assertEquals(productDimension.getAxis().getLocation(), Axis.COLUMNS); + assertEquals(measuresDimension.getAxis().getLocation(), Axis.ROWS); + + mdx = query.getSelect(); + mdxString = mdx.toString(); + assertEquals(mdxString, + "SELECT\n" + + "{[Product].[All Products].[Drink].Children} ON COLUMNS,\n" + + "{[Measures].[Store Sales]} ON ROWS\n" + + "FROM [Sales]"); + + query.swapAxes(); + + + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + + + public static void listHierarchies(Dimension dimension) { // Get a list of hierarchy objects and dump their names for (Hierarchy hierarchy : dimension.getHierarchies()) { @@ -397,7 +685,7 @@ public static void memberToXml( addCDataNode("name", member.getName(), root); addCDataNode("unique-name", member.getUniqueName(), root); - addCDataNode("description", member.getDescription(null), root); + // addCDataNode("description", member.getDescription(null), root); } catch (Throwable t) { t.printStackTrace();