From 35d9ba46d5939df0cc459f59436d6b6b05a5dcd7 Mon Sep 17 00:00:00 2001 From: mkambol Date: Wed, 26 Jun 2013 10:17:49 -0400 Subject: [PATCH] [MONDRIAN-1581] Adding support for .getParentMember() to XmlaOlap4jSurpriseMember. --- .../olap4j/driver/xmla/XmlaOlap4jCellSet.java | 59 ++++++++++++++++- testsrc/org/olap4j/ConnectionTest.java | 63 +++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java index 4cd39c8..06cebd2 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java @@ -1377,6 +1377,8 @@ private static class XmlaOlap4jSurpriseMember private final int lnum; private final String caption; private final String uname; + private Member parentMember; + private final String parentMemberUniqueName; /** * Creates an XmlaOlap4jSurpriseMember. @@ -1402,6 +1404,15 @@ private static class XmlaOlap4jSurpriseMember this.lnum = lnum; this.caption = caption; this.uname = uname; + parentMemberUniqueName = getParentUniqueName(); + } + + private String getParentUniqueName() { + List segments = IdentifierNode + .parseIdentifier(getUniqueName()).getSegmentList(); + IdentifierNode parentIdentifier = new IdentifierNode( + segments.subList(0, segments.size() - 1)); + return parentIdentifier.toString(); } public final XmlaOlap4jCube getCube() { @@ -1429,8 +1440,54 @@ public int getChildMemberCount() { return 0; } + + /** + * In the case of a query-calculated member over XMLA, the only + * information we have to determine parent is this member's own + * unique name, its level number, and whether .hasAll() is true. + * + * This method attempts to figure out the parent member based on + * what we hope is the unique name of the parent--i.e. the member's + * own unique name with the last segment stripped off. + * + * For calculated members defined directly on the hierarchy, + * stripping off the last segment does not produce a valid member + * unique name. In that case, though, the level depth is 0, which + * we can take as an indication that the parent is null. + */ public Member getParentMember() { - return null; + if (getLevel().getDepth() == 0 || parentMemberUniqueName == null) { + return null; + } + if (parentMember == null) { + try { + parentMember = + getCube().getMetadataReader() + .lookupMemberByUniqueName(parentMemberUniqueName); + if (parentMember == null + && getLevel().getDepth() == 1 + && getHierarchy().hasAll()) + { + // couldn't find the parent by the constructed + // unique name, but we know it's (All) in this case. + parentMember = getAllMember(); + } + } catch (OlapException e) { + throw new RuntimeException( + "Failed to retrieve parent of " + getName(), e); + } + } + return parentMember; + } + + private Member getAllMember() throws OlapException { + if (!getHierarchy().hasAll()) { + return null; + } + List roots = getHierarchy().getRootMembers(); + assert roots.size() == 1; + + return roots.get(0); } public Level getLevel() { diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index aec144e..8baee2b 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -2296,6 +2296,69 @@ public void testParentChild() throws ClassNotFoundException, SQLException { assertEquals(0, positions.get(0).getMembers().size()); } + public void testCalculatedMemberParent() + throws ClassNotFoundException, SQLException + { + Class.forName(tester.getDriverClassName()); + connection = tester.createConnection(); + OlapConnection olapConnection = + tester.getWrapper().unwrap(connection, OlapConnection.class); + + // map of calc member names -> expected parent + Map tests = new HashMap(); + // on top level member of hierarchy w/o All + tests.put("Time.[1997].calc", "Time.[1997]"); + // defined against the hierarchy + tests.put("[Time].[Time].[calc]", null); + // under [All] + tests.put("[Store].[All Stores].calc", "[Store].[All Stores]"); + // defined using Level name + tests.put( + "[Store].[Store Country].[USA].calc", + "[Store].[All Stores].[USA]"); + // parent child + tests.put( + "[Employees].[Employees].[All Employees].calc", + "[Employees].[Employees].[All Employees]"); + // under [All] member of single level dimension + tests.put( + "[Pay Type].[All Pay Types].calc", + "[Pay Type].[All Pay Types]"); + + String mdxWith = "with member %s as '1' "; + String mdxSelect = "select {%s} on 0 from hr"; + for (String calcMember : tests.keySet()) { + // Get the calc member + String calcMemberQuery = String + .format(mdxWith + mdxSelect, calcMember, calcMember); + CellSet calcCell = olapConnection.createStatement() + .executeOlapQuery(calcMemberQuery); + Member calc = calcCell.getAxes().get(0).getPositions() + .get(0).getMembers().get(0); + + String parentMemberName = tests.get(calcMember); + + if (parentMemberName != null) { + // Retrieve the parent member + String parentMemberQuery = String + .format(mdxSelect, parentMemberName); + CellSet parentCell = olapConnection.createStatement() + .executeOlapQuery(parentMemberQuery); + + Member parent = parentCell.getAxes().get(0).getPositions() + .get(0).getMembers().get(0); + // verify parent member and calc.getParentMember() are the same + assertEquals( + "Parent member of " + calcMember + " is unexpected.", + parent, calc.getParentMember()); + } else { + assertEquals( + "Expecting a null parent member for " + calcMember, + null, calc.getParentMember()); + } + } + } + /** * Tests the type-derivation for * {@link org.olap4j.mdx.SelectNode#getFrom()} and the {@link CubeType}