diff --git a/doc/index.html b/doc/index.html index c238c49..67652e5 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,141 +1,136 @@ - - - - - -olap4j - + + + + + +olap4j + - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - -
- olap4j   - open java api for - - OLAP
-
 
- - - - - -
-

- olap4j is an open Java - API for - OLAP.

- -

- Think of it as like - JDBC, - except for accessing multi-dimensional data.

- -

- olap4j is designed to be - a common API for any OLAP server, so you can write an - application on one OLAP server and easily switch it to - another. And built on that API, there will be a growing - collection of tools and components.

-
-
- - - - - -
-

Status

-

The draft olap4j - specification, version 0.5, was released on September 2nd, - 2006.

-

Participation

-

olap4j is an open specification, being developed by a - consortium of companies and open source projects.

-
- - - - - - - - - -
ProjectsCompanies
- -
- -
-

Get involved! Join the - forum, download the specification, and give us - your feedback. If you are developing an OLAP server, component or - application, let's work together to make your project olap4j-compliant.

-

Resources

- -
-
-
-
- - - + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + +
+ olap4j   + open java api for + + OLAP
+
 
+ + + + + +
+

+ olap4j is an open Java + API for + OLAP.

+ +

+ Think of it as like + JDBC, + except for accessing multi-dimensional data.

+ +

+ olap4j is designed to be + a common API for any OLAP server, so you can write an + application on one OLAP server and easily switch it to + another. And built on that API, there will be a growing + collection of tools and components.

+
+
+ + + + + +
+

Status

+

The draft olap4j + specification, version 0.5, was released on September 2nd, + 2006.

+

Participation

+

olap4j is an open specification, being developed by a + consortium of companies and open source projects.

+
+ + + + + + + + + +
ProjectsCompanies
+ +
+ +
+

Get involved! Join the + forum, download the specification, and give us + your feedback. If you are developing an OLAP server, component or + application, let's work together to make your project olap4j-compliant.

+

Resources

+ +
+
+
+
+ + + diff --git a/doc/olap4j_fs.html b/doc/olap4j_fs.html index f3e7f48..41f7953 100644 --- a/doc/olap4j_fs.html +++ b/doc/olap4j_fs.html @@ -104,15 +104,27 @@

