diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java
index c426992..9420fd6 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java
@@ -31,6 +31,8 @@ class XmlaOlap4jCatalog implements Catalog, Named {
XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData,
String name)
{
+ assert olap4jDatabaseMetaData != null;
+ assert name != null;
this.olap4jDatabaseMetaData = olap4jDatabaseMetaData;
this.name = name;
this.schemas =
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java
index e8dbbb6..ef4c286 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java
@@ -305,37 +305,43 @@ void populate() throws OlapException {
* are supported, but no dates are yet supported. Those not supported
* fall back to Strings.
*
- *
If any exception is encountered, it returns null.
- *
* @param cell The cell of which we want the casted object.
* @return The object with a correct value.
- * @throws OlapException gets thrown if any error is encountered while casting the cell value.
+ * @throws OlapException if any error is encountered while casting the cell
+ * value
*/
private Object getTypedValue(Element cell) throws OlapException {
- try {
- Element elm = findChild(cell, MDDATASET_NS, "Value");
+ Element elm = findChild(cell, MDDATASET_NS, "Value");
+ if (elm == null) {
+ // Cell is null.
+ return null;
+ }
- // The object type is contained in xsi:type attribute.
- String type = elm.getAttribute("xsi:type");
- if (type.equals( "xsd:int")) {
- return XmlaOlap4jUtil.intElement(cell, "Value");
+ // The object type is contained in xsi:type attribute.
+ String type = elm.getAttribute("xsi:type");
+ try {
+ if (type.equals( "xsd:int")) {
+ return XmlaOlap4jUtil.intElement(cell, "Value");
} else if (type.equals( "xsd:integer")) {
- return XmlaOlap4jUtil.integerElement(cell, "Value");
+ return XmlaOlap4jUtil.integerElement(cell, "Value");
} else if (type.equals( "xsd:double")) {
- return XmlaOlap4jUtil.doubleElement(cell, "Value");
+ return XmlaOlap4jUtil.doubleElement(cell, "Value");
} else if (type.equals( "xsd:float")) {
- return XmlaOlap4jUtil.floatElement(cell, "Value");
+ return XmlaOlap4jUtil.floatElement(cell, "Value");
} else if (type.equals( "xsd:long")) {
- return XmlaOlap4jUtil.longElement(cell, "Value");
+ return XmlaOlap4jUtil.longElement(cell, "Value");
} else if (type.equals( "xsd:boolean")) {
- return XmlaOlap4jUtil.booleanElement(cell, "Value");
+ return XmlaOlap4jUtil.booleanElement(cell, "Value");
} else {
- return XmlaOlap4jUtil.stringElement(cell, "Value");
+ return XmlaOlap4jUtil.stringElement(cell, "Value");
}
} catch (Exception e) {
- throw new OlapException("En exception was encountered while casting a cell value to it's correct data type.", e); //$NON-NLS-1$
- }
- }
+ throw new OlapException(
+ "Error while casting a cell value to the correct java type for"
+ + " its XSD type " + type,
+ e);
+ }
+ }
/**
* Creates metadata for a cell set, given the DOM of the XMLA result.
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
index 70381e3..7716ff0 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
@@ -256,7 +256,9 @@ String getDataSourceInfo() throws OlapException {
throw new OlapException("Datasource name not found.", e);
} finally {
try {
- rSet.close();
+ if (rSet != null) {
+ rSet.close();
+ }
} catch (SQLException e) {
// ignore
}
@@ -985,11 +987,14 @@ public void handle(Element row, Context context, List list)
Olap4jUtil.discard(measureMembers);
}
Member member =
- context.getCube(row).getMetadataReader().lookupMemberByUniqueName(
- measureUniqueName);
- int ordinal = -1;
+ context.getCube(row).getMetadataReader()
+ .lookupMemberByUniqueName(
+ measureUniqueName);
+ final int ordinal;
if (member != null) {
ordinal = member.getOrdinal();
+ } else {
+ ordinal = -1;
}
list.add(
@@ -1055,6 +1060,11 @@ public void handle(Element row, Context context, List list) {
stringElement(row, "MEMBER_CAPTION");
int childrenCardinality =
integerElement(row, "CHILDREN_CARDINALITY");
+ // If this member is a measure, we want to return an object that
+ // implements the Measure interface to all API calls. But we also
+ // need to retrieve the properties that occur in MDSCHEMA_MEMBERS
+ // that are not available in MDSCHEMA_MEASURES, so we create a
+ // member for internal use.
list.add(
new XmlaOlap4jMember(
context.getLevel(row), memberUniqueName, memberName,
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java
index 57f7afd..b378acf 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java
@@ -59,9 +59,7 @@ class XmlaOlap4jCube implements Cube, Named
this.description = description;
this.metadataReader =
new CachingMetadataReader(
- new RawMetadataReader()
- )
- ;
+ new RawMetadataReader());
final XmlaOlap4jConnection olap4jConnection =
olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
@@ -115,6 +113,13 @@ class XmlaOlap4jCube implements Cube, Named
XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES,
new XmlaOlap4jConnection.MeasureHandler(),
restrictions);
+ // replace temporary member versions of measures in cache with final
+ // measures
+ for (XmlaOlap4jMeasure measure : measures) {
+ ((CachingMetadataReader) metadataReader).memberMap.put(
+ measure.getUniqueName(),
+ new SoftReference(measure));
+ }
// populate named sets
olap4jConnection.populateList(
namedSets, context,
@@ -436,6 +441,21 @@ public List getLevelMembers(
final XmlaOlap4jConnection.Context context =
new XmlaOlap4jConnection.Context(level);
List list = new ArrayList();
+ // If this is a level in the [Measures] dimension, we want to
+ // return objects that implement the Measure interface. During
+ // bootstrap, the list will be empty, and we need to return the
+ // regular Member objects which have the extra properties that are
+ // returned by MSCHEMA_MEMBERS but not MDSCHEMA_MEASURES.
+ switch (level.getDimension().getDimensionType()) {
+ case MEASURE:
+ if (!level.olap4jHierarchy.olap4jDimension.olap4jCube.measures
+ .isEmpty()) {
+ return Olap4jUtil.cast(
+ level.olap4jHierarchy.olap4jDimension.olap4jCube
+ .measures);
+ }
+ break;
+ }
olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection
.populateList(
list,
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java b/src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java
index d59f8df..85288b5 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java
@@ -25,7 +25,7 @@ class XmlaOlap4jDimension
implements Dimension, Named
{
final XmlaOlap4jCube olap4jCube;
- private final Type type;
+ final Type type;
final NamedList hierarchies =
new NamedListImpl();
private final String defaultHierarchyUniqueName;
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java b/src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java
index 9a01448..6466449 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java
@@ -9,8 +9,7 @@
package org.olap4j.driver.xmla;
import org.olap4j.impl.Named;
-import org.olap4j.metadata.Datatype;
-import org.olap4j.metadata.Measure;
+import org.olap4j.metadata.*;
/**
* Implementation of {@link org.olap4j.metadata.Measure}
@@ -42,7 +41,11 @@ class XmlaOlap4jMeasure
{
super(
olap4jLevel, uniqueName, name, caption, description,
- parentMemberUniqueName, Type.MEASURE, 0, ordinal);
+ parentMemberUniqueName,
+ aggregator == Aggregator.CALCULATED ? Type.FORMULA : Type.MEASURE,
+ 0, ordinal);
+ assert olap4jLevel.olap4jHierarchy.olap4jDimension.type
+ == Dimension.Type.MEASURE;
this.aggregator = aggregator;
this.datatype = datatype;
this.visible = visible;
diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java
index 40a2268..a421b73 100644
--- a/testsrc/org/olap4j/ConnectionTest.java
+++ b/testsrc/org/olap4j/ConnectionTest.java
@@ -129,6 +129,11 @@ void assertIsValid(Connection connection, int timeout) {
} else {
throw new RuntimeException(e);
}
+ } catch (AbstractMethodError e) {
+ // This happens in commons-dbcp. Somehow the method exists in
+ // the connection class, but it fails later. Not the fault of
+ // olap4j or the olapj driver, so ignore the error.
+ Olap4jUtil.discard(e);
}
}
@@ -204,7 +209,7 @@ public void testConnection() throws ClassNotFoundException, SQLException {
case DBCP:
// DBCP complains if you close a connection twice. Even though the
// JDBC spec is clear that it is OK.
- break;
+ break;
default:
connection.close();
break;
@@ -348,6 +353,32 @@ public void testStatement() throws SQLException {
connection.close();
}
+ public void testAxes() throws SQLException {
+ connection = tester.createConnection();
+ Statement statement = connection.createStatement();
+
+ OlapStatement olapStatement =
+ tester.getWrapper().unwrap(statement, OlapStatement.class);
+
+ CellSet cellSet =
+ olapStatement.executeOlapQuery(
+ "SELECT {[Measures].[Unit Sales]} on 0,\n"
+ + "{[Store].Children} on 1\n"
+ + "FROM [Sales]");
+ List axesList = cellSet.getAxes();
+ assertEquals(2, axesList.size());
+ final Member rowsMember =
+ axesList.get(0).getPositions().get(0).getMembers().get(0);
+ assertTrue(
+ rowsMember.getUniqueName(),
+ rowsMember instanceof Measure);
+ final Member columnsMember =
+ axesList.get(1).getPositions().get(0).getMembers().get(0);
+ assertTrue(
+ columnsMember.getUniqueName(),
+ !(columnsMember instanceof Measure));
+ }
+
public void testInvalidStatement() throws SQLException {
connection = tester.createConnection();
Statement statement = connection.createStatement();
@@ -1313,6 +1344,9 @@ public void testMetadata() throws Exception {
for (Member rootMember : rootMemberList) {
assertNull(rootMember.getParentMember());
}
+ assertEquals(
+ rootMemberList,
+ hierarchy.getLevels().get(0).getMembers());
assertNotNull(hierarchy.getDefaultMember());
assertNotNull(hierarchy.getName());
assertNotNull(hierarchy.getUniqueName());
@@ -1328,6 +1362,10 @@ public void testMetadata() throws Exception {
for (Member member : level.getMembers()) {
assertNotNull(member.getName());
assertEquals(level, member.getLevel());
+ if (dimension.getDimensionType()
+ == Dimension.Type.MEASURE) {
+ assertTrue(member instanceof Measure);
+ }
if (++k > 3) {
break;
}
@@ -1422,6 +1460,7 @@ public void testMetadata() throws Exception {
// Measures
int k = -1;
+ Set measureNameSet = new HashSet();
for (Measure measure : cube.getMeasures()) {
++k;
// The first measure is [Unit Sales], because the list must be
@@ -1429,10 +1468,33 @@ public void testMetadata() throws Exception {
if (k == 0) {
assertEquals("Unit Sales", measure.getName());
}
+ if (measure.getName().equals("Profit Growth")
+ || measure.getName().equals("Profit last Period")
+ || measure.getName().equals("Profit")) {
+ assertEquals(Member.Type.FORMULA, measure.getMemberType());
+ assertTrue(measure.isCalculated());
+ } else {
+ assertEquals(Member.Type.MEASURE, measure.getMemberType());
+ assertFalse(measure.isCalculated());
+ }
assertNotNull(measure.getName());
assertNotNull(measure.getAggregator());
assertTrue(measure.getDatatype() != null);
+ measureNameSet.add(measure.getName());
}
+ assertEquals(
+ new HashSet(
+ Arrays.asList(
+ "Unit Sales",
+ "Customer Count",
+ "Profit last Period",
+ "Profit",
+ "Profit Growth",
+ "Promotion Sales",
+ "Sales Count",
+ "Store Sales",
+ "Store Cost")),
+ measureNameSet);
}
/**