diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 6e59a0e..55647d0 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -96,7 +96,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection { private boolean autoCommit; private boolean readOnly; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; /** * Name of the "DATA_SOURCE_NAME" column returned from @@ -1088,10 +1088,15 @@ public void handle( */ - final String hierarchyName = - stringElement(row, "HIERARCHY_NAME"); + final String hierarchyUniqueName = stringElement(row, "HIERARCHY_UNIQUE_NAME"); + // SAP BW doesn't return a HIERARCHY_NAME attribute, + // so try to use the unique name instead + final String hierarchyName = + stringElement(row, "HIERARCHY_NAME") == null + ? hierarchyUniqueName + : stringElement(row, "HIERARCHY_NAME"); final String hierarchyCaption = stringElement(row, "HIERARCHY_CAPTION"); final String description = @@ -1151,10 +1156,15 @@ public void handle( */ - final String levelName = - stringElement(row, "LEVEL_NAME"); + final String levelUniqueName = stringElement(row, "LEVEL_UNIQUE_NAME"); + // SAP BW doesn't return a HIERARCHY_NAME attribute, + // so try to use the unique name instead + final String levelName = + stringElement(row, "LEVEL_NAME") == null + ? levelUniqueName + : stringElement(row, "LEVEL_NAME"); final String levelCaption = stringElement(row, "LEVEL_CAPTION"); final String description = @@ -1219,44 +1229,36 @@ public void handle( Measure.Aggregator.getDictionary().forOrdinal( integerElement( row, "MEASURE_AGGREGATOR")); - final Datatype datatype = - Datatype.getDictionary().forOrdinal( + final Datatype datatype; + Datatype ordinalDatatype = + Datatype.getDictionary().forName( + stringElement(row, "DATA_TYPE")); + if (ordinalDatatype == null) { + datatype = Datatype.getDictionary().forOrdinal( integerElement(row, "DATA_TYPE")); + } else { + datatype = ordinalDatatype; + } final boolean measureIsVisible = booleanElement(row, "MEASURE_IS_VISIBLE"); - // REVIEW: We're making a lot of assumptions about where Measures - // live. - final XmlaOlap4jLevel measuresLevel = - (XmlaOlap4jLevel) - context.getCube(row).getHierarchies().get("Measures") - .getLevels().get(0); - - // Every measure is a member. MDSCHEMA_MEASURES does not return all - // properties of measures, so lookup the corresponding member. In - // particular, we need the ordinal. - if (list.isEmpty()) { - // First call this method, ask for all members of the measures - // level. This should ensures that we get all members in one - // round trip. - final List measureMembers = measuresLevel.getMembers(); - Olap4jUtil.discard(measureMembers); - } - Member member = + + final Member member = context.getCube(row).getMetadataReader() .lookupMemberByUniqueName( measureUniqueName); - final int ordinal; - if (member != null) { - ordinal = member.getOrdinal(); - } else { - ordinal = -1; + + if (member == null) { + throw new OlapException( + "The server failed to resolve a member with the same unique name as a measure named " + + measureUniqueName); } list.add( new XmlaOlap4jMeasure( - measuresLevel, measureUniqueName, measureName, - measureCaption, description, null, measureAggregator, - datatype, measureIsVisible, ordinal)); + (XmlaOlap4jLevel)member.getLevel(), measureUniqueName, + measureName, measureCaption, description, null, + measureAggregator, datatype, measureIsVisible, + member.getOrdinal())); } public void sortList(List list) { @@ -1565,9 +1567,18 @@ public void handle( String uniqueName = stringElement(row, "DESCRIPTION"); String caption = stringElement(row, "PROPERTY_CAPTION"); String name = stringElement(row, "PROPERTY_NAME"); - Datatype dataType = - Datatype.getDictionary().forOrdinal( + Datatype datatype; + + Datatype ordinalDatatype = + Datatype.getDictionary().forName( + stringElement(row, "DATA_TYPE")); + if (ordinalDatatype == null) { + datatype = Datatype.getDictionary().forOrdinal( integerElement(row, "DATA_TYPE")); + } else { + datatype = ordinalDatatype; + } + final Integer contentTypeOrdinal = integerElement(row, "PROPERTY_CONTENT_TYPE"); Property.ContentType contentType = @@ -1580,7 +1591,7 @@ public void handle( Property.TypeFlag.getDictionary().forMask(propertyType); list.add( new XmlaOlap4jProperty( - uniqueName, name, caption, description, dataType, type, + uniqueName, name, caption, description, datatype, type, contentType)); } } diff --git a/src/org/olap4j/metadata/Datatype.java b/src/org/olap4j/metadata/Datatype.java index ab3a07c..abb347b 100644 --- a/src/org/olap4j/metadata/Datatype.java +++ b/src/org/olap4j/metadata/Datatype.java @@ -82,7 +82,102 @@ public enum Datatype implements XmlaConstant { + "actual length of the string is determined from the bound length " + "value. The maximum length of the string is the number of allocated " + "bytes divided by sizeof(wchar_t) and truncated to the nearest " - + "integer."); + + "integer."), + + /** + * Used by SAP BW. Represents a Character + */ + ACCP(1000, "ACCP", "SAP BW Character"), + + /** + * Used by SAP BW. Represents a CHAR + */ + CHAR(1001, "CHAR", "SAP BW CHAR"), + + /** + * Used by SAP BW. Represents a CHAR + */ + CUKY(1002, "CUKY", "SAP BW CHAR"), + + /** + * Used by SAP BW. Represents a Currency - Packed decimal, Integer + */ + CURR(1003, "CURR", "SAP BW Currency - Packed decimal, Integer"), + + /** + * Used by SAP BW. Represents a Date + */ + DATS(1004, "DATS", "SAP BW Date"), + + /** + * Used by SAP BW. Represents a Decimal + */ + DEC (1005, "DEC", "SAP BW Decimal"), + + /** + * Used by SAP BW. Represents a Point + */ + FLTP(1006, "FLTP", "SAP BW Floating Point"), + + /** + * Used by SAP BW. Represents a Byte + */ + INT1(1007, "INT1", "SAP BW Byte"), + + /** + * Used by SAP BW. Represents a Small integer + */ + INT2(1008, "INT2", "SAP BW Small integer"), + + /** + * Used by SAP BW. Represents an Integer + */ + INT4(1009, "INT4", "SAP BW Integer"), + + /** + * Used by SAP BW. Represents a Text + */ + LCHR(1010, "LCHR", "SAP BW Text"), + + /** + * Used by SAP BW. Represents a Numeric + */ + NUMC(1011, "NUMC", "SAP BW Numeric"), + + /** + * Used by SAP BW. Represents a Tiny Int + */ + PREC(1012, "PREC", "SAP BW Tiny Int"), + + /** + * Used by SAP BW. Represents a QUAN Integer + */ + QUAN(1013, "QUAN", "SAP BW QUAN Integer"), + + /** + * Used by SAP BW. Represents a String + */ + SSTR(1014, "SSTR", "SAP BW String"), + + /** + * Used by SAP BW. Represents a Long String + */ + STRG(1015, "STRG", "SAP BW Long String"), + + /** + * Used by SAP BW. Represents a Time + */ + TIMS(1016, "TIMS", "SAP BW Time"), + + /** + * Used by SAP BW. Represents a Varchar + */ + VARC(1017, "VARC", "SAP BW Varchar"), + + /** + * Used by SAP BW. Represents a Long String for Units + */ + UNIT(1018, "UNIT", "SAP BW Long String for Units"); private final int xmlaOrdinal; private String dbTypeIndicator; @@ -101,14 +196,24 @@ public enum Datatype implements XmlaConstant { this.description = description; } + /** + * The internal name of this Datatype. + * Might not be unique across Datatype instances. + */ public String xmlaName() { return dbTypeIndicator; } + /** + * Human readable description of a Datatype instance. + */ public String getDescription() { return description; } + /** + * Unique identifier of a Datatype instance. + */ public int xmlaOrdinal() { return xmlaOrdinal; } diff --git a/src/org/olap4j/metadata/XmlaConstants.java b/src/org/olap4j/metadata/XmlaConstants.java index e44a889..e4bfedc 100644 --- a/src/org/olap4j/metadata/XmlaConstants.java +++ b/src/org/olap4j/metadata/XmlaConstants.java @@ -776,4 +776,4 @@ public interface EnumWithDesc { } } -// XmlaConstants.java +// End XmlaConstants.java