Contents

  • Components of the API
      -
    1. Driver management
    2. +
    3. Driver management
        +
      1. The Driver class
      2. +
      3. The DriverManager class
      4. +
      5. The DataSource interface
      6. +
      7. The OlapException class
      8. +
      9. Internationalization
      10. +
      +
    4. Connections
        -
      1. OlapConnection
      2. +
      3. The OlapConnection interface
      4. Connection pooling
    5. Statements
        -
      1. OlapStatement
      2. -
      3. PreparedOlapStatement
      4. +
      5. The OlapStatement interface
      6. +
      7. The PreparedOlapStatement interface
      8. +
      9. The OlapParameterMetaData interface
      10. +
      11. The OlapResultSet interface
      12. +
      13. The ResultAxis interface
      14. +
      15. The Position interface
      16. +
      17. The ResultCell interface
    6. MDX query model
    7. @@ -120,29 +132,32 @@

      Contents

    8. Metadata
      1. Access control
      2. Metadata objects
          -
        1. Schema
        2. -
        3. Cube
        4. -
        5. Dimension
        6. -
        7. Hierarchy
        8. -
        9. Level
        10. -
        11. Measure
        12. -
        13. Member
        14. -
        15. Property
        16. +
        17. The MetadataElement interface
        18. +
        19. The Catalog interface
        20. +
        21. The Schema interface
        22. +
        23. The Cube interface
        24. +
        25. The Dimension interface
        26. +
        27. The Hierarchy interface
        28. +
        29. The Level interface
        30. +
        31. The Member interface
        32. +
        33. The Measure interface
        34. +
        35. The Property interface
      3. -
      4. Methods which return - schema rowsets
          -
        1. getDatasources
        2. -
        3. getDatabaseProperties
        4. -
        5. getLiterals
        6. -
        7. getCubes
        8. -
        9. getDimensions
        10. -
        11. getFunctions
        12. -
        13. getHierarchies
        14. -
        15. getLevels
        16. -
        17. getMeasures
        18. -
        19. getMembers
        20. -
        21. getProperties
        22. -
        23. getSets
        24. +
        25. + + The OlapDatabaseMetaData interface, and schema result sets
            +
          1. The getDatasources method
          2. +
          3. The getDatabaseProperties method
          4. +
          5. The getLiterals method
          6. +
          7. The getCubes method
          8. +
          9. The getDimensions method
          10. +
          11. The getFunctions method
          12. +
          13. The getHierarchies method
          14. +
          15. The getLevels method
          16. +
          17. The getMeasures method
          18. +
          19. The getMembers method
          20. +
          21. The getProperties method
          22. +
          23. The getSets method
        26. Other methods
      5. @@ -383,15 +398,47 @@

        2.1. Driver management

        javax.sql.DataSource -

        2.1.1. Driver

        +

        2.1.1. The Driver class

        Same functionality as JDBC.

        Here is an example of registering an olap4j driver:

        Class.forName("mondrian.olap4j.Driver");
        -

        2.1.2. DriverManager

        +

        2.1.2. The DriverManager class

        Same functionality as JDBC.

        -

        2.1.3. DataSource

        +

        2.1.3. The DataSource interface

        Same functionality as JDBC.

        +

        2.1.4 The OlapException class

        +

        OlapException +(extends + +java.sql.SQLException) describes an error which occurred while accessing an +OLAP server.

        +

        Since olap4j extends JDBC, it is natural that OlapException should extend +JDBC's + +SQLException. The implementation by an olap4j
        +driver of a JDBC method which is declared to throw a SQLException may, if the +driver chooses, throw instead an OlapException.
        +
        +OlapException provides some additional information to help an OLAP client +identify the location of the error. The context is the ResultCell +or ResultPosition object where the error occurred. The region is an +object representing the textual region in the MDX statement.

        +

        Methods:

        +
          +
        • getRegion
        • +
        • setRegion
        • +
        • getContext
        • +
        • setContext
        • +
        + +

        2.1.5. Internationalization

        +

        [move this section elsewhere]

        +

        Suppose one cube is available in English and French, and in French and +Spanish, and both are shown in same portal. Clients typically say that seeing +reports in a mixture of languages is confusing; the portal would figure out the +best common language, in this case French. Cube and Schema have +getSupportedLocales() methods for this purpose.

        2.2. Connections

        @@ -442,7 +489,7 @@

        2.2. Connections

        Package name: org.olap4j

        -

        2.2.1. OlapConnection

        +

        2.2.1. The OlapConnection interface

        OlapConnection  (extends @@ -497,12 +544,12 @@

        2.2.2. Connection pooling

        be sufficient merely to cast the objects returned from factory methods.

        2.3. Statements

        -

        2.3.1. OlapStatement

        +

        2.3.1. The OlapStatement interface

        OlapStatement  (extends java.sql.Statement) is an object used to execute a static MDX statement and return the result it produces.

        -

        2.3.2. PreparedOlapStatement

        +

        2.3.2. The PreparedOlapStatement interface

        PreparedOlapStatement (extends @@ -523,13 +570,19 @@

        2.3.2. PreparedOlapStatement

        value until they are set, and then retain their new values for each subsequent execution of this PreparedOlapStatement.

        [How to find out what cube a prepared statement relates to?]

        -

        2.3.3. OlapParameterMetaData

        +

        2.3.3. The OlapParameterMetaData interface

        OlapParameterMetaData (extends java.sql.ParameterMetaData) describes parameters of a PreparedOlapStatement.

        -

        2.3.4. OlapResultSet

        +

        Additional methods:

        +
          +
        • getName()
        • +
        • getOlapType(int param)
        • +
        + +

        2.3.4. The OlapResultSet interface

        OlapResultSet (extends java.sql.ResultSet) is the result of executing an OlapStatement @@ -545,14 +598,45 @@

        2.3.4. OlapResultSet

      6. getType()
      7. getWarnings()
      8. -

        Additional methods to retrieve the axes of the multidimensional result.

        -

        2.3.5. ResultAxis

        +

        Additional methods to retrieve the axes of the multidimensional result:

        +
          +
        • List<ResultAxis> getAxes()
        • +
        • ResultSet getCell(List<Integer> coordinates)
        • +
        + +

        2.3.5. The ResultAxis interface

        +

        A ResultAxis is +a

        [tbd]

        [access positions by index (i.e. a list) and by scrolling (i.e. an iterator)]

        -

        2.3.6. Position

        -

        [tbd]

        -

        2.3.7. ResultCell

        -

        [tbd]

        +

        2.3.6. The ResultPosition interface

        +

        ResultPosition +is a position on a +ResultAxis.

        +

        Methods:

        +
          +
        • List<Member> getMembers()
        • +
        • int getOrdinal()
        • +
        + +

        2.3.7. The ResultCell interface

        +

        A ResultCell is +a cell returned from an +OlapResultSet.

        +

        Methods:

        +
          +
        • getResultSet()
        • +
        • getOrdinal()
        • +
        • getCoordinateList()
        • +
        • getPropertyValue(Property)
        • +
        • isError()
        • +
        • isNull()
        • +
        • isEmpty()
        • +
        • getDoubleValue()
        • +
        • getErrorText()
        • +
        • getValue()
        • +
        • getFormattedValue()
        • +

        2.4. MDX query model

        @@ -748,7 +832,8 @@

        2.6. Metadata

        org.olap4j.metadata.Cube.
      9. A schema result set is a JDBC ResultSet which returns a record for each instance of a particular metadata class. There is a method in - OlapDatabaseMetaData to create a schema rowset for each metadata class. Some + the + OlapDatabaseMetaData interface to create a schema result set for each metadata class. Some of these methods accept parameters to filter the rows returned. For example, OlapDatabaseMetaData.getCubes(<schemaName>, <cubeName>).
      10. @@ -768,9 +853,29 @@

        2.6.1. Access control

        2.6.2. Metadata objects

        -

        [Diagram of object model, showing relationships between Schema, Cube, -Dimension, etc.]

        -
        2.6.2.1. MetadataElement
        +

        [Diagram of object model, showing relationships. Catalog contains Schema; +Schema contains Cube and shared Dimension; Cube contains Dimension, Measure and +Set; Measure is a Member; Dimension contains Hierarchy; Hierarchy contains +Level; Level contains Member and Property.]

        +

        Most metadata objects extend the +MetadataElement interface, which gives them name and +uniqueName attributes, and localized caption and +description.

        +

        When the API returns a list of metadata elements whose names must be unique +(for example, the list of dimensions in a cube), the return type is the +NamedList +extension to + +java.util.List.

        +

        Providers are at liberty to implement metadata objects using a cache, and +therefore over the course of time, different java objects may represent the same +underlying metadata object. Always use + +equals(), not the = operator, when comparing metadata objects, +and do not use + +IdentityHashMap.

        +
        2.6.2.1. The MetadataElement interfacee

        MetadataElement is the base class for Cube, Dimension, Hierarchy, Level, Member, Property; provides name and unique-name properties (not localized), and localized caption and @@ -781,19 +886,31 @@

        2.6.2.1. MetadataElement
      11. String getCaption(Locale locale)
      12. String getDescription(Locale locale)
      13. -
        2.6.2.2. Schema
        +
        2.6.2.2. The Catalog interface
        +

        Catalog ...

        +
          +
        • String getName()
        • +
        • NamedList<Schema> getSchemas()
        • +
        +
        2.6.2.3. The Schema interface

        Schema ...

        • String getName()
        • +
        • List<Dimension> getSharedDimensions()
        • +
        • List<Cube> getCubes()
        • +
        • getSupportedLocales() (see + Internationalization)
        -
        2.6.2.3. Cube
        +
        2.6.2.4. The Cube interface

        Cube ...

        • List<Dimension> getDimensions()
        • Schema getSchema()
        • String getName()
        • +
        • getSupportedLocales() (see + Internationalization)
        -
        2.6.2.4. Dimension
        +
        2.6.2.5. The Dimension interface

        Dimension ...

          @@ -802,7 +919,7 @@
          2.6.2.4. Dimension
        • List<Member> getRootMembers()
        • Dimension.Type getDimensionType()
        -
        2.6.2.5. Hierarchy
        +
        2.6.2.6. The Hierarchy interface

        Hierarchy ...

          @@ -811,7 +928,7 @@
          2.6.2.5. Hierarchy
        • List<Level> getLevels()
        • boolean hasAll()
        -
        2.6.2.6. Level
        +
        2.6.2.7. The Level interface

        Level ...

        • int getDepth()
        • @@ -819,12 +936,7 @@
          2.6.2.6. Level
        • Level.Type getLevelType()
        • List<Property> getProperties()
        -
        2.6.2.6. Measure
        -

        Meaure ...

        -
          -
        • extends Member
        • -
        -
        2.6.2.7. Member
        +
        2.6.2.8. The Member interface

        Member ...

        • String getName()
        • @@ -845,7 +957,12 @@
          2.6.2.7. Member
        • boolean isHidden()
        • Member getDataMember()
        -
        2.6.2.8. Property
        +
        2.6.2.9. The Measure interface
        +

        Measure ...

        +
          +
        • extends Member
        • +
        +
        2.6.2.10. The Property interface

        Property ...

          @@ -859,8 +976,14 @@
          2.6.2.8. Property
          }
        • enum StandardCellProperty { BACK_COLOR, CELL_EVALUATION_LIST, ... }
        -

        2.6.3. Methods which return schema rowsets

        -

        Schema rowsets are specified as in [XML for Analysis +

        2.6.3. +The OlapDatabaseMetaData +interface, and methods which return schema rowsets

        +

        +OlapDatabaseMetaData (extends + +java.sql.DatabaseMetaData) contains methods which return schema result sets.

        +

        Schema result sets are specified as in [XML for Analysis specification]. Here is a table of the XML/A methods and the corresponding olap4j method.

        @@ -2873,28 +2996,6 @@

        2.6.4. Other methods

        -

        OlapDatabaseMetaData extends

        -

        Classes:

        -
          -
        • Schema
        • -
        • Cube
        • -
        • Dimension
        • -
        • Hierarchy
        • -
        • Level
        • -
        • Member
        • -
        • Measure
        • -
        • Property
        • -
        • Set
        • -
        • Role
        • -
        - -

        Object model:

        -
          -
        • Schema contains Cubes
        • -
        • Cube contains Dimensions, Hierarchies, Measures, Sets
        • -
        • Hierarchy contains Levels
        • -
        -

        2.7. Transform

        A transform is an operation which maps a query model to a new query model. It @@ -3137,6 +3238,10 @@

        A.3. Writethrough/Writeback

        Specify how clients can write cell values back to the database. Useful for budgeting applications and 'what if?' analysis.

        (PALO, 2006/10/14)

        +

        A.4. Drillthrough

        +

        Mondrian exposes the SQL statement used to form the result set, and exposes +the mapping from columns to members/levels, whereas olap4j currently only +returns a result set.

        Appendix B. Feedback

        @@ -3164,27 +3269,10 @@

        D.1. To be specified

        [2006/10/20#1. Specification should include compliance levels, like the SQL specification does. In particular, we will allow providers to comply with a limited subset of MDX.]

        -

        [2006/10/20#2. Metadata objects need to be compared using equals, not -identity. (Michael had war-stories of an OLAP API where members from a result -set were not equal to members obtained by browsing the schema.)]

        [2006/10/20#3. Need to allow clients to access the members on a ResultAxis via a list (for convenience) and via an iterator. Iterators need to be restartable, but not bidirectional. Need to know the size of the axes, even if using the iterator interface.]

        -

        [2006/10/20#4. Cells - random access (not the 'etchasketch' model used by -JOLAP). Access via ordinal, not via a coordinates. Since access to cells is -random access, it makes it hard for a low-memory provider to access cells -without many round-trips. We agreed that the provider should try to recognize -the pattern. John drew the analogy of a modern file system, implementing a -serial access interface (streams) on top of random-access primitives. Michael -suggested that we implement a method to get a cell range - the hypercube of -cells between coordinates minX and maxX, and minY and maxY - but we deferred -that to a future release.]

        -

        [2006/10/20#5. Available locales in cubes and schemas. Use case: suppose one -cube is available in English and French, and in French and Spanish, and both are -shown in same portal. Clients typically say that seeing reports in a mixture of -languages is confusing; the portal would figure out the best common language, in -this case French. Add methods to Schema and Cube.]

        [2006/10/20#6. We discussed session support. It is necessary for write-back. JDBC's 'stateful session' is difficult to implement over a stateless protocol like HTTP. Michael suggested adding 'session name' as a parameter to 'execute' @@ -3199,23 +3287,34 @@

        D.1. To be specified

        is to support an object model (hence easy programming model) without increasing memory. No specific change to the specification, but decided to add memory efficiency as a design goal.]

        -

        [2006/10/20#8. Need to make shared dimensions accessible from schema.]

        -

        [2006/10/20#9. Need to support drill-through. Method which returns a result -set. (Mondrian exposes the SQL statement used to form the result set, and -exposes the mapping from columns to members/levels, but we will not include this -in the olap4j interface.)]

        -

        [2006/10/20#10. John proposed adding OlapException. These would extend -SQLException, and have a 'Object getContext()' method which would return the -context (member or cell) where the error occurred. New methods would have -'throws OlapException', and existing methods (e.g. Statement.close()) can (at -provider's choice) throw either OlapException or SQLException.]

        - +

        [Is an OlapResultSet still accessible when its OlapStatement is closed?]

        D.2. Design notes

        JDK. We are targeting JDK 1.5, and running retroweaver for backward compatibility for JDK 1.4. See forum thread: olap4j, JDK 1.5 and generics.

        +

        Result sets, random access, and memory usage

        +

        Should result sets return their axes as cursors or collections? Cursors +require less memory, but collections provide an easier programming model.

        +

        Also on the subject of memory, how to represent the metadata? Schema result +sets require less memory, are more flexible, and have better defined semantics +in the presence of transactions and offline working; but an object model (Cube, +Dimension, Level) provides an easier programming model.

        +

        Accessing cells

        +

        It would be possible to access cells in a result set (a) by ordinal; (b) by +coordinates; (c) by the 'etchasketch' model determined by the position of the +iterator along each axis, as used by JOLAP. We decided to support (a) and (b) +but not (c). There are methods on ResultSet to convert from ordinal to +coordinates and vice versa.

        +

        If there is a huge number of cells, the client has limited memory, and +bandwidth to the server is limited, random access to cells is costly. Michael +suggested that we add a method List<ResultCell> getCells(int startOrdinal, int +endOrdinal), which matches XML/A behavior, but we declined to add it to the spec +for now. John drew the analogy of a modern file system, implementing a serial +access interface (streams) on top of random-access primitives. For now, we +support only random access, but suggest that the provider looks for patterns of +access.

        Appendix E. References

        diff --git a/src/org/olap4j/Axis.java b/src/org/olap4j/Axis.java new file mode 100644 index 0000000..95a4ebe --- /dev/null +++ b/src/org/olap4j/Axis.java @@ -0,0 +1,48 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +/** + * Enumeration of axis types. + * + *

        Typically used values are ROWS, COLUMNS, and SLICER. + * + * @author jhyde + * @version $Id: $ + * @since Oct 23, 2006 + */ +public enum Axis { + SLICER, + COLUMNS, + ROWS, + PAGES, + CHAPTERS, + SECTIONS; + + /** + * Returns the ordinal which is to be used for retrieving this axis from + * the {@link org.olap4j.OlapResultSet#getAxes()}, or retrieving its + * coordinate from {@link ResultCell#getCoordinateList()}. + * + *

        The axis ordinal is one less than the {@link #ordinal} value which + * every enum value possesses. Hence, {@link #SLICER} is -1 + * (because it is not treated the same as the other axes), {@link #COLUMNS} + * is 0, {@link #ROWS} is 1, and so forth. + * + * @return Axis ordinal + */ + public int axisOrdinal() { + return axisOrdinal; + } + + private final int axisOrdinal = ordinal() - 1; +} + +// End Axis.java diff --git a/src/org/olap4j/OlapDatabaseMetaData.java b/src/org/olap4j/OlapDatabaseMetaData.java index 102afa7..d7c7340 100644 --- a/src/org/olap4j/OlapDatabaseMetaData.java +++ b/src/org/olap4j/OlapDatabaseMetaData.java @@ -9,6 +9,8 @@ */ package org.olap4j; +import org.olap4j.metadata.Database; + import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; @@ -28,6 +30,12 @@ * @since Oct 12, 2006 */ public interface OlapDatabaseMetaData extends DatabaseMetaData { + /** + * Returns the Database, which is the root of the hierarchy + * of metadata objects. + * @return the Database + */ + Database getDatabase(); /** * Retrieves a list of descriptions of an Action. diff --git a/src/org/olap4j/OlapException.java b/src/org/olap4j/OlapException.java new file mode 100644 index 0000000..5112fa0 --- /dev/null +++ b/src/org/olap4j/OlapException.java @@ -0,0 +1,157 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import java.sql.SQLException; + +/** + *

        An exception describing an error accessing an OLAP database.

        + * + *

        Since olap4j extends JDBC, it is natural that OlapException + * should extend JDBC's {@link SQLException}. The implementation by an olap4j + * driver of a JDBC method which is declared to throw a SQLException may, if the + * driver chooses, throw instead an OlapException.

        + * + *

        OlapException provides some additional information to help an OLAP client + * identify the location of the error. This information is + * + * @author jhyde + * @version $Id: $ + * @since Oct 23, 2006 + */ +public class OlapException extends SQLException { + private Region region; + private Object context; + + /** + * Constructs a fully-specified SQLException object. + * + * @param reason a description of the exception + * @param sqlState an XOPEN or SQL 99 code identifying the exception + * @param vendorCode a database vendor-specific exception code + */ + public OlapException(String reason, String sqlState, int vendorCode) { + super(reason, sqlState, vendorCode); + } + + /** + * Constructs an SQLException object with the given reason and + * SQLState; the vendorCode field defaults to 0. + * + * @param reason a description of the exception + * @param sqlState an XOPEN or SQL 99 code identifying the exception + */ + public OlapException(String reason, String sqlState) { + super(reason, sqlState); + } + + /** + * Constructs an SQLException object with a reason; + * the sqlState field defaults to null, and + * the vendorCode field defaults to 0. + * + * @param reason a description of the exception + */ + public OlapException(String reason) { + super(reason); + } + + /** + * Constructs an SQLException object; + * the reason field defaults to null, + * the sqlState field defaults to null, and + * the vendorCode field defaults to 0. + */ + public OlapException() { + super(); + } + + /** + * Sets the textual region where the exception occurred. + */ + public void setRegion(Region region) { + this.region = region; + } + + /** + * Returns the textual region where the exception occurred, or null if no + * region can be identified. + */ + public Region getRegion() { + return region; + } + + /** + * Sets the context where the exception occurred. + * + * @param context Context where the exception occurred + * @throws IllegalArgumentException If context is not a {@link ResultCell} + * or a {@link ResultPosition} + */ + public void setContext(Object context) { + if (!(context instanceof ResultCell) && + !(context instanceof ResultPosition)) { + throw new IllegalArgumentException( + "expected ResultCell or ResultPosition"); + } + this.context = context; + } + + /** + * Returns the context where the exception occurred. + * Typically a {@link ResultCell} or a {@link ResultPosition}, or null. + */ + public Object getContext() { + return context; + } + + /** + * Description of the position of a syntax or validation error in the source + * MDX string. + * + *

        Row and column positions are 1-based and inclusive. For example, + * in + * + *

        + * SELECT { [Measures].MEMBERS } ON COLUMNS, { } ON ROWS FROM [Sales] + *
        + * + * the SELECT keyword occupies positions (1, 1) through (1, 6), + * and would have a Region(startLine=1, startColumn=1, endColumn=1, + * endLine=6). + */ + public static final class Region { + public final int startLine; + public final int startColumn; + public final int endLine; + public final int endColumn; + protected Region( + int startLine, + int startColumn, + int endLine, + int endColumn) { + this.startLine = startLine; + this.startColumn = startColumn; + this.endColumn = endLine; + this.endLine = endColumn; + } + + public String toString() { + if (startLine == endColumn && startColumn == endLine) { + return "line " + startLine + ", column " + startColumn; + } else { + return "line " + startLine + ", column " + startColumn + + " through line " + endLine + ", column " + endColumn; + } + } + } +} + +// End OlapException.java diff --git a/src/org/olap4j/OlapResultSet.java b/src/org/olap4j/OlapResultSet.java index 6a22d48..8effae4 100644 --- a/src/org/olap4j/OlapResultSet.java +++ b/src/org/olap4j/OlapResultSet.java @@ -9,15 +9,50 @@ */ package org.olap4j; +import org.olap4j.metadata.Property; +import org.olap4j.metadata.Cube; + import java.util.List; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; /** * Result of executing an OLAP Statement. * - *

        It consists of a set of (typically two) axes, each populated with a - * sequence of members, and a collection of cells at the intersection of these - * axes. + *

        An consists of a set of (typically two) axes, + * each populated with a sequence of members, and a collection of cells at the + * intersection of these axes. + * + *

        Cell ordinals and coordinates

        + * + *

        There are two ways to identify a particular cell: ordinal and coordinates. + * Suppose that there are p axes, and each axis k + * (k between 0 and p - 1) has + * Uk positions. + * There are U + * = U0 * ... * Up - 1 cells in total. + * Then:

          + *
        • A cell's ordinal is an integer between 0 and + * U - 1.
        • + *
        • A cell's coordinates are a list of p integers, + * indicating the cell's position on each axis. + * Each integer is between 0 and Up-1.
        • + *
        + * + *

        The ordinal number of a cell whose tuple ordinals are + * (S0, S1, ... Sp-1) is + *

        + * + * Σi=0p-1 Si . Ei + * + * where + * E0 = 1 + * and + * + * Ei = Πi=0p-1 Uk + * + *

        * * @author jhyde * @version $Id$ @@ -25,7 +60,17 @@ */ public interface OlapResultSet extends ResultSet { /** - * Retrieves a list of axes containing the result. + * Retrieves the description of this OlapResultSet's axes + * and cells. + * + * @return the description of this OlapResultSet's axes + * and cells + * @exception OlapException if a database access error occurs + */ + OlapResultSetMetaData getMetaData() throws OlapException; + + /** + * Retrieves a list of ResultAxis objects containing the result. * *

        The list contains axes according to their ordinal: 0 is the columns * axis, 1 the rows axis, and so forth. @@ -33,12 +78,43 @@ public interface OlapResultSet extends ResultSet { List getAxes(); /** - * Returns the cell at a given set of coordinates. + * Returns the ResultCell at a given set of coordinates. * - * @param coordinates 0-based coordinates of the cell + * @param coordinates List of 0-based coordinates of the cell * @return Cell */ - ResultCell getCell(int[] coordinates); + ResultCell getCell(List coordinates); + + /** + * Returns the ResultCell at a ordinal. + * + *

        Equivalent to + *

        + * getCell(ordinalToCoordinates(ordinal) + *
        + * + * @param ordinal 0-based ordinal of the cell + * @return Cell + */ + ResultCell getCell(int ordinal); + + /** + * Converts a cell ordinal to a list of cell coordinates. + * + * @param ordinal Cell ordinal + * @return Cell coordinates + */ + List ordinalToCoordinates(int ordinal); + + /** + * Converts a list of cell coordinates to a cell ordinal. + * + *

        The mapping + * @param coordinates Cell coordinates + * @return Cell ordinal + */ + int coordinatesToOrdinal(List coordinates); + } // End OlapResultSet.java diff --git a/src/org/olap4j/OlapResultSetAxisMetaData.java b/src/org/olap4j/OlapResultSetAxisMetaData.java new file mode 100644 index 0000000..4ee44bd --- /dev/null +++ b/src/org/olap4j/OlapResultSetAxisMetaData.java @@ -0,0 +1,73 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import org.olap4j.metadata.Hierarchy; +import org.olap4j.metadata.Property; + +import java.util.List; + +/** + * Description of structure of a particular axis of an {@link OlapResultSet}. + * + *

        For example, in the MDX statement + *

        + * + * SELECT
        + * {[Measures].Members} ON COLUMNS,
        + * CrossJoin([Store].Members, [Gender].Children)
        + * DIMENSION PROPERTIES
        + * MEMBER_ORDINAL,
        + * MEMBER_UNIQUE_NAME,
        + * DISPLAY_INFO ON ROWS
        + * FROM [Sales] + *
        + *
        + * + * the ROWS axis is described by the following metadata: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        AttributeValue
        hierarchies{[Store], [Gender]}
        properties{MEMBER_ORDINAL, MEMBER_UNIQUE_NAME, DISPLAY_INFO}
        + * + * @author jhyde + * @version $Id: $ + * @since Oct 23, 2006 + */ +public interface OlapResultSetAxisMetaData { + /** + * Returns the definition of the axis. + * ({@link Axis#SLICER}, {@link Axis#ROWS}, and so forth.) + */ + Axis getAxis(); + + /** + * Returns the hierarchies which are mapped onto this axis. + */ + List getHierarchies(); + + /** + * Returns the member properties which are returned on this axis. + */ + List getProperties(); +} + +// End OlapResultSetAxisMetaData.java diff --git a/src/org/olap4j/OlapResultSetMetaData.java b/src/org/olap4j/OlapResultSetMetaData.java new file mode 100644 index 0000000..d6d32eb --- /dev/null +++ b/src/org/olap4j/OlapResultSetMetaData.java @@ -0,0 +1,42 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j; + +import org.olap4j.metadata.Property; +import org.olap4j.metadata.Cube; + +import java.sql.ResultSetMetaData; +import java.util.List; + +/** + * OlapResultSetMetaData ... + * + * @author jhyde + * @version $Id: $ + * @since Oct 23, 2006 + */ +public interface OlapResultSetMetaData extends ResultSetMetaData { + /** + * Returns a list of properties which each ResultCell may have. + */ + List getCellProperties(); + + /** + * Returns the Cube which was referenced in this statement. + */ + Cube getCube(); + + /** + * Returns a list of metadata describing each result axis. + */ + List getAxesMetaData(); +} + +// End OlapResultSetMetaData.java diff --git a/src/org/olap4j/ResultAxis.java b/src/org/olap4j/ResultAxis.java index 2436fd1..ee0cf5d 100644 --- a/src/org/olap4j/ResultAxis.java +++ b/src/org/olap4j/ResultAxis.java @@ -9,10 +9,15 @@ */ package org.olap4j; +import org.olap4j.metadata.Hierarchy; +import org.olap4j.metadata.NamedList; + import java.util.List; import java.util.Iterator; import java.util.ListIterator; +import mondrian.olap.Property; + /** * ResultAxis ... * @@ -21,25 +26,57 @@ * @since Aug 22, 2006 */ public interface ResultAxis { - int SLICER = 0; - int COLUMNS = 1; - int ROWS = 2; + /** + * Returns the ordinal of this ResultAxis. + * + *

        0 = ROWS, 1 = COLUMNS, and so forth, as described by the + * {@link Axis#axisOrdinal()} method of the {@link Axis} enumeration.

        + */ + int getOrdinal(); + + /** + * Returns the {@link OlapResultSet} which this ResultAxis + * belongs to. + */ + OlapResultSet getResultSet(); /** - * Returns a list of positions on this axis. - * @return + * Returns a description of the type (e.g. {@link Axis#ROWS}) of this + * axis, and the hierarchies and properties which will be found on it. + * + *

        The result is identical to evaluating + *

        + * + * getResultSet().getMetaData().getAxesMetaData(getOrdinal()) + * + *
        + */ + OlapResultSetAxisMetaData getAxisMetaData(); + + /** + * Returns a list of ResultPosition objects on this ResultAxis. + * + * @return List of positions on this axis (never null) */ List getPositions(); /** - * Opens an iterator + * Returns the number of positions on this ResultAxis. + * + *

        This method can be called at any time. In particular, it is not + * necessary to complete an iteration through all positions before calling + * this method.

        + * + *

        The number of positions on an axis is important when computing the + * ordinal of a cell.

        + */ + int getPositionCount(); + + /** + * Opens an iterator on */ ListIterator iterate(); - enum Direction { - ForwardOnly, - Restartable, - } } // End ResultAxis.java diff --git a/src/org/olap4j/ResultCell.java b/src/org/olap4j/ResultCell.java index dcedcb1..8db8687 100644 --- a/src/org/olap4j/ResultCell.java +++ b/src/org/olap4j/ResultCell.java @@ -9,15 +9,115 @@ */ package org.olap4j; +import org.olap4j.metadata.Property; + +import java.util.List; +import java.sql.ResultSet; + /** - * ResultCell ... + * Cell returned from a {@link OlapResultSet}. * * @author jhyde * @version $Id$ * @since Aug 22, 2006 */ public interface ResultCell { + /** + * Returns the {@link OlapResultSet} that this ResultCell belongs to. + * + * @return OlapResultSet, never null + */ + OlapResultSet getResultSet(); + + /** + * Returns the ordinal of this ResultCell. + * + *

        The formula is the sequence, zero-based, which the cell would be + * visited in a raster-scan through all of the cells of this + * {@link OlapResultSet}. The ordinal of the first cell is zero, and the + * ordinal of the last cell is the product of the lengths of the axes, minus + * 1. For example, if a result has 10 columns and 20 + * rows, then:

          + *
        • (row 0, column 0) has ordinal 0,
        • + *
        • (row 0, column 1) has ordinal 1,
        • + *
        • (row 1, column 0) has ordinal 10,
        • + *
        • (row 19, column 9) has ordinal 199.
        • + *
        + */ + int getOrdinal(); + + /** + * Returns the coordinates of this ResultCell in its {@link ResultAxis}. + * + *

        This method is provided for convenience. It is equivalent to the + * following code: + *

        + * + * getResult().ordinalToCoordinateList(getOrdinal()) + * + *
        + */ + List getCoordinateList(); + + /** + * Returns the value of a given property for this ResultCell. + * + * @see org.olap4j.OlapResultSet#getMetaData() + * @see Todo + */ + Object getPropertyValue(Property property); + + /** + * Returns whether this cell is empty. + * + * @return Whether this cell is empty. + */ + boolean isEmpty(); + + /** + * Returns whether an error occurred while evaluating this cell. + * + * @return Whether an error occurred while evaluating this cell. + */ + boolean isError(); + + /** + * Returns whether the value of this cell is NULL. + * + * @return Whether the value of this cell is NULL. + */ + boolean isNull(); + + /** + * Returns the value of this cell as a double value. + */ + double getDoubleValue() throws OlapException; + + /** + * @see Todo + */ + String getErrorText(); + + /** + * @see Todo + * returns a OlapException if the cell is an error + */ + Object getValue(); + + /** + * Returns the value of this ResultCell, formatted according to the + * FORMAT_STRING property and using the numeric formatting tokens the + * current locale. + * + * @return Formatted value of this ResultCell + */ String getFormattedValue(); + + /** + * Drills through from this cell to the underlying fact table data, + * and returns a {@link java.sql.ResultSet} of the results. + */ + ResultSet drillThrough(); } // End ResultCell.java diff --git a/src/org/olap4j/ResultPosition.java b/src/org/olap4j/ResultPosition.java index 8a482aa..6e78c38 100644 --- a/src/org/olap4j/ResultPosition.java +++ b/src/org/olap4j/ResultPosition.java @@ -14,18 +14,30 @@ import java.util.List; /** - * ResultPosition ... + * Position on one of the {@link ResultAxis} objects in a {@link OlapResultSet}. * * @author jhyde * @version $Id$ * @since Aug 22, 2006 */ public interface ResultPosition { + /** + * Returns the list of Member objects at this position. + * + *

        Recall that the {@link OlapResultSetAxisMetaData#getHierarchies()} + * method describes the hierarchies which occur on an axis. The positions on + * that axis must conform. Suppose that the ROWS axis of a given statement + * returns {[Gender], [Store]}. Then every ResultPosition on + * that axis will have two members: the first a member of the [Gender] + * dimension, the second a member of the [Store] dimension.

        + * + * @return A list of Member objects at this ResultPosition. + */ public List getMembers(); /** - * Returns the ordinal of this position on its {@link ResultAxis}. - * Zero-based. + * Returns the zero-based ordinal of this ResultPosition on its + * {@link ResultAxis}. */ int getOrdinal(); } diff --git a/src/org/olap4j/metadata/Catalog.java b/src/org/olap4j/metadata/Catalog.java new file mode 100644 index 0000000..20547f0 --- /dev/null +++ b/src/org/olap4j/metadata/Catalog.java @@ -0,0 +1,32 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.metadata; + +import org.olap4j.OlapException; + +/** + * Catalog ... + * + * @author jhyde + * @version $Id: $ + * @since Oct 24, 2006 + */ +public interface Catalog { + /** + * Returns a list of {@link Schema} objects which belong to + * this Catalog. + * + * @see org.olap4j.OlapDatabaseMetaData#getSchemas + * @return List of Schema in this Catalog + */ + NamedList getSchemas() throws OlapException; +} + +// End Catalog.java diff --git a/src/org/olap4j/metadata/Cube.java b/src/org/olap4j/metadata/Cube.java index 04a430b..6d808f7 100644 --- a/src/org/olap4j/metadata/Cube.java +++ b/src/org/olap4j/metadata/Cube.java @@ -9,6 +9,10 @@ */ package org.olap4j.metadata; +import java.util.List; +import java.util.Locale; +import java.util.Collection; + /** * Cube ... * @@ -17,8 +21,47 @@ * @since Aug 22, 2006 */ public interface Cube extends MetadataElement { + /** + * Returns the {@link Schema} this Cube belongs to. + */ Schema getSchema(); + + /** + * Returns a list of {@link Dimension} objects in this Cube. + * + * @see org.olap4j.OlapDatabaseMetaData#getDimensions() + */ NamedList getDimensions(); + + /** + * Returns a list of {@link Measure} objects in this Cube. + * + * @see org.olap4j.OlapDatabaseMetaData#getMeasures() + */ + List getMeasures(); + + /** + * Returns a collection of {@link java.util.Locale} objects for which this + * Cube has been localized. + * + *

        Consider the following use case. Suppose one cube is available in + * English and French, and in French and Spanish, and both are shown in same + * portal. Clients typically say that seeing reports in a mixture of + * languages is confusing; the portal would figure out the best common + * language, in this case French. This method allows the client to choose + * the most appropriate locale.

        + * + *

        The list is advisory: a client is free to choose another locale, + * in which case, the server will probably revert to the base locale for + * locale-specific behavior such as captions and formatting.

        + * + * @see Schema#getSupportedLocales + * + * @return List of locales for which this Cube has been + * localized + */ + Collection getSupportedLocales(); + } // End Cube.java diff --git a/src/org/olap4j/metadata/Database.java b/src/org/olap4j/metadata/Database.java new file mode 100644 index 0000000..e67a120 --- /dev/null +++ b/src/org/olap4j/metadata/Database.java @@ -0,0 +1,30 @@ +/* +// $Id: $ +// This software is subject to the terms of the Common Public License +// Agreement, available at the following URL: +// http://www.opensource.org/licenses/cpl.html. +// Copyright (C) 2006-2006 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.metadata; + +/** + * Database ... + * + * @author jhyde + * @version $Id: $ + * @since Oct 24, 2006 + */ +public interface Database { + /** + * Retrieves a list of {@link Catalog} objects which + * belong to this Database. + * + * @see org.olap4j.OlapDatabaseMetaData#getDatabase + * @return List of Catalogs in this Database + */ + NamedList getCatalogs(); +} + +// End Database.java diff --git a/src/org/olap4j/metadata/Dimension.java b/src/org/olap4j/metadata/Dimension.java index 3d341b0..b7d3d17 100644 --- a/src/org/olap4j/metadata/Dimension.java +++ b/src/org/olap4j/metadata/Dimension.java @@ -9,6 +9,8 @@ */ package org.olap4j.metadata; +import org.olap4j.OlapException; + /** * Dimension ... * @@ -23,8 +25,10 @@ public interface Dimension extends MetadataElement { * *

        Many dimensions have only one Hierarchy, whose name is the same as the * Dimension. + * + * @see org.olap4j.OlapDatabaseMetaData#getHierarchies */ - NamedList getHierarchies(); + NamedList getHierarchies() throws OlapException; /** * Returns the root member or members of this Dimension. @@ -32,12 +36,12 @@ public interface Dimension extends MetadataElement { *

        If the dimension has an 'all' member, then this will be the sole * root member. */ - NamedList getRootMembers(); + NamedList getRootMembers() throws OlapException; /** * Returns the type of this Dimension. */ - Dimension.Type getDimensionType(); + Dimension.Type getDimensionType() throws OlapException; /** * Enumeration of the types of a Dimension. diff --git a/src/org/olap4j/metadata/Hierarchy.java b/src/org/olap4j/metadata/Hierarchy.java index 3008099..873065f 100644 --- a/src/org/olap4j/metadata/Hierarchy.java +++ b/src/org/olap4j/metadata/Hierarchy.java @@ -29,6 +29,8 @@ public interface Hierarchy extends MetadataElement { /** * Returns a list of the {@link Level}s in this Hierarchy. + * + * @see org.olap4j.OlapDatabaseMetaData#getLevels */ NamedList getLevels(); diff --git a/src/org/olap4j/metadata/Level.java b/src/org/olap4j/metadata/Level.java index bf3c0e7..c86172c 100644 --- a/src/org/olap4j/metadata/Level.java +++ b/src/org/olap4j/metadata/Level.java @@ -10,7 +10,7 @@ package org.olap4j.metadata; /** - * Group of {@link Member}s in a {@link Hierarchy}, + * Group of {@link Member} objects in a {@link Hierarchy}, * all with the same attributes and at the same depth in the hierarchy. * * @author jhyde @@ -48,6 +48,8 @@ public interface Level extends MetadataElement { /** * Returns a list of definitions for the properties available to members * of this Level. + * + * @see org.olap4j.OlapDatabaseMetaData#getProperties() */ NamedList getProperties(); diff --git a/src/org/olap4j/metadata/Member.java b/src/org/olap4j/metadata/Member.java index f3624ee..69a8d0f 100644 --- a/src/org/olap4j/metadata/Member.java +++ b/src/org/olap4j/metadata/Member.java @@ -16,7 +16,7 @@ import java.util.List; /** - * Member is a data value in a in an OLAP Dimension. + * Member is a data value in an OLAP Dimension. * * @author jhyde * @version $Id$ @@ -28,6 +28,8 @@ public interface Member extends MetadataElement { * *

        If access-control is in place, the list does not contain inaccessible * children. + * + * @see org.olap4j.OlapDatabaseMetaData#getMembers() */ NamedList getChildMembers(); @@ -138,7 +140,7 @@ private Type(int ordinal) { * *

        Every member has certain system properties such as "name" and * "caption" (the full list is described in the {@link Property} - * ({@link org.olap4j.Todo} move Property) + * ({@link org.olap4j.Todo todo: move Property}) * enumeration), as well as extra properties defined for its Level * (see {@link Level#getProperties()} * diff --git a/src/org/olap4j/metadata/Schema.java b/src/org/olap4j/metadata/Schema.java index af0075d..241e958 100644 --- a/src/org/olap4j/metadata/Schema.java +++ b/src/org/olap4j/metadata/Schema.java @@ -9,6 +9,13 @@ */ package org.olap4j.metadata; +import mondrian.xmla.DataSourcesConfig; + +import java.util.Locale; +import java.util.Collection; + +import org.olap4j.OlapException; + /** * Schema ... * @@ -17,7 +24,48 @@ * @since Oct 13, 2006 */ public interface Schema { - NamedList getCubes(); + /** + * Returns the {@link Catalog} this Schema belongs to. + */ + Catalog getCatalog(); + + /** + * Returns a list of cubes in this Schema. + * + * @see org.olap4j.OlapDatabaseMetaData#getCubes + * @return List of cubes in this Schema + */ + NamedList getCubes() throws OlapException; + + /** + * Returns a list of shared {@link Dimension} objects in this + * Schema. + * + * @see org.olap4j.OlapDatabaseMetaData#getDimensions() + */ + NamedList getSharedDimensions() throws OlapException; + + /** + * Returns a collection of {@link java.util.Locale} objects for which this + * Schema has been localized. + * + *

        Consider the following use case. Suppose one cube is available in + * English and French, and in French and Spanish, and both are shown in same + * portal. Clients typically say that seeing reports in a mixture of + * languages is confusing; the portal would figure out the best common + * language, in this case French. This method allows the client to choose + * the most appropriate locale.

        + * + *

        The list is advisory: a client is free to choose another locale, + * in which case, the server will probably revert to the base locale for + * locale-specific behavior such as captions and formatting. + * + * @see Cube#getSupportedLocales + * + * @return List of locales for which this Schema has been + * localized + */ + Collection getSupportedLocales() throws OlapException; } // End Schema.java diff --git a/src/org/olap4j/sample/SimpleQuerySample.java b/src/org/olap4j/sample/SimpleQuerySample.java index 3e432a9..547c086 100644 --- a/src/org/olap4j/sample/SimpleQuerySample.java +++ b/src/org/olap4j/sample/SimpleQuerySample.java @@ -1,5 +1,5 @@ /* -// $Id$ +// $Id: SimpleQuerySample.java 10 2006-10-16 05:37:08Z jhyde $ // This software is subject to the terms of the Common Public License // Agreement, available at the following URL: // http://www.opensource.org/licenses/cpl.html. @@ -18,6 +18,7 @@ import java.sql.*; import java.util.List; +import java.util.ArrayList; import mondrian.olap.Query; @@ -25,7 +26,7 @@ * Collection of olap4j samples illustrating connections and statements. * * @author jhyde - * @version $Id$ + * @version $Id: SimpleQuerySample.java 10 2006-10-16 05:37:08Z jhyde $ * @since Aug 22, 2006 */ public class SimpleQuerySample { @@ -63,17 +64,18 @@ void simpleStatement() throws SQLException, ClassNotFoundException { // Print headings. System.out.print("\t"); - ResultAxis columnsAxis = resultAxes.get(ResultAxis.COLUMNS); + ResultAxis columnsAxis = resultAxes.get(Axis.COLUMNS.ordinal()); for (ResultPosition position : columnsAxis.getPositions()) { Member measure = position.getMembers().get(0); System.out.print(measure.getName()); } // Print rows. - ResultAxis rowsAxis = resultAxes.get(ResultAxis.ROWS); - for (ResultPosition position : rowsAxis.getPositions()) { + ResultAxis rowsAxis = resultAxes.get(Axis.ROWS.axisOrdinal()); + int cellOrdinal = 0; + for (ResultPosition rowPosition : rowsAxis.getPositions()) { boolean first = true; - for (Member member : position.getMembers()) { + for (Member member : rowPosition.getMembers()) { if (first) { first = false; } else { @@ -84,11 +86,20 @@ void simpleStatement() throws SQLException, ClassNotFoundException { // Print the value of the cell in each column. for (ResultPosition columnPosition : columnsAxis.getPositions()) { - ResultCell cell = result.getCell( - new int[] { - columnPosition.getOrdinal(), - position.getOrdinal(), - }); + // Access the cell via its ordinal. The ordinal is kept in step + // because we increment the ordinal once for each row and + // column. + ResultCell cell = result.getCell(cellOrdinal); + + // Just for kicks, convert the ordinal to a list of coordinates. + // The list matches the row and column positions. + List coordList = + result.ordinalToCoordinates(cellOrdinal); + assert coordList.get(0) == rowPosition.getOrdinal(); + assert coordList.get(1) == columnPosition.getOrdinal(); + + ++cellOrdinal; + System.out.print('\t'); System.out.print(cell.getFormattedValue()); } @@ -173,32 +184,35 @@ private void printResult(OlapResultSet result) { // Print headings. System.out.print("\t"); - ResultAxis columnsAxis = resultAxes.get(ResultAxis.COLUMNS); + ResultAxis columnsAxis = resultAxes.get(Axis.COLUMNS.axisOrdinal()); for (ResultPosition position : columnsAxis.getPositions()) { Member measure = position.getMembers().get(0); System.out.print(measure.getName()); } // Print rows. - ResultAxis rowsAxis = resultAxes.get(ResultAxis.ROWS); - for (ResultPosition position : rowsAxis.getPositions()) { - boolean first = true; - for (Member member : position.getMembers()) { - if (first) { - first = false; - } else { + ResultAxis rowsAxis = resultAxes.get(Axis.ROWS.axisOrdinal()); + List coordList = new ArrayList(2); + int row = 0; + for (ResultPosition rowPosition : rowsAxis.getPositions()) { + assert rowPosition.getOrdinal() == row; + coordList.set(0, row++); + + // Print the row label. + int memberOrdinal = 0; + for (Member member : rowPosition.getMembers()) { + if (memberOrdinal++ > 0) { System.out.print('\t'); } System.out.print(member.getName()); } // Print the value of the cell in each column. + int column = 0; for (ResultPosition columnPosition : columnsAxis.getPositions()) { - ResultCell cell = result.getCell( - new int[] { - columnPosition.getOrdinal(), - position.getOrdinal(), - }); + assert columnPosition.getOrdinal() == column; + coordList.set(1, column++); + ResultCell cell = result.getCell(coordList); System.out.print('\t'); System.out.print(cell.getFormattedValue()); }